理论
1、算法优缺点:
(1)优点:在数据较少的情况下,依然有效,可以处理多分类问题;
(2)缺点:对输入数据的准备方式较为敏感。
(3)适用于标称型数据
2、条件假设:
(1)假设变量间相互独立,即
p(x|ci)=p(x1|ci)∗p(x2|ci)∗···∗p(xn|ci)
; (
xi
可以看做特征)
(2)假设所有变量同等重要。
3、基本原理:
贝叶斯准则:
根据变量相互独立性,对于给定数据
x
,求结果为
为了防止下溢,方便计算等原因,对上诉式子取对数
得
对分类来说
p(x)
是相同的,所以上式可以简化成
取最大的 logp(ci|x) 对应的分类 ci 作为新样本的分类。
实现
按照《机器学习实战》中给出的示例:对社区中对狗狗评论判断是否属于侮辱性评论。
上诉公式可改成
1)、首先我们样本中将每篇评论文章切割单词形成向量,并标注每条评论是否属于侮辱性词汇,假设共m篇文章(样本)
from numpy import *
def loadDataSet():
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] #1 is abusive, 0 not
return postingList,classVec
2)、然后获取样本中包含的单词库(对所有评论单词去重后的列表),假设单词库长包含n个单词
def createVocabList(dataSet):
vocabSet = set([]) #create empty set
for document in dataSet:
vocabSet = vocabSet | set(document) #union of the two sets
return list(vocabSet)
3) 每句维护一个2)中获取的单词库长度的列表,初始值为0,根据单词库,判断每篇文章中的单词是否出现在列表中,出现将将对应的位置值改成1,函数返回m*n的向量
def setOfWords2Vec(vocabList, inputSet):
returnVec = [0]*len(vocabList)
for word in inputSet:
if word in vocabList:
returnVec[vocabList.index(word)] = 1
else: print "the word: %s is not in my Vocabulary!" % word
return returnVec
4)计算
p(ci|W)
、
p(ci)
这里为二分类(多分类另外处理),根据公式,为了求
p(c=0|W)
和
p(c=1|W)
,需要求
p(c=0)
、
p(W|c=0)
和
p(c=1)
、
p(W|c=1)
p(c=1)
计算方式:所有标签为1的样本数/样本总数
p(wi|c=0)
表示该单词
wi
在
c=0
条件下出现的概率,计算方式:所有类别为
c=0
的文章中,该单词出现的次数/这类文章所有的单词数
以下几点需要单独说明:
1、将所有单词出现的次数初始化为1,将分母初始化为2,防止出现
p(wi|c)=0
的情况
2、使用
log
替代连乘,防止数据太小连乘导致下溢情况
3、这里每个单词出现就标记其值为1 returnVec[vocabList.index(word)] = 1
,如果需要统计,为适应词袋模型,通常记录单词出现的总次数returnVec[vocabList.index(word)] += 1
4、这里使用numpy实现,返回的p0Vect和p1Vect都是矩阵类型
def trainNB0(trainMatrix,trainCategory):
numTrainDocs = len(trainMatrix)
numWords = len(trainMatrix[0])
pAbusive = sum(trainCategory)/float(numTrainDocs)
p0Num = ones(numWords); p1Num = ones(numWords) #change to ones()
p0Denom = 2.0; p1Denom = 2.0 #change to 2.0
for i in range(numTrainDocs):
if trainCategory[i] == 1:
p1Num += trainMatrix[i]
p1Denom += sum(trainMatrix[i])
else:
p0Num += trainMatrix[i]
p0Denom += sum(trainMatrix[i])
p1Vect = log(p1Num/p1Denom) #change to log()
p0Vect = log(p0Num/p0Denom) #change to log()
return p0Vect,p1Vect,pAbusive
为新的数据vec2Classify(通过方法setOfWords2Vec)处理后的数据分类
def classifyNB(vec2Classify, p0Vec, p1Vec, pClass1):
p1 = sum(vec2Classify * p1Vec) + log(pClass1) #element-wise mult
p0 = sum(vec2Classify * p0Vec) + log(1.0 - pClass1)
if p1 > p0:
return 1
else:
return 0