统计学习方法第四章朴素贝叶斯的贝叶斯估计,例题4.2代码实践(如需要查看极大似然估计的算法请看我的另一篇文章http://blog.csdn.net/grinandbearit/article/details/79044065),贝叶斯算法略微复杂了点对分子分母做了矫正防止出现乘0现象
#-*- coding:utf-8 -*-
from numpy import *
#将书上的数据输入,这里懒得输入那么多个列表就用下array的转置方法吧!就用这个方法吧0.0
def loadDataSet():
dataSet=[[1,1,1,1,1,2,2,2,2,2,3,3,3,3,3],['S','M','M','S','S','S','M','M','L','L','L','M','M','L','L']]
labels=[-1,-1,1,1,-1,-1,-1,1,1,1,1,1,1,1,-1]
return array(dataSet).transpose().tolist(),labels
'''
这里将labels中所有不同的类别及其类别的概率存储在一个字典中方便调用,这个可扩展性也比较强,支持n分类(不局限于书上的二分类),
alpha对应于拉普拉斯平滑的一个参数
'''
def calc_label(labels,alpha):
m=len(labels)
uniqueLabel=set(labels) #所有不重复的类别
diffLabelNum=len(uniqueLabel)
labelRate={}
for label in uniqueLabel:
labelRate[label]=(labels.count(label)+alpha)/float(m+diffLabelNum*alpha) #分子分母对应于极大似然估计做了改变
return labelRate,list(uniqueLabel) #刚开始的uniqueLabel是set属性不方便计算,这里转换成list
#计算词汇表,即所有的不重复的属性值融合到一个列表中
def calcVocaulary(dataset):
voca=set()
for content in dataset:
voca = voca | set(content)
return list(voca)
#计算词向量,在词汇表中出现则在对应位置加1
def calcVector(voca,vector):
n=len(voca)
originVector=zeros(n)
for word in vector:
if word in voca:
originVector[voca.index(word)] += 1
return array(originVector) #为方便后面向量相加计算这里转换成array属性
#这个函数用于计算每个属性值的后验概率的分母
def calcUniqueValueNum(dataset,labels,label,voca):
labelDataSet=[]
for i in range(len(labels)):
if labels[i]==label:
labelDataSet.append(dataset[i])
m,n=shape(labelDataSet)
uniqueValueDict={}
for i in range(n):
uniqueValue=set()
[uniqueValue.add(content[i]) for content in labelDataSet]
for value in uniqueValue:
uniqueValueDict[value] = len(uniqueValue)
a=len(voca)
returnArray=zeros(a)
for key in uniqueValueDict:
returnArray[voca.index(key)] = float(uniqueValueDict[key])
return returnArray
#开始训练这里将不同类别及其类别对应的训练好的极大似然估计向量存储到字典中,同样字典的key长度对应于所有不重复的标记,可支持n类标记
def Bayes(dataset,labels,uniqueLabel,voca,alpha):
n=len(uniqueLabel);m=len(dataset)
trainVecDict={}
for i in range(n):
labelVector=array(ones(len(voca)))*alpha
for j in range(m):
if labels[j]== uniqueLabel[i]:
labelVector += calcVector(voca,dataset[j]) #将相同类别的词向量相加
labelVector /= (labels.count(uniqueLabel[i])+calcUniqueValueNum(dataset,labels,uniqueLabel[i],voca)*alpha) #词向量的和除对应该类别出现的频率
trainVecDict[uniqueLabel[i]]=labelVector #将该类别及其训练好的极大似然估计向量存储到字典中
return trainVecDict
#开始分类,结果即为类别概率最大的那个类别
def testFunction(testArray,voca,trainVecDict,labelRate):
result = -1;maxRate = -inf
for key in trainVecDict:
singleLabelRate=1.0
for word in testArray:
singleLabelRate *= trainVecDict[key][voca.index(word)] #这里把测试集中出现的属性到每个分类对应的向量中取出其概率相乘
if singleLabelRate*labelRate[key] > maxRate:
result = key;maxRate =singleLabelRate*labelRate[key]
return result
dataSet,labels=loadDataSet()
labelRate,uniqueLabel=calc_label(labels,1)
voca=calcVocaulary(dataSet)
trainVecDict=Bayes(dataSet,labels,uniqueLabel,voca,1)
testArray=array([2,'S'])
print testFunction(testArray,voca,trainVecDict,labelRate)
print labelRate
print trainVecDict
结果如下:
['1', 'S', '2', 'M', '3', 'L']
-1
{1: 0.5882352941176471, -1: 0.4117647058823529}
{1: array([ 0.25 , 0.16666667, 0.33333333, 0.41666667, 0.41666667,
0.41666667]), -1: array([ 0.44444444, 0.44444444, 0.33333333, 0.33333333, 0.22222222,
0.22222222])}
made by zcl at CUMT
I know I can because I have a heart that beats