目录
1.朴素贝叶斯算法介绍
1.朴素贝叶斯介绍
朴素贝叶斯法(Naive Bayes model)是基于贝叶斯定理与特征条件独立假设的分类方法 。朴素贝叶斯算法(Naive Bayesian algorithm) 是应用最为广泛的分类算法之一。
最为广泛的两种分类模型是决策树模型(Decision Tree Model)和朴素贝叶斯模型(Naive Bayesian Model,NBM)。和决策树模型相比,朴素贝叶斯分类器(Naive Bayes Classifier 或 NBC)发源于古典数学理论,有着坚实的数学基础,以及稳定的分类效率。同时,NBC模型所需估计的参数很少,对缺失数据不太敏感,算法也比较简单。理论上,NBC模型与其他分类方法相比具有最小的误差率。但是实际上并非总是如此,这是因为NBC模型假设属性之间相互独立,这个假设在实际应用中往往是不成立的,这给NBC模型的正确分类带来了一定影响。朴素贝叶斯方法是在贝叶斯算法的基础上进行了相应的简化,即假定给定目标值时属性之间相互条件独立。也就是说没有哪个属性变量对于决策结果来说占有着较大的比重,也没有哪个属性变量对于决策结果占有着较小的比重。虽然这个简化方式在一定程度上降低了贝叶斯分类算法的分类效果,但是在实际的应用场景中,极大地简化了贝叶斯方法的复杂性。
2.朴素贝叶斯公式的理解
朴素贝叶斯公式
设有样本数据集D{d1,d2,d3,..,dn},对应样本数据的特征属性集X={x1,x2,x3,...,xn},类变量为Y={y1,y2,y3,...,yn},即D可以分为yn个类别。其中x1,x2,x3,...,xn相互独立且随机,则Y的先验概率P1=P(Y),Y的后验概率P2=P(Y|X),由朴素贝叶斯算法可得,后验概率可以由先验概率P1=P(Y)、证据P(X)、类条件概率P(X|Y)计算出:
概率基础复习
- 联合概率:包含多个条件,且所有条件同时成立的概率
- 记作:
P(A,B)
- 记作:
- 条件概率:就是事件A在另外一个事件B已经发生条件下的发生概率
- 记作:
P(A|B)
- 记作:
- 相互独立:如果
P(A, B) = P(A)P(B)
,则称事件A与事件B相互独立
3.朴素贝叶斯算法优总结
(1)优点
朴素贝叶斯模型发源于古典数学理论,有稳定的分类效率
对缺失数据不太敏感,算法也比较简单,常用于文本分类
分类准确度高,速度快
(2)缺点
由于使用了样本属性独立性的假设,所以如果特征属性有关联时其效果不好
需要计算先验概率,而先验概率很多时候取决于假设,假设的模型可以有很多种,因此在某些时候会由于假设的先验模型的原因导致预测效果不佳;
4.朴素贝叶斯实现垃圾邮件分类
4.1垃圾邮件分类问题背景
垃圾邮件曾经是一个令广大网友非常头痛的问题,长期困扰着邮件运营商和用户。据官方统计,用户收到的电子邮件中80%以上是垃圾邮件。影响我们的正常网络生活而且还占取有限的可用资源;占用大量网络带宽,浪费存储空间,影响网络传输和运算速度;妖言惑众,骗人钱财,传播色情、反动等内容的垃圾邮件,已对现实社会造成严重危害。
传统的垃圾邮件过滤方法,主要有"关键词法"和"校验码法"等。关键词法的过滤依据是特定的词语,(如垃圾邮件的关键词:“发票”,“贷款”,“利率”,“中奖”,“办证”,“抽奖”,“号码”,“钱”,“款”,“幸运”……等等。)但这种方法效果很不理想,而且容易规避。一是正常邮件中也可能有这些关键词,非常容易误判。二是将关键词进行变形,如“代!开-发/票”,“中奖”如果被拆成“中 ~~~ 奖”可能会识别不了。后来,直到提出了使用“贝叶斯”的方法才使得垃圾邮件的分类达到一个较好的效果,而且随着邮件数目越来越多,贝叶斯分类的效果会更加好。如果将关键词的各种变形都找出来过滤,那是无穷无尽的,而且更容易误判正常邮件。
校验码法则是计算邮件文本的校验码,再与已知的垃圾邮件进行对比。它们的识别效果都不理想,而且很容易规避。直到2002年,Paul Graham提出使用“贝叶斯方法”过滤垃圾邮件,经过几年的工程化应用,才算解决了这个问题。而这种方法的效果,好的不可思议。此外,这种过滤方法还具有自我学习能力,会根据新收到的邮件,不断调整。收到的垃圾邮件越多,它的准确率就越高。采用的分类方法是通过多个词来判断是否为垃圾邮件,但这个概率难以估计,通过贝叶斯公式,可以转化为求垃圾邮件中这些词出现的概率。
4.2朴素贝叶斯算法实现垃圾邮件分类的步骤
(1)提供样本数据(邮件样本):收集相关文本文件,在此我在网上搜集了一些 Enron Email Dataset 数据集
(2)数据读入:第一步将准备的数据文件读入
(3)准备数据(预处理):清除标点符符号、将字符串标记为单词、计算某个单词出现的次数等
(4)数据处理:建立一个集合存储所有出现的单词、统计spam和ham邮件的个数、计算先验概率(即在所有的样本邮件中垃圾邮件和正常邮件的占比)、构建一个字典存储单封邮件中的单词以及其个数
(5)测试:遍历所有的测试集、计算P(内容|垃圾邮件)和P(内容|正常邮件),所有的单词都要进行拉普拉斯平滑、把计算到的P(内容|垃圾邮件)和P(内容|正常邮件)加起来、把先验加上去(P(垃圾邮件)和P(正常邮件))、最后进行预测,如果spam_score > ham_score则标志为1,即垃圾邮件
4.3具体实现
1.数据集准备
2.将词表转换成向量
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
# 创建词汇表
def createVocabList(dataSet):
vocabSet = set([]) # 创建一个空集
for document in dataSet:
vocabSet = vocabSet | set(document) # |表示求并操作
return list(vocabSet) # 返回一个不重复的列表
# 输出文档向量
def setOfwords2Vec(vocabList, inputSet):
returnVec = [0] * len(vocabList) # 创建一个等长向量并设置为0
for word in inputSet:
if word in vocabList:
returnVec[vocabList.index(word)] = 1 # 若出现了单词表中的单词,则将对应值设置为1
else:
print("单词:%s 不存在!" % word)
return returnVec
# 测试函数效果
# 创建实验样本
listPosts, listClasses = loadDataSet()
print('数据集\n', listPosts)
# 创建词汇表
myVocabList = createVocabList(listPosts)
print('词汇表:\n', myVocabList)
# 输出文档向量
print(setOfwords2Vec(myVocabList, listPosts[5]))
3.词集模型
为输入的邮件构造单词集合
#词集模型
def setOfWord2Vec(vocabList,inputSet):
returnVec=zeros(len(vocabList))
for word in inputSet:
if word in vocabList:
returnVec[vocabList.index(word)]=1
else:
print("这个单词不在所有的单词向量里面")
return returnVec
4.词袋模型
#词袋模型
def bagOfword2VecMN(vocabList,inputSet):
returnVec=[0]*len(vocabList)
for word in inputSet:
if word in vocabList:
returnVec[vocabList.index(word)]+=1
return returnVec
5.朴素贝叶斯函数
#朴素贝叶斯训练函数
def trainB0(trainMatrix,trainCategory):
numTrainDocs=len(trainMatrix)
numwords=len(trainMatrix[0])
#对于category为0,1 才可以使用sum
pAbusive=sum(trainCategory)/float(numTrainDocs)
p0Num=ones(numwords)
p1Num=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=log(p1Num/p1Denom)
p0Vect=log(p0Num/p0Denom)
return p0Vect,p1Vect,pAbusive
6.朴素贝叶斯分类函数
#朴素贝叶斯分类函数
def classifyNB(vec2Classify,p0Vec,p1Vec,pClass1):
p1=sum(vec2Classify*p1Vec)+log(pClass1)
p0=sum(vec2Classify*p0Vec)+log(1-pClass1)
if p1>p0:
return 1
else:
return 0
7.提取单词
#将输入的文本字符串分割成单词list
def textParse(bigString):
listOfTokens=re.split(r'\W*',bigString)
return [tok.lower() for tok in listOfTokens if len(tok)>2]
8.垃圾邮件测试函数
def spamTest():
docList=[]
classList=[]
fullText=[]
filenameList1=listdir("email/train")
for name in filenameList1:
wordList=textParse(open("email/train/"+name).read())
docList.append(wordList)
fullText.extend(wordList)
classList.append(1)
filenameList2=listdir("email/test")
for name in filenameList2:
wordList = textParse(open("email/test/"+name).read())
docList.append(wordList)
fullText.extend(wordList)
classList.append(0)
vocabList=createVocabList(docList)
trainingSet=list(range(len(docList)))
testSet=[]
for i in range(int(0.2*len(docList))):
randIndex=int(random.uniform(0,len(trainingSet)))
testSet.append(trainingSet[randIndex])
del(trainingSet[randIndex])
trainMat=[]
trainClasses=[]
for docIndex in trainingSet:
trainMat.append(setOfWord2Vec(vocabList,docList[docIndex]))
trainClasses.append(classList[docIndex])
p0V,p1V,pSpam=trainB0(array(trainMat),array(trainClasses))
errorCount=0
for docIndex in testSet:
wordVector=setOfWord2Vec(vocabList,docList[docIndex])
if classifyNB(array(wordVector),p0V,p1V,pSpam)!=classList[docIndex]:
errorCount+=1
print (r"垃圾邮件准确率:",float(errorCount/float(len(testSet))))
运行结果
5.总结
对于该模型来说想要提高准确率,下次使用的应该是具有独立性比较高的数据集,只有在完全独立的时候才能满足公式算出来的概率。