一、什么是朴素贝叶斯
朴素贝叶斯:它是一系列以假设特征特征之间强独立下运用的贝叶斯定理为基础的简单概率分类器,它的核心思想就是,假设有一篇文章,它属于A类文章的概率为P(A)属于B类文章的概率为P(B),如果P(A)>P(B),则这篇文章属于A类,否则这篇文章属于B类。
优点:在数据较少的情况下仍然有效,可以处理多分类问题
缺点:对于输入数据的准备方式较为敏感
二、程序实现流程图
运行环境要求:jieba(安装方法:pip install jieba)+numpy
三、具体实现代码如下
#encoding:utf8
import jieba,numpy
import jieba.analyse
import math
import os
'''
使用jieba分词,采用TF-IDF算法来提取文档中的前10个关键词
'''
def extractWordsTop30(file_path):
#读取文档中的所有内容
contents = open(file_path,"rb").read()
#对文档进行分词,获取文档的前10个关键词
#wordsTop30 = jieba.analyse.extract_tags(contents,topK=30) TF-IDF算法提取关键词 allowPOS=('ns', 'n', 'vn', 'v')
wordsTop30 = jieba.analyse.textrank(contents, topK=30, withWeight=False, allowPOS=('ns', 'n')) #textrank算法提取关键词
return wordsTop30
'''
将所有文档的关键词,进行合并,去掉重复的关键词
'''
def mergeKeyWords(listKeyWords):
allWords = set([])
for words in listKeyWords:
allWords = allWords | set(words)
return list(allWords)
'''
将输入的关键词,转换为与所有词对应的一个词向量
'''
def setOfWords2Vec(allWords,inputWords):
resultWords = [0] * len(allWords)
for word in inputWords:
if word in allWords:
resultWords[allWords.index(word)] = 1
return resultWords
'''
将输入的关键词,转换与所有词相对应的一个词袋
词袋模型与词向量模型的区别在于,词袋模型中的每个词可以出现多次
词向量模型中的词只能出现一次
'''
def bagOfwords2Vec(allWords,inputWords):
resultWords = [0] * len(allWords)
for word in inputWords:
if word in allWords:
resultWords[allWords.index(word)] += 1
return resultWords
'''
朴素贝叶斯的训练函数
'''
def trainNB(trainMatrix,trainCategory):
#计算出训练文档的个数
numTrainDocs = len(trainMatrix)
#计算总共词的个数
numWords = len(trainMatrix[0])
#计算属于1类的概率
pCorrect = sum(trainCategory)/numTrainDocs
print("sum(trainCategory):",sum(trainCategory))
print("numTrainDocs:",numTrainDocs)
p0Num = numpy.ones(numWords)
p1Num = numpy.ones(numWords)
p0Denom = 2.0
p1Denom = 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 = p1Num / p1Denom
p0Vect = p0Num / p0Denom
return p0Vect,p1Vect,pCorrect
'''
分类器
vec2Classify:输入向量
'''
def ClassifyNB(vec2Classify,p0Vec,p1Vec,pClass1):
p1 = sum(vec2Classify * p1Vec) + math.log(pClass1)
p0 = sum(vec2Classify * p0Vec) + math.log(1-pClass1)
if p1 > p0:
return 1
else:
return 0
def test():
docList = []
classList = []
cars = os.listdir("../C000007/")
for file in cars:
docList.append(extractWordsTop30("../C000007/"+file))
classList.append(0)
docList.append(extractWordsTop30("../C000008/" + file))
classList.append(1)
allWords = mergeKeyWords(docList)
trainingSet = [x for x in range(598)]
testSet = []
import random
for i in range(198):
randIndex = int(random.uniform(0,len(trainingSet)))
testSet.append(trainingSet[randIndex])
del trainingSet[randIndex]
trainMat = []
trainClasses = []
for docIndex in trainingSet:
trainMat.append(setOfWords2Vec(allWords,docList[docIndex]))
trainClasses.append(classList[docIndex])
p0V,p1V,p = trainNB(trainMat,trainClasses)
print("p:",p)
errorCount = 0
for docIndex in testSet:
wordVector = setOfWords2Vec(allWords,docList[docIndex])
if ClassifyNB(wordVector,p0V,p1V,p) != classList[docIndex]:
errorCount += 1
print("errorCount:",errorCount)
print("len(testSet):",len(testSet))
print("错误率:",errorCount/len(testSet))
if __name__=="__main__":
test()
四、总结在运行的时候会发现每次的运行结果的错误率不一样,原因在每一次的训练数据和测试数据都是从数据集中随机抽取的,所以每一次的运行结果会不一致,观察结果可以发现分类的效果并不是很理想,最好的错误率在10%左右,大的可能到50%。而且,在利用朴素贝叶斯进行分类文本的时候可以发现,如果我需要的分类文本既不属于1类也不属于0类的时候,分类器还是会把它分为属于1类或者是0类,这样显然是不合理的,为了避免这种情况的发生,我们可以多设置一种类别,但是对于这种类别的文档我们应该如何选择,这也是一个问题。整个项目我已经上传到了CSDN,下载地址 http://download.csdn.net/download/sinat_29957455/9956328,数据集采用的是搜狗的新闻词库,其中的C000007文件夹中的类别属于汽车,C000008属于财经。在使用TF-IDF算法和textrank算法分类的时候,对比结果发现textrank算法的准确率要高于TF-IDF算法。