naive bayes 算法的Python实现与理解

在机器学习中,朴素贝叶斯算法对于大家来说其实并不陌生,在我前面的博客中,我也对朴素贝叶斯算法的原理有所介绍,这篇文章我们一起来学习如何用Python来实现这个朴素贝叶斯算法。
首先我们导入numpy这个Python库,来支持我们后续的一些数学运算。

from numpy import *

然后我们定义一个导入数据集的方法,这个数据集是一个有6个维度的向量,其中向量中的内容是若干词语,这些词语是带有感情色彩的,然后classVec中1表示带有侮辱性的词语,0代表正常的词语,这个方法如下:

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]
    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   # index函数在字符串里找到字符第一次出现的位置 词集模型
            returnVec[vocabList.index(word)] += 1    # 文档的词袋模型
        else: print (the word: %s is not in my Vocabulary!" % word)
    return returnVec

我们将词语转换成向量之后,就容易进行数学处理了,下一步我们来定义朴素贝叶斯分类器的训练函数:

def trainNB1(trainMatrix,trainCategory):
    numTrainDocs=len(trainMatrix)
    numWord=len(trainMatrix[0])
    pAbusive=sum(trainCategory)/len(trainCategory)
    p0Num=ones(numWord)
    p1Num=ones(numWord)# 初始化为1
    p0Demon=2
    p1Demon=2 #初始化为2
    for i in range(numTrainDocs):
        if trainCategory[i]==0:
            p0Num+=trainMatrix[i]
            p0Demon+=sum(trainMatrix[i])
        else:
            p1Num+=trainMatrix[i]
            p1Demon+=sum(trainMatrix[i])
    p0Vec=log(p0Num/p0Demon) #对结果求对数
    p1Vec=log(p1Num/p1Demon)
    return p0Vec,p1Vec,pAbusive

在这里,我们来看看如何利用词向量来计算概率,根据朴素贝叶斯公式,假设这个词向量为:

w=(w1,w2,...,wn) w = ( w 1 , w 2 , . . . , w n )

这个向量分到类别ci的概率可以用朴素贝叶斯公式表示:
p(ci|w)=p(w|ci)p(ci)p(w) p ( c i | w ) = p ( w | c i ) ⋅ p ( c i ) p ( w )

可以看到这个公式中p(ci)的数量表示类别ci的数量,p(ci)的计算公式可以表示成:p(ci) = 类别ci的样本数量/总的样本数量,p(ω|ci)由于各个条件特征相互独立且地位相同,所以在求解p(ω|ci),我们可以用到公式p(ω|ci) = p(w0|ci)p(w1|ci)p(w2|ci)……p(wn|ci),而求p(ωk|ci)也就是求在分类类别为ci的文档词汇表集合中,单个词项ωk出现的概率,用公式可以表示成:p(wi|ci) = wi在ci中出现的次数/ci类别的词的总数。p0Vec=p0Num/p0Demon是用向量除以词项的总和,我们可以理解成将这个向量标准化,归一化,便于后续的处理。因为在公式p(ω|ci) = p(w0|ci)p(w1|ci)p(w2|ci)……p(wN|ci)中,可能会因为其中某一项为0的话,整个p(ω|ci) 就会等于0,为了避免零概率的存在,我们把向量里元素的初始值都初始化为1。还有就是各个项相乘的时候,因为每一项都很小,所以可能导致结果溢出,我们就考虑取对数的方法来防止结果溢出。接着,我们可以用贝叶斯公式计算概率来对词语进行分类:

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

有了这个分类器之后,我们创建测试样本来对我们的样本进行分类操作:

def testingNB():
    listPosts,listClasses=loadDataSet()
    myVocabList=createVocabList(listPosts)
    trainMat=[]
    for postinDoc in listPosts:
        trainMat.append(setOfWords2Vec(myVocabList,postinDoc))
    p0V,p1V,pAb=trainNB1(trainMat,listClasses)
    testEntry=['love','my','dalmation']
    thisDoc=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))

最后我们执行这个方法,可以得到分类结果:

['love', 'my', 'dalmation'] classified as: 0 #分类到正常言论
['stupid', 'garbage'] classified as: 1 #分类到侮辱性言论

最后我们可以得到这两组测试样本正确的分类,希望这篇文章对各位朋友对朴素贝叶斯算法的理解有所帮助,如有纰漏,也请各位不吝指教。

你可能感兴趣的:(Machine,Learning)