背景:以在线社区的留言板为例,为了不影响社区的发展,我们需要屏蔽侮辱性的言论,所以要构建一个快速过滤器,如果某条留言使用了负面或者侮辱性的语言,那么就将该留言标识为内容不当。过滤这类内容是一个很常见的需求,对此问题建立两个类别:侮辱类和非侮辱类,使用0和1分别表示。

接下来首先给出将文本转换为数字向量的过程,然后介绍如何基于这些向量来计算条件概率,并在此基础上构建分类器。创建一个bayes.py的新文件

 1、准备数据:从文本中构建词向量

要从文本中获取特征,需要先拆分文本,这里的特征来自文本的词条(token),一个词条是字符的任意组合。可以把词条想象为单词,也可以使用非单词词条,如:URL、IP地址或者任意其他字符串。然后将每一个文本片段表示为一个词条向量,其中值为1表示词条出现在文档,0表示词条未出现。

我们将把文本看成单词向量或者词条向量,也就是说将句子抓换为向量。考虑出现在所有文档中的所有单词,再决定将那些词纳入词汇表或者说所要的词汇集合,然后必须要将每一篇文档转换为词汇表上的向量。

#词表到向量的转换函数
#!/usr/bin/python
# -*- coding: utf-8 -*-
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 createVocabList(dataSet):
vocabSet=set([]) #创建一个空集
for document in dataSet:
vocabSet=vocabSet|set(document) #创建两个集合的并集,set会返回一个不重复词表
return list(vocabSet)
#该函数输入参数为词汇表及其某个文档,输出是文档向量
def setOfWords2Vec(vocabList,inputSet):
returnVec=[0]*len(vocabList)  #创建一个和词汇表等长的向量,并将其元素都设置为0
for word in inputSet:  #遍历输入文档中所有单词,如果出现了词汇表中的单词,则将输出的文档向量中的对应值设为1
if word in inputSet:
returnVec[vocabList.index(word)]=1
else:print "the word:%s is not in my Vocabulary!" % word
return returnVec

保存bayes.py文件,然后在python提示符下输入:

  >>> import bayes
 >>> listOPosts,listClasses=bayes.loadDataSet()
 >>> myVocabList=bayes.createVocabList(listOPosts)
 >>> myVocabList
['cute', 'love', 'help', 'garbage', 'quit', 'I', 'stop', 'is', 'park', 'flea', 'dalmation', 'licks', 'food', 'not', 'him', 'buying', 'posting', 'has', 'worthless', 'ate', 'to', 'maybe', 'please', 'dog', 'how', 'stupid', 'so', 'take', 'mr', 'problem', 'steak', 'my']
 >>> bayes.setOfWords2Vec(myVocabList,listOPosts[0])
[0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1]
>>> bayes.setOfWords2Vec(myVocabList,listOPosts[1])
[0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0]
 >>> bayes.setOfWords2Vec(myVocabList,listOPosts[2])
  [1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]
  >>> bayes.setOfWords2Vec(myVocabList,listOPosts[3])
  [0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0]
  >>> bayes.setOfWords2Vec(myVocabList,listOPosts[4])
  [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1]
  >>> bayes.setOfWords2Vec(myVocabList,listOPosts[5])
  [0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0]

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

前面介绍了如何将一组单词转换为一组数字,接下来看看如何使用这些数字计算概率。现在已经知道一个词是否出现在一篇文档中,也知道该文档所属类别。

(1)

首先通过类别i中文档数除以总的文档数来计算概率P(Ci),然后计算P(w|Ci),即P(w0|Ci)P(w1Ci)...P(wN|Ci)来计算上述概率。

#朴素贝叶斯分类器训练函数
def trainNBO(trainMatrix,trainCategory):
numTrainDocs=len(trainMatrix)
numWords=len(trainMatrix[0])
pAbusive=sum(trainCategory)/float(numTrainDocs)
p0Num=zeros(numWords);p1Num=zeros(numWords)
p0Demo=0.0;p1Demo=0.0 #初始化概率
for i in range(numTrainDocs):
if trainCategory[i]==1:
p1Num+=trainMatrix[i]
p1Demo+=sum(trainMatrix[i])
else:
p0Num+=trainMatrix[i]
p0Demo+=sum(trainMatrix[i])
p1Vect=p1Num/p1Demo
p0Vect=p0Num/p0Demo
return p0Vect,p1Vect,pAbusive

将上述代码添加到bayes.py文件中,在python提示符下输入:

>>> reload(bayes)
<module 'bayes' from 'bayes.py'>
>>> listOPosts,listClass=bayes.loadDataSet()
>>> listOPosts
[['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']]
>>> listClasses
[0, 1, 0, 1, 0, 1]
>>> myVocabList=bayes.createVocabList(listOPosts)
>>> trainMat=[]
>>> trainMat
[[0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1], [0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0],
[1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1],
[0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0]]
>>> p0V,p1V,pAb=bayes.trainNBO(trainMat,listClasses)
>>> pAb
0.5
>>> p0V  #求的是p(w|C0),0.04166667=(cute在非侮辱文档0、2、4中cute出现的总次数)/(非侮辱文档中的总词条数)=1/24)
array([ 0.04166667,  0.04166667,  0.04166667,  0.        ,  0.        ,
        0.04166667,  0.04166667,  0.04166667,  0.        ,  0.04166667,
        0.04166667,  0.04166667,  0.        ,  0.        ,  0.08333333,
        0.        ,  0.        ,  0.04166667,  0.        ,  0.04166667,
        0.04166667,  0.        ,  0.04166667,  0.04166667,  0.04166667,
        0.        ,  0.04166667,  0.        ,  0.04166667,  0.04166667,
        0.04166667,  0.125     ])
>>> p1V  #求的是p(w|C1),0.15789474=(stupid在侮辱文档1、3、5中stupid出现的总次数)/(侮辱文档中的总词条数)=3/19)
array([ 0.        ,  0.        ,  0.        ,  0.05263158,  0.05263158,
        0.        ,  0.05263158,  0.        ,  0.05263158,  0.        ,
        0.        ,  0.        ,  0.05263158,  0.05263158,  0.05263158,
        0.05263158,  0.05263158,  0.        ,  0.10526316,  0.        ,
        0.05263158,  0.05263158,  0.        ,  0.10526316,  0.        ,
        0.15789474,  0.        ,  0.05263158,  0.        ,  0.        ,
        0.        ,  0.        ])

解释:

>>> numTrainDocs=len(trainMat)
>>> numTrainDocs
6
>>> numWords=len(trainMat[0])
>>> numWords
32
>>> from numpy import *
>>> p0Num=zeros(numWords);p1Num=zeros(numWords);p0Demo=0.0;p1Demo=0.0
>>> p0Num
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., 0., 0., 0., 0., 0., 0., 0.])
>>> for i in range(numTrainDocs):
... if listClasses[i]==1:
... p1Num+=trainMat[i]
... p1Demo+=sum(trainMat[i])
... else:
... p0Num+=trainMat[i]
... p0Demo+=sum(trainMat[i])
...
>>> p0Num
array([ 1., 1., 1., 0., 0., 1., 1., 1., 0., 1., 1., 1., 0., 0., 2., 0., 0., 1., 0., 1., 1., 0., 1., 1., 1., 0., 1., 0., 1., 1., 1., 3.]) #trainMat的第一行、三行、五行非侮辱性文档词向量相加
>>> p0Demo
24.0
>>> p1Num
array([ 0., 0., 0., 1., 1., 0., 1., 0., 1., 0., 0., 0., 1., 1., 1., 1., 1., 0., 2., 0., 1., 1., 0., 2., 0., 3., 0., 1., 0., 0., 0., 0.]) #trainMat的第二行、四行、六行非侮辱性文档词向量相加
>>> p1Demo
19.0

3、测试算法:根据现实情况修改分类器

利用贝叶斯分类器对文档进行分类时,要计算多个概率的乘积以获得文档属于某个类别的概率,即计算P(w0|1)P(w1|1)P(w2|1)...,如果其中一个概率值为0,那么最后的乘积也为0。为降低这种影响,可以将所有词的出现次数初始化为1,并将分母初始化为2。修改trainNBO()的相应位置的代码:

p0Num=ones(numWords);p1Num=ones(numWords)   #计算p(w0|1)p(w1|1),避免其中一个概率值为0,最后的乘积为0
p0Demo=2.0;p1Demo=2.0 #初始化概率
p1Vect=log(p1Num/p1Demo) #计算p(w0|1)p(w1|1)时,大部分因子都非常小,程序会下溢出或得不到正确答案(相乘许多很小数,最后四舍五入会得到0)
p0Vect=log(p0Num/p0Demo)

运行后:


>>> reload(bayes)
<module 'bayes' from 'bayes.py'>
>>> listOPosts,listClass=bayes.loadDataSet()
>>> listOPosts
[['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']]
>>> listClasses
[0, 1, 0, 1, 0, 1]
>>> myVocabList=bayes.createVocabList(listOPosts)
>>> trainMat=[]
>>> trainMat
[[0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1], [0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0],
[1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1],
[0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0]]
>>> p0V,p1V,pAb=bayes.trainNBO(trainMat,listClasses)
>>> pAb
0.5
>>> p0V #求的是p(w|C0),-2.56494936=log((cute在非侮辱文档0、2、4中cute出现的总次数)/(非侮辱文档中的总词条数))=log(2/26))
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, -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,
       -2.56494936, -1.87180218])
>>> p1V #求的是p(w|C1),-1.65822808=log((stupid在侮辱文档1、3、5中stupid出现的总次数)/(侮辱文档中的总词条数))=log(4/21))
array([-3.04452244, -3.04452244, -3.04452244, -2.35137526, -2.35137526,
       -3.04452244, -2.35137526, -3.04452244, -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, -3.04452244])

解释:

>>> numTrainDocs=len(trainMat)
>>> numTrainDocs
6
>>> numWords=len(trainMat[0])
>>> numWords
32
>>> from numpy import *
>>> p0Num=ones(numWords);p1Num=ones(numWords);p0Demo=2.0;p1Demo=2.0
>>> p0Num
array([ 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.])
>>> for i in range(numTrainDocs):
... if listClasses[i]==1:
... p1Num+=trainMat[i]
... p1Demo+=sum(trainMat[i])
... else:
... p0Num+=trainMat[i]
... p0Demo+=sum(trainMat[i])
...
>>> p0Num
array([ 2., 2., 2., 1., 1., 2., 2., 2., 1., 2., 2., 2., 1., 1., 3., 1., 1., 2., 1., 2., 2., 1., 2., 2., 2., 1., 2., 1., 2., 2., 2., 4.])
>>> p0Demo
26.0
>>> sum(p0Num)
56.0
>>> p1Num
array([ 1., 1., 1., 2., 2., 1., 2., 1., 2., 1., 1., 1., 2., 2., 2., 2., 2., 1., 3., 1., 2., 2., 1., 3., 1., 4., 1., 2., 1., 1., 1., 1.])
>>> p1Demo
21.0
>>> sum(p1Num)
51.0
#朴素贝叶斯分类函数
def classifyNB(vec2Classify,p0Vec,p1Vec,pClass1):  #vec2Classify表示要分类的向量
p1=sum(vec2Classify*p1Vec)+log(pClass1)  #这里的相乘是指对应元素相乘,即先将两个向量中的第1个元素相乘,然后将第2个元素相乘,以此类推,接下来将词汇表中所有词的对应值相加,然后将该值家到类别的对数频率上。
p0=sum(vec2Classify*p0Vec)+log(1.0-pClass1)
if p1>p0:
return 1
else:
return 0
def testingNB():
listOPosts,listClasses=loadDataSet()
myVocabList=createVocabList(listOPosts)
trainMat=[]
for postinDoc in listOPosts:
trainMat.append(setOfWords2Vec(myVocabList,postinDoc))
p0V,p1V,pAb=trainNBO(array(trainMat),array(listClasses))
testEntry=['love','my','dalmation']
thisDoc=array(setOfWords2Vec(myVocabList,testEntry))
print testEntry,'classified as:',classifyNB(thisDoc,p0V,p1V,pAb)
testEntry=['stupid','garbage']
thisDoc=array(setOfWords2Vec(myVocabList,testEntry))
print testEntry,'classified as:',classifyNB(thisDoc,p0V,p1V,pAb)

将上述代码添加到bayes.py文件中,在python提示符下输入:

>>> reload(bayes)
<module 'bayes' from 'bayes.pyc'>
>>> bayes.testingNB()
['love', 'my', 'dalmation'] classified as: 0
['stupid', 'garbage'] classified as: 1

【Machine Learning in Action --4】朴素贝叶斯过滤网站的恶意留言的更多相关文章

  1. Machine Learning in Action(3) 朴素贝叶斯算法

    贝叶斯决策一直很有争议,今年是贝叶斯250周年,历经沉浮,今天它的应用又开始逐渐活跃,有兴趣的可以看看斯坦福Brad Efron大师对其的反思,两篇文章:“Bayes'Theorem in the 2 ...

  2. 《Machine Learning in Action》—— 白话贝叶斯,“恰瓜群众”应该恰好瓜还是恰坏瓜

    <Machine Learning in Action>-- 白话贝叶斯,"恰瓜群众"应该恰好瓜还是恰坏瓜 概率论,可以说是在机器学习当中扮演了一个非常重要的角色了.T ...

  3. machine learning for hacker记录(3) 贝叶斯分类器

    本章主要介绍了分类算法里面的一种最基本的分类器:朴素贝叶斯算法(NB),算法性能正如英文缩写的一样,很NB,尤其在垃圾邮件检测领域,关于贝叶斯的网上资料也很多,这里推荐那篇刘未鹏写的http://mi ...

  4. 吴裕雄--天生自然python机器学习:使用朴素贝叶斯过滤垃圾邮件

    使用朴素贝叶斯解决一些现实生活中 的问题时,需要先从文本内容得到字符串列表,然后生成词向量. 准备数据:切分文本 测试算法:使用朴素贝叶斯进行交叉验证 文件解析及完整的垃圾邮件测试函数 def cre ...

  5. 《Machine Learning in Action》—— 浅谈线性回归的那些事

    <Machine Learning in Action>-- 浅谈线性回归的那些事 手撕机器学习算法系列文章已经肝了不少,自我感觉质量都挺不错的.目前已经更新了支持向量机SVM.决策树.K ...

  6. 《Machine Learning in Action》—— Taoye给你讲讲Logistic回归是咋回事

    在手撕机器学习系列文章的上一篇,我们详细讲解了线性回归的问题,并且最后通过梯度下降算法拟合了一条直线,从而使得这条直线尽可能的切合数据样本集,已到达模型损失值最小的目的. 在本篇文章中,我们主要是手撕 ...

  7. 机器学习实战 [Machine learning in action]

    内容简介 机器学习是人工智能研究领域中一个极其重要的研究方向,在现今的大数据时代背景下,捕获数据并从中萃取有价值的信息或模式,成为各行业求生存.谋发展的决定性手段,这使得这一过去为分析师和数学家所专属 ...

  8. 朴素贝叶斯python实现

    概率论是非常多机器学习算法基础,朴素贝叶斯分类器之所以称为朴素,是由于整个形式化过程中仅仅做最原始.简单的如果. (这个如果:问题中有非常多特征,我们简单如果一个个特征是独立的.该如果称做条件独立性, ...

  9. 【机器学习实战】第4章 朴素贝叶斯(Naive Bayes)

    第4章 基于概率论的分类方法:朴素贝叶斯 朴素贝叶斯 概述 贝叶斯分类是一类分类算法的总称,这类算法均以贝叶斯定理为基础,故统称为贝叶斯分类.本章首先介绍贝叶斯分类算法的基础——贝叶斯定理.最后,我们 ...

随机推荐

  1. request获取ip

    public static String getIp(HttpServletRequest request) { String ip = request.getHeader("x-forwa ...

  2. Linux Curl常用命令使用【转】

    Curl是Linux下一个很强大的http命令行工具,其功能十分强大. 1)读取网页 $ curl linuxidc.com">http://www.linuxidc.com 2)保存 ...

  3. magento里的session传值

    1.$registrationCode = Mage::getSingleton('customer/session' )->setData('login_phone_code', $valid ...

  4. 【Python】使用super初始化超类

    初始化超类的传统方式,在子类的实例中调用超类的__init__()方法. 但是传统的方法有两个问题,比如: 问题1: class MyBaseClass: def __init__(self, val ...

  5. CentOS 7中将Tomcat设置为系统服务

    tomcat 需要增加一个pid文件,在tomca/bin 目录下面,增加 setenv.sh 配置,catalina.sh启动的时候会调用,在该文件中添加如下内容 CATALINA_PID=&quo ...

  6. AJAX在Struts2中使用

    前台页面: <%@ page language="java" contentType="text/html; charset=UTF-8" pageEnc ...

  7. wall time

    "showing elapsed time and wall clock time correspondingly." what's difference between elap ...

  8. opencv3.1自带demo的介绍和运行操作。转载

    opencv3.1自带demo的介绍和运行操作. 下列实验基本都试过,有些需要根据自己的电脑修改一些路径或者调试参数. 值得注意的是,控制台程序输入有时候要在图像所在的窗口输入相应的指令.我的电脑上安 ...

  9. JavaScript 作用域 匿名函数 模仿块级作用域(私有作用域)

    作用域 对于有块级作用域的语言来说,for语句中定义并初始化的变量i在循环外是无法访问的. 而javascript没有块级作用域,for语句中定义的变量i在循环结束后,依旧会存在于循环外部的执行环境( ...

  10. C# lesson2

    一.C#数据类型 1.值类型 包括数据相关(short.long.int .double.float).布尔(bool).枚举 2.引用类型 Object .对象.数组.字符串 二.存储方式 值类型 ...