贝叶斯公式:
什么是朴素贝叶斯方法?思想和原理?
判断依据:如果,那么属于c1类。如果,那么属于c2类。
朴素贝叶斯优点:在数据较少的情况下仍然有效,可以处理多类别问题
缺点:对于输入数据的准备方式较为敏感
适用数据类型:标称型数据
应用:使用朴素贝叶斯法来文档分类
# encoding: utf-8
import numpy as np
from numpy import *
#4-1词表到向量的转换函数
#loadDataSet()创建了一个实验样本,第一个变量是进行词条切分后的文档集合,第二个变量是一个类别标签的集合
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代表侮辱性文字,0代表正常言论
return postingList,classVec
#createVocabList()创建一个包含在所有文档中出现的不重复词的列表
def createVocabList(dataSet):
vocabSet = set([]) #set()函数就是返回一个不包含重复元素的列表
for document in dataSet:
vocabSet = vocabSet | set(document)#操作符|相当于两个集合的并集
return list(vocabSet)
#这个函数第一个输入参数是总样本(字母表),第二个参数是子样本
#该函数的作用是将子样本出现的单词一一在总样本中寻找,若总样本中有,就将此位置的值设为1
#此过程是在一个新的列表中进行的
def setOfWords2Vec(vocabList,inputSet):
returnVec = [0]*len(vocabList)#创建一个和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
通过类别i(侮辱性留言或非侮辱性留言)中文档数除以总的文档数来计算概率p(ci)。接下来就是计算p(w|ci),这就需要用到朴素贝叶斯假设。如果将w展开为一个个独立特征,那么就可以将上述概率写作p(w0,w1,w2,w3...wN|ci)。这里我们再假设其条件独立性,将其写成p(w0|ci)p(w1|ci)p(w2|ci)p(w3|ci)p(w4|ci)来计算上述概率。
实现的伪代码:
计算每个类别中的文档数目
对每篇训练文档:
对每个类别:
如果词条出现在文档中 增加该词条的计数值
增加所有词条的计数值
对每个类别:
对每个词条:
将该词条的数目除以总词条数目得到条件概率
返回每个类别的条件概率
#4-2朴素贝叶斯分类器训练函数
def trainNB0(trainMatrix,trainCategory):#第一个参数为文档矩阵,第二个参数为类别标签
numTrainDocs = len(trainMatrix)#读取文档的个数,这是一个文档矩阵的长度
numWords = len(trainMatrix[0])#该文档第一个单词长度
pAbusive = sum(trainCategory)/float(numTrainDocs)#sum(trainCategory)代表的是所有分类的和
#p0Num = zeros(numWords);p1Num = zeros(numWords)
#p0Denom = 0.0; p1Denom = 0.0
p0Num = ones(numWords);p1Num = ones(numWords)#为什么把注释改成这样?《机器学习实战》P62
p0Denom = 2.0;p1Denom = 2.0
for i in range(numTrainDocs):
if trainCategory[i] == 1:#遍历每一个词,若属于侮辱性文档
p1Num += trainMatrix[i]#将它加入到p1Nm矩阵中
p1Denom += sum(trainMatrix[i])#该文档的总词数也加1
else:
p0Num += trainMatrix[i]
p0Denom += sum(trainMatrix[i])
#p1Vect = p1Num/p1Denom#每个元素除以该类别中总词数
#p0Vect = p0Num/p0Denom
p1Vect = log(p1Num / p1Denom)#为什么这么改,取对数,防止下溢出
p0Vect = log(p0Num / p0Denom)
return p0Vect,p1Vect,pAbusive#p1Vect中每个元素对应的条件概率,pAbusive就是p(ci)先验概率
#4-3朴素贝叶斯分类函数
def classifyNB(vec2Classify, p0Vec,p1Vec,pClass1):#第一个为要分类的向量以及trainNB0计算出的三个概率
p1 = sum(vec2Classify*p1Vec) + log(pClass1)
p0 = sum(vec2Classify*p0Vec) + log(1.0 - 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(array(trainMat),array(listClasses))
testEntry = ['love','my','dalmation']
thisDoc = array(setOfWords2Vec(myVocabList,testEntry))
print testEntry,'classified as:',classifyNB(thisDoc,p0V,p1V,pAb)
testEntry = ['stupid','garbage']
thisDoc = array(setOfWords2Vec(myVocabList,testEntry))
print testEntry,'classified as: ',classifyNB(thisDoc,p0V,p1V,pAb)
#4-4朴素贝叶斯词袋模型,与setOfWords2Vec(词集模型)几乎一样,只不过改成累计数,而不是标1
def bagOfWords2VecMN(vocabList,inpuSet):
returnVec = [0]*len(vocabList)
for word in inpuSet:
if word in vocabList:
returnVec[vocabList.index(word)] += 1
return returnVec
应用:使用朴素贝叶斯法来过滤垃圾邮件
#4-5文件解析及完整的垃圾邮件测试函数
def textParse(bigString):
listOfTokens = re.split(r'\w*',bigString)
return [tok.lower() for tok in listOfTokens if len(tok) > 2]#将大写改为小写,返回单词长度大于2的单词
#这个函数首先读取样本,再把样本分别训练样本和测试样本,通过之前写的一系列的函数,朴素贝叶斯方法求出训练样本
#三个概率,然后再一一和测试样本进行比对,进而求出错误率。
def spamTest():
docList = [];classList = [];fullTest = []
for i in range(1,26):
wordList = textParse(open('email/spam/%d.txt' %i).read())
docList.append(wordList)
fullTest.extend(wordList)
classList.append(1)
#正例
wordList = textParse(open('email/ham/%d.txt' %i).read())
docList.append(wordList)
fullTest.extend(wordList)
classList.append(0)
#反例
vocabList = createVocabList(docList)
trainingSet = range(50)
testSet = []
#第一个for循环,随机选取十个索引,这十个数就是我们随机选取的十个测试样本。
#所以训练样本要删除这十个数
for i in range(10):
#random.uniform(x, y) 方法将随机生成一个实数,它在 [x,y] 范围内。
randIndex = int(random.uniform(0,len(trainingSet)))
testSet.append(trainingSet[randIndex])
del(trainingSet[randIndex])
trainMat = [];trainClasses = []
#第二个for循环遍历所有的训练样本分别求出对应的p0V,p1V,pSpm
for docIndex in trainingSet:
trainMat.append(setOfWords2Vec(vocabList, docList[docIndex]))
trainClasses.append(classList[docIndex])
p0V,p1V,pSpm = trainNB0(array(trainMat),array(trainClasses))
errorCount = 0
#第三个for循环分别对测试样本进行比对,求出错误率
for docIndex in testSet:
wordVector = setOfWords2Vec(vocabList, docList[docIndex])
if classifyNB(array(wordVector),p0V,p1V,pSpm) != classList[docIndex]:
errorCount += 1
print 'the error rate is: ',float(errorCount)/len(testSet)
第一个函数textParse接收一个大字符串并将其解析为字符串列表。
append和extend两种列表操作函数有什么区别?