贝叶斯分类是一类分类算法的总称,这类算法均以贝叶斯定理为基础,故统称为贝叶斯分类。
我们称之为“朴素”,是因为整个形式化过程只做最原始、最简单的假设。
关于贝叶斯更多,可以参考http://www.cnblogs.com/apachecnxy/p/7471634.html
使用朴素贝叶斯过滤垃圾邮件
源码如下(bayes.py):
# coding: utf-8
"""
朴素贝叶斯-文本分类、过滤垃圾邮件
"""
import numpy as np
import re
"""
创造实验样本
"""
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正常言论
return postingList,classVec
"""
创建一个包含在所有文档中出现的不重复词的列表
"""
def createVocabList(dataSet):
vocabSet = set([]) #create empty set
for document in dataSet:
vocabSet = vocabSet | set(document) #union of the two sets
return list(vocabSet)
"""
输入: 词汇表及某个文档
输出: 文档向量,向量的每一元素为1或0,分别表示词汇表中的单词在输人文档中是否出现
"""
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
"""
朴素贝叶斯分类器训练函数
输入:trainMatrix 统计训练样本词条中单词是否在词汇表出现的文档0-1矩阵,
trainCategory 由每篇文档类别标签所构成的向量,对这些样本词条人工标注的分类矩阵
输出:pAbusive这些词条属于攻击性言论的概率
"""
def trainNB0(trainMatrix, trainCategory):
numTrainDocs = len(trainMatrix)
numWords = len(trainMatrix[0])
pAbusive = sum(trainCategory)/float(numTrainDocs)
# p0Num为正常言论词个数 p1Num侮辱性文字词个数
# np.ones生成所有值为1矩阵,例:np.ones(5)为array([ 1., 1., 1., 1., 1.])
# 初始化概率
p0Num = np.ones(numWords); p1Num = np.ones(numWords) #change to ones()
p0Denom = 2.0; p1Denom = 2.0 #change to 2.0
# 一旦某个词语 (侮辱性或正常词语)在某一文档中出现,则该词对应的个数(P1Nmn或者p0Num)就加1
# 而且在所有的文档中,该文档的总词数也相应加1
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词汇表中单词属于攻击性质的概率
# 对每个元素除以该类别中的总词数
# 想求函数的最大值时,可以使用该函数的自然对数来替换原函数进行求解
p1Vect = np.log(p1Num/p1Denom) #change to log()
p0Vect = np.log(p0Num/p0Denom) #change to log()
# pAbusive这些词条属于攻击性言论的概率
return p0Vect,p1Vect,pAbusive
"""
分类器
输入:vec2Classify 要分类的向量,
p0Vec, p1Vec, pClass1 使用函数trainNB0得到的三个概率
输出:1攻击性言论 | 0正常言论
"""
def classifyNB(vec2Classify, p0Vec, p1Vec, pClass1):
p1 = sum(vec2Classify * p1Vec) + np.log(pClass1) #element-wise mult计算向量相乘结果
# 这里的相乘是指对应元素相乘,即先将两个向量中的第1个元素相乘,然后将第2个元素相乘,以此类推。接下来将词汇表
# 所有词的对应值相加,然后将该值加到类别的对数概率上。最后,比较类别的概率返回大概率对应的类别标签。
p0 = sum(vec2Classify * p0Vec) + np.log(1.0 - pClass1)
if p1 > p0:
return 1
else:
return 0
"""
便利函数,封装所有操作,以节省输入代码的时间
"""
def testingNB():
listOPosts,listClasses = loadDataSet()
myVocabList = createVocabList(listOPosts)
#print myVocabList # 词汇表
#print listOPosts[0] # 词汇表第一组数据
#print setOfWords2Vec(myVocabList, listOPosts[0]) # 词汇表myVocabList中的单词在输人文档listOPosts[0]中是否出现
# for循环使用词向量来填充trainMat ,将文本转换为数字矩阵
trainMat=[]
for postinDoc in listOPosts:
trainMat.append(setOfWords2Vec(myVocabList, postinDoc))
# print trainMat
# 朴素贝叶斯分类器训练函数
p0V,p1V,pAb = trainNB0(np.array(trainMat),np.array(listClasses))
# print p0V
# print plV
# print pAb # 任意文档属于侮辱性文档的概率 0.5
testEntry = ['love', 'my', 'dalmation']
thisDoc = np.array(setOfWords2Vec(myVocabList, testEntry))
print testEntry,'classified as: ',classifyNB(thisDoc,p0V,p1V,pAb)
testEntry = ['stupid', 'garbage']
thisDoc = np.array(setOfWords2Vec(myVocabList, testEntry))
print testEntry,'classified as: ',classifyNB(thisDoc,p0V,p1V,pAb)
"""
朴素贝叶斯词袋模型
如果一个词在文档中出现不止一次,这可能意味着包含该词是否出现在文档中所不能表达的某种信息,这种方法被称为词袋模型
在词袋中,每个单词可以出现多次 ,而在词集中,每个词只能出现一次
"""
def bagOfWords2VecMN(vocabList, inputSet):
returnVec = [0]*len(vocabList)
for word in inputSet:
if word in vocabList:
returnVec[vocabList.index(word)] += 1
return returnVec
"""
接受一个大字符串并将其解析为字符串列表。
该函数去掉少于两个字符的字符串,并将所有字符串转换为小写。
"""
def textParse(bigString): #input is big string, #output is word list
listOfTokens = re.split(r'\W*', bigString)
return [tok.lower() for tok in listOfTokens if len(tok) > 2]
"""
对贝叶斯垃圾邮件分类器进行自动化处理
导人文件夹email/spam(垃圾邮件)与ham(正常邮件)下的文本文件
"""
def spamTest():
docList=[]; classList = []; fullText =[]
# 导入并解析文件
for i in range(1,26):
wordList = textParse(open('email/spam/%d.txt' % i).read())
docList.append(wordList)
fullText.extend(wordList)
classList.append(1)
wordList = textParse(open('email/ham/%d.txt' % i).read())
docList.append(wordList)
fullText.extend(wordList)
classList.append(0)
vocabList = createVocabList(docList)#create vocabulary
trainingSet = range(50); testSet=[] #create test set
# 随机构建训练集
for i in range(10):
randIndex = int(np.random.uniform(0,len(trainingSet)))
testSet.append(trainingSet[randIndex])
del(trainingSet[randIndex])
trainMat=[]; trainClasses = []
for docIndex in trainingSet:#train the classifier (get probs) trainNB0
trainMat.append(bagOfWords2VecMN(vocabList, docList[docIndex]))
trainClasses.append(classList[docIndex])
p0V,p1V,pSpam = trainNB0(np.array(trainMat), np.array(trainClasses))
errorCount = 0
# 对测试集分类
for docIndex in testSet: #classify the remaining items
wordVector = bagOfWords2VecMN(vocabList, docList[docIndex])
if classifyNB(np.array(wordVector),p0V,p1V,pSpam) != classList[docIndex]:
errorCount += 1
print "classification error",docList[docIndex]
print 'the error rate is: ',float(errorCount)/len(testSet)
# return vocabList,fullText
if __name__ == '__main__':
testingNB() #测试朴素贝叶斯文本分类
# 使用朴素贝叶斯过滤垃圾邮件
spamTest()