【python和机器学习入门3】朴素贝叶斯1——过滤恶意留言

参考博客:朴素贝叶斯基础篇之言论过滤器 (po主Jack-Cui,《——大部分内容转载自

                 

参考书籍:《机器学习实战》——第四章4.5

一 朴素贝叶斯理论

 

二 demo:过滤网站恶意留言

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

    我们把文本看成单词向量或者词条向量,也就是说将句子转换为向量。考虑出现所有文档中的单词,再决定将哪些单词纳入词汇表或者说所要的词汇集合,然后必须要将每一篇文档转换为词汇表上的向量。简单起见,我们先假设已经将本文切分完毕,存放到列表中,并对词汇向量进行分类标注。

1.1 准备数据

准备数据包括3块:导入数据,创建词汇表,构建词向量

本demo的数据直接假设已经将文档切分成词条。数据包括6个切分好的文档词条和6个文档对应分类。

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):
    vocabList = set([]) #创建一个空的set集合
    for data in dataset: #遍历每个文档句子
        vocabList = vocabList | set(data) #取与之前的词汇表的交集,目的在于去重
    return list(vocabList) #返回list形式

 

1.3 训练数据

本demo的目标是计算一篇文档在侮辱类c1和非侮辱类c2下的概率并比较两概率,预测该文档为最大概率的类

根据一般贝叶斯条件概率公式和朴素贝叶斯独立性的要求,可以得到概率公式

文档w (包含词汇w1~wn) 属于ci类 的概率p (ci|w) = p(w | ci) * p(ci) / p(w) = p(w1|ci)*...*p(wn|ci) * p(ci) / p(w)

因为我们只是要比较各类下文档w的概率,而分子p(w)都相同,在代码中计算可以省略,所以代码中的计算公式如下

p (ci|w) = p(w | ci) * p(ci)  = p(w1|ci)*...*p(wn|ci) * p(ci) 

本demo是个二分类。知道p1就可以用1-p1来计算p0,所以代码直接这样计算了。多分类需要稍加改动。

 

P(c1) = P1 = 训练集类标签为1的数量 / 训练集总数 = 侮辱类数量/ 训练集总数

即pAbuses = float(sum(trainCategory)) / float(numTrainDocs) 

 P(c0) = P0 = 训练集类标签为0的数量 / 训练集总数 = 1 - p1

p(wi | ci)该类下该单词出现的概率该类下该单词出现的次数 / 该类的单词总数,代码中为

p(w | ci) = p1Num / p1Denom

'''计算p(wi|ci) 和 p1
   该类下,该单词出现的概率
   需要计算每一类每个单词出现的次数(分子) 和 每一类出现过的总单词数(分母)
    ————————————————————————————————————————
   参数:trainMatrix 训练集数据矩阵,多个doc的词汇表向量
        trainCategory 训练集类矩阵
'''
def trainNB(trainMatrix,trainCategory):
    numTrainDocs = len(trainMatrix)  #文档数目
    numWords = len(trainMatrix[0]) #词汇表单词总数
    pAbuses = float(sum(trainCategory)) / float(numTrainDocs) # p1
    p1Num = ones(numWords)
    p0Num = ones(numWords) #记录每个单词在该类出现的次数,是一个向量
    p1Denom = 2.0
    p0Denom = 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])
    p1Vec = log(p1Num / p1Denom)
    p0Vec = log(p0Num / p0Denom)
    return p0Vec,p1Vec,pAbuses

 

1.4 测试数据


'''计算文档属于某个类别i的概率:p = p(w0|ci)p(w1|ci)p(w2|ci)~p(wn|ci)*p(ci)'''
def classiftNB(vec2classify,p0vec,p1vec,pclass1):
    p1 = sum(vec2classify * p1vec) + log(pclass1)
    p0 = sum(vec2classify * p0vec) + log(1 - pclass1)
    if p1 > p0:
        print "p1=%f" % p1
        return 1
    else:
        print "p0=%f" % p0
        return 0

1.5 完整代码

#!/usr/bin/env python
#_*_coding:utf-8_*_
from numpy import *
'''
    文本分类
'''


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):
    vocabList = set([])
    for data in dataset:
        vocabList = vocabList | set(data)
    return list(vocabList)

'''词汇转向量'''
def setOfWord2Vec(vocabList,dataset):
    returnVec = [0] * len(vocabList)
    for word in dataset:
        if word in vocabList:
            returnVec[vocabList.index(word)] = 1 #单词出现标1
        else:
            print "sorry this word %s is not in our vocablist" % word
    return  returnVec


'''计算p(wi|ci)
   该类下,该单词出现的概率
   需要计算每一类每个单词出现的次数(分子) 和 每一类出现过的总单词数(分母)
'''
def trainNB(trainMatrix,trainCategory):
    numTrainDocs = len(trainMatrix)
    numWords = len(trainMatrix[0])
    pAbuses = float(sum(trainCategory)) / float(numTrainDocs)
    p1Num = ones(numWords)
    p0Num = ones(numWords) #记录每个单词在该类出现的次数,是一个向量
    p1Denom = 2.0
    p0Denom = 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])
    p1Vec = log(p1Num / p1Denom)
    p0Vec = log(p0Num / p0Denom)
    return p0Vec,p1Vec,pAbuses

'''计算文档属于某个类别i的概率:p = p(w0|ci)p(w1|ci)p(w2|ci)~p(wn|ci)*p(ci)'''
def classiftNB(vec2classify,p0vec,p1vec,pclass1):
    p1 = sum(vec2classify * p1vec) + log(pclass1)
    p0 = sum(vec2classify * p0vec) + log(1 - pclass1)
    if p1 > p0:
        print "p1=%f" % p1
        return 1
    else:
        print "p0=%f" % p0
        return 0

if __name__ == '__main__':
    postingList, classVec = loadDataSet()
    vocabList = createVocablist(postingList)
    word2Vec = []
    for data in postingList:
        word2Vec.append(setOfWord2Vec(vocabList,data))
    p0Vec, p1Vec, pAbuses = trainNB(word2Vec,classVec)
    testList = ['love','my','dalmation']
    test2Vec = setOfWord2Vec(vocabList,testList)
    classResult = classiftNB(test2Vec,p0Vec,p1Vec,pAbuses)
    if classResult == 1:
        print "该文档分类为 侮辱性"
    else:
        print "该文档分类为 正常"

 

你可能感兴趣的:(机器学习,python)