引文:前面提到的K最近邻算法和决策树算法,数据实例最终被明确的划分到某个分类中,下面介绍一种不能完全确定数据实例应该划分到哪个类别,或者说只能给数据实例属于给定分类的概率。
基于贝叶斯决策理论的分类方法之朴素贝叶斯
优点:在数据较少的情况下仍然有效,可以处理多类别问题
缺点:对于输入数据的准备方式较为敏感
适用数据类型:标称型数据。
朴素贝叶斯的一般过程
收集数据:可以使用任何方式
准备数据:需要数据型或是布尔型数据
分类数据:有大量特征时,绘制特征作用不大,此时使用直方图效果更好
训练算法:计算不同的独立特征的条件概率
测试算法:计算错误率
使用算法:文档分类
原理
主要是运用贝叶斯定理
代码:
# _*_ coding:utf-8 _*_
import numpy as np
def loadDataSet():
"""
导入数据, 1代表脏话
@ return postingList: 数据集
@ return classVec: 分类向量
"""
postingList = [['my', 'dog', 'has', 'flea', 'problems', 'help', 'please'],
['maybe', 'not', 'take', 'him', 'to', 'dog', 'park', 'stupid'],
['my', 'dalmation', 'is', 'so', 'cute', 'I', 'love', 'him'],
['stop', 'posting', 'stupid', 'worthless', 'garbage'],
['mr', 'licks', 'ate', 'my', 'steak', 'how', 'to', 'stop', 'him'],
['quit', 'buying', 'worthless', 'dog', 'food', 'stupid']]
classVec = [0, 1, 0, 1, 0, 1]
return postingList, classVec
def createVocabList(dataSet):
"""
创建词库
@ param dataSet: 数据集
@ return vocabSet: 词库
"""
vocabSet = set([])
for document in dataSet:
# 求并集
vocabSet = vocabSet | set(document)
return list(vocabSet)
def setOfWords2Vec(vocabList, inputSet):
"""
文本词向量.词库中每个词当作一个特征,文本中就该词,该词特征就是1,没有就是0
@ param vocabList: 词表
@ param inputSet: 输入的数据集
@ return returnVec: 返回的向量
"""
returnVec = [0] * len(vocabList)
for word in inputSet:
if word in vocabList:
returnVec[vocabList.index(word)] = 1
else:
print("单词: %s 不在词库中!" % word)
return returnVec
def trainNB0(trainMatrix, trainCategory):
"""
训练
@ param trainMatrix: 训练集
@ param trainCategory: 分类
"""
numTrainDocs = len(trainMatrix)
numWords = len(trainMatrix[0])
pAbusive = sum(trainCategory) / float(numTrainDocs) # “滥用”概率
#防止某个类别计算出的概率为0,导致最后相乘都为0,所以初始词都赋值1,分母赋值为2.
p0Num = np.ones(numWords)
p1Num = np.ones(numWords)
p0Denom = 2
p1Denom = 2
for i in range(numTrainDocs):
if trainCategory[i] == 1:
p1Num += trainMatrix[i]
p1Denom += sum(trainMatrix[i]) # 记录一共出现多少个单词
else:
p0Num += trainMatrix[i]
p0Denom += sum(trainMatrix[i])
# 这里使用log函数,方便计算,因为最后是比较大小,所有对结果没有影响。
p1Vect = np.log(p1Num / p1Denom) #计算类标签为1时的其它属性发生的条件概率
p0Vect = np.log(p0Num / p0Denom) #计算标签为0时的其它属性发生的条件概率
return p0Vect, p1Vect, pAbusive #返回条件概率和类标签为1的概率
def classifyNB(vec2Classify,p0Vec,p1Vec,pClass1):
"""
判断大小
"""
p1 = sum(vec2Classify*p1Vec)+np.log(pClass1) # logp1 + logp3 + logp7 = log(p1*p3*p7) 等同于 p1*p3*p7
p0 = sum(vec2Classify*p0Vec)+np.log(1-pClass1)
if p1>p0:
return 1
else:
return 0
def testingNB():
listOPosts,listClasses = loadDataSet()
myVocabList = createVocabList(listOPosts)
trainMat=[]
for postinDoc in listOPosts:
trainMat.append(setOfWords2Vec(myVocabList, postinDoc))
p0V,p1V,pAb = trainNB0(np.array(trainMat),np.array(listClasses))
testEntry = ['love', 'my', 'dalmation']
thisDoc = np.array(setOfWords2Vec(myVocabList, testEntry))
print(testEntry,'classified as: ',classifyNB(thisDoc,p0V,p1V,pAb))
testEntry = ['stupid', 'garbage', 'bob']
thisDoc = np.array(setOfWords2Vec(myVocabList, testEntry))
print(testEntry,'classified as: ',classifyNB(thisDoc,p0V,p1V,pAb))
if __name__=='__main__':
testingNB()
运行结果:
注:
贝叶斯公式:
P(y|x) = ( P(x|y) * P(y) ) / P(x)
这里:
P(y|x) 是后验概率,一般是我们求解的目标。
P(x|y) 是条件概率,又叫似然概率,一般是通过历史数据统计得到。一般不把它叫做先验概率,但从定义上也符合先验定义。
P(y) 是先验概率,一般都是人主观给出的。贝叶斯中的先验概率一般特指它。
P(x) 其实也是先验概率,只是在贝叶斯的很多应用中不重要(因为只要最大后验不求绝对值),需要时往往用全概率公式计算得到。
- 朴素贝叶斯其实只是算了一下样本属于每一类的后验概率,然后去最大后验概率作为预测结果
- 后验概率根据先验概率和条件概率求得
- 贝叶斯算法将[‘love’, ‘my’, ‘dalmation’]分为“无侮辱”一类,
- 贝叶斯算法将[‘stupid’, ‘garbage’]分为“侮辱”性质的一类。
- ‘Bob’一词则不在词库中
参考资料:
https://blog.csdn.net/Dream_angel_Z/article/details/46120867
https://blog.csdn.net/yangang908/article/details/62215209
《Machine Learning in Action 》机器学习实战