机器学习——朴素贝叶斯

目录

一.朴素贝叶斯

所谓的“朴素”即是说各个属性之间是互相独立的。

朴素贝叶斯公式:​

二.使用Python进行文本分类

三.使用朴素贝叶斯进行垃圾邮件过滤


一.朴素贝叶斯

1.条件概率知识:事件A在另外一个事件B已经发生条件下的发生概率。条件概率表示为P(A|B),读作“在B条件下A的概率。

机器学习——朴素贝叶斯_第1张图片

机器学习——朴素贝叶斯_第2张图片

如果已知P(A|B),要求P(B|A),则有:

机器学习——朴素贝叶斯_第3张图片

 全概率公式: 表示若事件A1,A2,…,An构成一个完备事件组且都有正概率,则对任意一个事件B都有公式成立。

贝叶斯公式是将全概率公式带入到条件概率公式当中, 对于事件A和事件B有:

 

 对于P(Ai​∣B)来说,分母都是固定的。所以只用比较分子即可。

所谓的“朴素”即是说各个属性之间是互相独立的。

朴素贝叶斯公式:

(其中是先验概率,xi表示第i个属性)

二.使用Python进行文本分类

1.准备数据:

import numpy as np
import random
import re

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):
    vocabSet = set([])  #创建一个空集
    for document in dataSet:
        vocabSet = vocabSet | set(document) #创建两个集合的并集
    return list(vocabSet)

def setOfWords2Vec(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

if __name__ == '__main__':
    postingList,classVec = loadDataSet()
    print("postingList:\n",postingList)
    myVocabList = createVocabList(postingList)
    print('myVocabList:\n',myVocabList)
    trainMat = []
    for postingLIst in postingList:
        trainMat.append(setOfWords2Vec(myVocabList,postingLIst))
    print('trainMat:\n',trainMat)

运行结果:

 2.从词向量计算概率

机器学习——朴素贝叶斯_第4张图片

此时x是向量,即它由多个数值组成 

代码实现:

def trainNB0(trainMatrix, trainCategory):
    numTrainDocs = len(trainMatrix)
    numWords = len(trainMatrix[0])
    pAbusive = sum(trainCategory)/float(numTrainDocs)
    p0Num = np.zeros(numWords); p1Num = np.zeros(numWords)
    p0Denom = 0.0; p1Denom = 0.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 = p1Num/p1Denom            #转换为log
    p0Vect = p0Num/p0Denom       
    return p0Vect, p1Vect, pAbusive

if __name__ == '__main__':
    postingList,classVec = loadDataSet()
    print("postingList:\n",postingList)
    myVocabList = createVocabList(postingList)
    print('myVocabList:\n',myVocabList)
    trainMat = []
    for postingLIst in postingList:
        trainMat.append(setOfWords2Vec(myVocabList,postingLIst))
    p0V, p1V, pAb = trainNB0(trainMat, classVec)
    print('trainMat:\n', trainMat)
    print('p0Vect:\n', p0V)   #正常言论的概率
    print('p1Vect:\n', p1V)    #侮辱性词汇的概率
    print('classVec:\n', classVec)
    print('pAbusive:\n', pAb)   #侮辱性词汇占总样本的概率

运行结果:

 机器学习——朴素贝叶斯_第5张图片

 

 3.朴素贝叶斯分类函数

代码实现:

def classifyNB(vec2Classify, p0Vec, p1Vec, pClass1):
    p1 = sum(vec2Classify * p1Vec) + np.log(pClass1)    #element-wise mult
    p0 = sum(vec2Classify * p0Vec) + np.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 = trainNB0(np.array(trainMat), np.array(listClasses))
    testEntry = ['love', 'my', 'dalmation']
    thisDoc = np.array(setOfWords2Vec(myVocabList, testEntry))
    if classifyNB(thisDoc,p0V,p1V,pAb):
        print(testEntry,'属于侮辱类词汇')
    else:
        print(testEntry,'属于非侮辱类词汇')
    testEntry = ['stupid', 'garbage']
    thisDoc = np.array(setOfWords2Vec(myVocabList, testEntry))
    if classifyNB(thisDoc, p0V, p1V, pAb):
        print(testEntry, '属于侮辱类词汇')
    else:
        print(testEntry, '属于非侮辱类词汇')

结果展示:

4.准备数据:文档词袋模型

目前为止,我们将每个词的出现与否作为一个特征, 这可以被描述为词集模型( set-of- wordsmodel )。如果-一个词在文档中出现不止一次,这可能意味着包含该词是否出现在文档中所不能表达的某种信息,这种方法被称为词袋模型( bag-of-words model )。在词袋中,每个单词可以出现多次,而在词集中,每个词只能出现一次。为适应词袋模型,需要对函数setofWords2Vec()稍加修改,修改后的函数称为bagOfWords2Vec()。

它与函数setOfWords2Vec()几乎完全相同,唯一不同的是每当遇到一个单词时,它会增加词向量中的对应值,而不只是将对应的数值设为1.

def bagOfWords2VecMN(vocabList, inputSet):
    returnVec = [0]*len(vocabList)
    for word in inputSet:
        if word in vocabList:
            returnVec[vocabList.index(word)] += 1
    return returnVec

三.使用朴素贝叶斯进行垃圾邮件过滤

函数spamTest()对贝叶斯垃圾邮件分类器进行自动化处理。导入文件夹spam和ham下的文本文件,并将它们解析为词汇表中。接下来构建一个测试集和一个训练集,两个集合中的邮件都是随机选出的。在该示例中共有50封邮件,其中10封邮件被随机选择为测试集。分类器所需要的概率计算指利用训练集中的文档来完成。Python变量trainingSet是一个整数列表,值从0到49.接下俩,随机选择10个文件,选择出的数字所对应的文档被添加到训练集,同时也将其从训练集中提出。这种随机选择数据的一部分作为训练集,而剩余部分作为测试集的过程称为留存交叉验证。假设现在只完成了一次迭代,那么为了更精确地估计分类器的错误率,就应该多次迭代后求出平均错误率。

接下来的for循环遍历训练集的所有文档,对每封邮件基于词汇表并使用setOfWords2Vec()函数来构建词向量。这些词在trainNB0()函数中用于计算分类所需的概率,然后遍历测试集

def spamTest():
    docList = []; classList = []; fullText = []
    for i in range(1, 26):
        wordList = textParse(open('D:/pycharm/实验/test/spam/%d.txt' % i,encoding="ISO-8859-1").read())
        docList.append(wordList)
        fullText.extend(wordList)
        classList.append(1)             #标记垃圾邮件,1表示垃圾邮件
        wordList = textParse(open('D:/pycharm/实验/test/ham/%d.txt' % i,encoding="ISO-8859-1").read())
        docList.append(wordList)
        fullText.extend(wordList)
        classList.append(0)                 #标记非垃圾邮件,0表示非垃圾邮件
    vocabList = createVocabList(docList)#create vocabulary
    trainingSet = range(50); testSet = []           #create test set
    for i in range(10):                  # 从50个邮件中,随机挑选出40个作为训练集,10个做测试集
        randIndex = int(np.random.uniform(0, len(trainingSet)))
        testSet.append(trainingSet[randIndex])
        del(list(trainingSet)[randIndex])
    trainMat = []; trainClasses = []
    for docIndex in trainingSet:#train the classifier (get probs) trainNB0
        trainMat.append(bagOfWords2VecMN(vocabList, docList[docIndex]))
        trainClasses.append(classList[docIndex])
    p0V, p1V, pSpam = trainNB0(np.array(trainMat), np.array(trainClasses))    #训练朴素贝叶斯模型
    errorCount = 0
    for docIndex in testSet:        #对测试集分类
        wordVector = bagOfWords2VecMN(vocabList, docList[docIndex])
        if classifyNB(np.array(wordVector), p0V, p1V, pSpam) != classList[docIndex]:     #如果分类错误
            errorCount += 1                #错误次数加一
            print("分类错误的测试集", docList[docIndex])
    print('错误率为: ', float(errorCount)/len(testSet))

结果展示:

 

因为函数spamTest()是输出10封随机邮件的分类错误率,所以每运行一次结果都有可能不同,有时候错误率会为0,错误率为0时说明垃圾邮件分类没有出现差错;有时候则不为0,当错误率不为0时,结果会输出分类错误的测试集 ,这样就可以了解到底是哪篇文档发生了错误。

注:该博客所有代码都是基于《机器学习实战》

你可能感兴趣的:(概率论,机器学习)