机器学习实战之朴素贝叶斯

朴素贝叶斯就是利用先验知识来解决后验概率,因为训练集中我们已经知道了每个单词在类别0和1中的概率,即p(w|c),
我们就是要利用这个知识去解决在出现这些单词的组合情况下,类别更可能是0还是1,即p(c|w)。
如果说之前的训练样本少,那么这个p(w|c)就更可能不准确,所以样本越多我们会觉得这个p(w|c)越可信。

1
2
3
4
import os
import sys
from numpy import *
sys.path.append(os.getcwd())
1
import bayes
1
2
# 返回实验样本和类别标签(侮辱类和非侮辱类)
listOPosts,listClasses=bayes.loadDataSet()
1
2
3
4
5
6
7
# 创建词汇表
# 将实验样本里面的词汇进行去重
def createVocabList(dataSet):
vocabSet=set([])
for document in dataSet:
vocabSet=vocabSet|set(document)
return list(vocabSet)
1
myVocabList=createVocabList(listOPosts)
1
2
3
4
5
6
7
8
9
10
# 将词汇转成特征向量
# 也就是将每一行样本转成特征向量
# 向量的每一元素为1或者0,分别表示词汇表中的单词在输入文档中是否出现
def setOfWordsVec(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

训练算法:从词向量计算概率

朴素贝叶斯分类器训练函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# 输入为文档矩阵以及由每篇文档类别标签所构成的向量
def trainNB0(trainMatrix,trainCategory):
# 文档总数,有几篇文档,在这里也就是有几个一维数组
numTrainDocs=len(trainMatrix)
# 每篇文档里面的单词数,也就是一维数组的长度
numWords=len(trainMatrix[0])
# 因为就只有0和1两个分类,将类别列表求和后,就是其中一个类别的个数
# 然后numTrainDocs也就是文档总数,这样相除后就是这个类别的概率了
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
1
2
# 所有文档的特征向量
trainMat=[]
1
2
3
# 将文档的每一行,转成词向量,然后追加到trainMat中
for postinDoc in listOPosts:
trainMat.append(bayes.setOfWords2Vec(myVocabList,postinDoc))
1
p0V,p1V,pAb=trainNB0(trainMat,listClasses)
1
pAb
0.5
1
p0V
array([-2.56494936, -2.56494936, -2.56494936, -3.25809654, -3.25809654,
       -2.56494936, -2.56494936, -2.56494936, -3.25809654, -2.56494936,
       -2.56494936, -2.56494936, -2.56494936, -3.25809654, -3.25809654,
       -2.15948425, -3.25809654, -3.25809654, -2.56494936, -3.25809654,
       -2.56494936, -2.56494936, -3.25809654, -2.56494936, -2.56494936,
       -2.56494936, -3.25809654, -2.56494936, -3.25809654, -2.56494936,
       -2.56494936, -1.87180218])
1
p1V
array([-3.04452244, -3.04452244, -3.04452244, -2.35137526, -2.35137526,
       -3.04452244, -3.04452244, -3.04452244, -2.35137526, -2.35137526,
       -3.04452244, -3.04452244, -3.04452244, -2.35137526, -2.35137526,
       -2.35137526, -2.35137526, -2.35137526, -3.04452244, -1.94591015,
       -3.04452244, -2.35137526, -2.35137526, -3.04452244, -1.94591015,
       -3.04452244, -1.65822808, -3.04452244, -2.35137526, -3.04452244,
       -3.04452244, -3.04452244])
1
2
3
4
5
6
7
8
9
# 朴素贝叶斯分类函数
def classifyNB(vec2classify,p0Vec,p1Vec,pClass1):
#元素相乘
p1=sum(vec2classify*p1Vec)+log(pClass1)
p0=sum(vec2classify*p0Vec)+log(pClass1)
if p1>p0:
return 1
else:
return 0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def testingNB():
listOPosts,listClasses=bayes.loadDataSet()
myVocabList=createVocabList(listOPosts)
trainMat=[]
for postinDoc in listOPosts:
trainMat.append(setOfWordsVec(myVocabList,postinDoc))
p0V,p1V,pAb=trainNB0(array(trainMat),array(listClasses))
testEntry=['love','my','dalmation']
thisDoc=array(setOfWordsVec(myVocabList,testEntry))
print testEntry,'classified as : ',classifyNB(thisDoc,p0V,p1V,pAb)
testEntry=['stupid','garbage']
thisDoc=array(setOfWordsVec(myVocabList,testEntry))
print testEntry,'classified as : ',classifyNB(thisDoc,p0V,p1V,pAb)
1
testingNB()
['love', 'my', 'dalmation'] classified as :  0
['stupid', 'garbage'] classified as :  1

使用朴素贝叶斯过滤垃圾邮件

  • 收集数据:提供文本文件
  • 准备数据:将文本文件解析成词条向量
  • 分析数据:检查词条确保解析的正确性
  • 训练算法:使用我们之前建立的trainNB0()函数
  • 测试算法:使用classifyNB()
1
mySent='This book is the best book on Python or M.L. I have ever laid eyes upon.'
1
2
3
4
5
# 文件解析及完整的垃圾邮件测试函数
def textParse(bigString):
import re
listOfTokens=re.split(r'\W*',bigString)
return [tok.lower() for tok in listOfTokens if len(tok)>2]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
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)
# 随机构建训练集、测试集
trainingSet=range(50);testSet=[]
for i in range(10):
randIndex=int(random.uniform(0,len(trainingSet)))
testSet.append(trainingSet[randIndex])
del(trainingSet[randIndex])
# 生成测试集的特征向量
trainMat=[];trainClasses=[]
for docIndex in trainingSet:
trainMat.append(setOfWordsVec(vocabList,docList[docIndex]))
trainClasses.append(classList[docIndex])
p0V,p1V,pSpam=trainNB0(trainMat,trainClasses)
# 测试集,测试错误率
errorCount=0
for docIndex in testSet:
wordVector=setOfWordsVec(vocabList,docList[docIndex])
if classifyNB(wordVector,p0V,p1V,pSpam)!=classList[docIndex]:
errorCount+=1
print 'the error rate is : ',float(errorCount)/len(testSet)
1
spamTest()
the error rate is :  0.2

使用朴素贝叶斯分类器从个人广告中获取区域倾向

  • 收集数据:从RSS源收集内容,这里需要对RSS源构建一个接口
  • 准备数据:将文本文件解析成词条向量
  • 分析数据:检查词条确保解析的正确性
  • 训练算法:使用我们之前建立的trainNB0()函数
  • 测试算法:观察错误率,确保分类器可用.可以修改切分程序,以降低错误率,提高分类结果.
  • 使用算法:构建一个完整的程序,封装所有内容.给定两个RSS源,该程序会显示最常用的公共词.

下面将使用来自不同城市的广告训练一个分类器,然后观察分类器的效果。我们的目的并不是使用该分类器进行分类,而是通过观察单词和条件概率值来发现与特定城市相关的内容。

Donate comment here