您的位置:首页 > 其它

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

2017-08-21 21:02 260 查看

使用python进行文本分类

# -*- coding: utf-8 -*-
"""
Created on Mon Aug 21 17:17:19 2017

@author: rocky
"""

#机器学习实战第四章
#朴素bayes
#使用python进行文本分类

#从文本中构建词向量
from numpy import *
def loadDataSet():#创建一个实验样本
postingList=[['my','dog','has','flea','problem','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 createVocalList(dataSet):
vocabSet=set([])#set返回一个不含重复词的列表
for document in dataSet:
vocabSet=vocabSet|set(document)#创建两个集合的并集
return list(vocabSet)

def setOfWord2Vec(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对程序1进行非重复处理并拼接,返回一篇文档
#程序3的输入分别对应程序2的结果和程序1中的第i篇文档,返回的结果是2的结果的每一个词
#是否出现在第i篇文章中。出现则是1,没出现则是0.
#这样我们就把一篇文章(在第i篇文档环境下)转换成了一组数字


我们可以做这样的实验,在命令窗口输入以下:

listOPosts,listClasses=loadDataSet()
data=[['my','dog'],['is','rain']]

lis=createVocalList(data)
lis
Out[22]: ['rain', 'my', 'is', 'dog']
setOfWord2Vec(lis,listOPosts[5])
the word: quit is not in my Vocabulary!
the word: buying is not in my Vocabulary!
the word: worthless is not in my Vocabulary!
the word: food is not in my Vocabulary!
the word: stupid is not in my Vocabulary!
Out[23]: [0, 0, 0, 1]


我们可以判断第六行的每个词是否出现在data中,从而得到data的数字表示,为后面对data进行概率计算(好坏属性判断)准备。

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

#训练算法:从词向量计算概率(假设二类分布,即只有两个属性)
def trainNB0(trainMatrix,trainCategory):
numTrainDocs=len(trainMatrix)#统计矩阵行数,即文档数
numWords=len(trainMatrix[0])#统计列数,即每个文档的字数
pAbusive=sum(trainCategory)/float(numTrainDocs)#计算文档属性的概率(P1,另一个就是P0)
p0Num=zeros(numWords)#建立零向量,长度为文档字数
p1Num=zeros(numWords)
p0Denom=0.0
p1Denom=0.0#以上是对概率的初始化
for i in range(numTrainDocs):#循环每个文档
if trainCategory[i]==1:#如果这个文档的属性是1
p1Num+=trainMatrix[i]#把第i行数据(或者第i个文档)赋给p1Num
p1Denom+=sum(trainMatrix[i])#求该文档中1的和,赋给。。。
else:
p0Num+=trainMatrix[i]
p0Denom+=sum(trainMatrix[i])
p1Vect=p1Num/p1Denom
p0Vect=p0Num/p0Denom
return p0Vect,p1Vect,pAbusive


在命令行输入以下命令检验:

#建立自己的数据集和类别,不使用上面的。
data=[['to','my','worthless'],['dog','take','ate'],['stop','to','him']]

listclass=[1,1,0]

mylist=createVocalList(data)
#mylist就是待检验的文档
mylist
Out[17]: ['to', 'worthless', 'take', 'ate', 'my', 'him', 'dog', 'stop']

trainmat=[]
#生成一个文本矩阵,代表着这个待检验文本在每个样本下的存在与否
for postindoc in data:
trainmat.append(setOfWord2Vec(mylist,postindoc))

trainmat
Out[21]: [[1, 1, 0, 0, 1, 0, 0, 0], [0, 0, 1, 1, 0, 0, 1, 0], [1, 0, 0, 0, 0, 1, 0, 1]]
#计算各个概率
p0V,p1V,pAb=trainNB0(trainmat,listclass)

pAb
Out[23]: 0.66666666666666663

p0V
Out[24]:
array([ 0.33333333,  0.        ,  0.        ,  0.        ,  0.        ,
0.33333333,  0.        ,  0.33333333])

p1V
Out[25]:
array([ 0.16666667,  0.16666667,  0.16666667,  0.16666667,  0.16666667,
0.        ,  0.16666667,  0.        ])


在trainNB0的循环中,循环参数是行数,也就是类别数,也就是3,而不是列数(8),这一点要注意。在上面自己的数据中,前两行类别都是1,那么经过i=0和i=1后,p1Num=(11111010)(两个向量相加),p1Denom=6(即3+3),经i=2后,p0Num=(10000101)(第三个向量),p0Denom=3。这样就可以计算概率了。

以上计算的是文本中每个词在各个类别下出现的概率。

测试算法,修改分类器

上面计算了各个词在每个类别下的概率,下面就要计算多个概率的乘积来获得文档属于某个类别的概率。那么如果一个词的概率为0,总结果就是0,这显然不行。所以进行简单处理,所有词的初始出现数为1,分母初始化2,修改上述程序。修改p0Num\p0Denom\p1Num\p1Denom的初值,以及最后的概率计算,改为对数运算。

def trainNB0(trainMatrix,trainCategory):
numTrainDocs=len(trainMatrix)#统计矩阵行数,即文档数
numWords=len(trainMatrix[0])#统计列数,即每个文档的字数
pAbusive=sum(trainCategory)/float(numTrainDocs)#计算文档属性的概率(P1,另一个就是P0)
p0Num=ones(numWords)#建立o向量,长度为文档字数
p1Num=ones(numWords)
p0Denom=2.0
p1Denom=2.0#以上是对概率的初始化
for i in range(numTrainDocs):#循环每个文档
if trainCategory[i]==1:#如果这个文档的属性是1
p1Num+=trainMatrix[i]#把第i行数据(或者第i个文档)赋给p1Num
p1Denom+=sum(trainMatrix[i])#求该文档中1的和,赋给。。。
else:
p0Num+=trainMatrix[i]
p0Denom+=sum(trainMatrix[i])
p1Vect=log(p1Num/p1Denom)
p0Vect=log(p0Num/p0Denom)
return p0Vect,p1Vect,pAbusive


下面构建完整的分类器。

#创建朴素贝叶斯分类函数
def classifyNB(vec2Classify,p0Vec,p1Vec,pClass1):
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=createVocalList(listOPosts)
trainMat=[]
for postinDoc in listOPosts:
trainMat.append(setOfWord2Vec(myVocabList,postinDoc))
p0V,p1V,pAb=trainNB0(array(trainMat),array(listClasses))
testEntry=['love','my','dalmation']
thisDoc1=array(setOfWord2Vec(myVocabList,testEntry))
#上面这一句的意思是检查myVocabList中的文字是否出现在testEntry中
print(testEntry,'classified as: ',classifyNB(thisDoc1,p0V,p1V,pAb))

testEntry=['stupid','garbage']
thisDoc2=array(setOfWord2Vec(myVocabList,testEntry))
print(testEntry,'classified as: ',classifyNB(thisDoc2,p0V,p1V,pAb))
return thisDoc1,thisDoc2


最后的return thisDoc1,thisDoc2是自己加的,检查结果。后一个函数是封装了一些操作。命令窗口输入以下:

testingNB()
['love', 'my', 'dalmation'] classified as:  0
['stupid', 'garbage'] classified as:  1
Out[31]: (array([0, 0, 0, ..., 1, 0, 0]), array([0, 0, 0, ..., 0, 1, 0]))


我们可以看到,thisDoc1结果是([0, 0, 0, …, 1, 0, 0]),中间有一些省略号,看不到中间是什么数据,这时我们可以在开头定义numpy的下面,输入一行’np.set_printoptions(threshold=np.inf)’,可以保证数据全部显示,另外我也将myVocabList输出(return稍作修改即可):

testingNB()
['love', 'my', 'dalmation'] classified as:  0
['stupid', 'garbage'] classified as:  1
Out[42]:
(array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0,
0, 0, 0, 0, 0, 0, 1, 0, 0]),
array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 1, 0, 0, 0, 0, 1, 0]),
['to',
'worthless',
'ate',
'quit',
'stop',
'steak',
'take',
'has',
'I',
'problem',
'park',
'dog',
'so',
'love',
'is',
'posting',
'flea',
'not',
'help',
'maybe',
'my',
'licks',
'food',
'cute',
'buying',
'stupid',
'how',
'please',
'him',
'dalmation',
'garbage',
'mr'])


以上我们可以看到[‘love’, ‘my’, ‘dalmation’]的出现,用1表示,而之前我们得到了一个概率分布,这样thisDoc1(thisDoc2)表示待测文本在当前环境下的表示(仍保持thisDoc1的意义),这样再利用函数classifyNB就可以计算thisDoc1是否属于侮辱性文档的概率。

注:处理垃圾邮件尚未学习,等回顾上述思路待后续。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: