机器学习-朴素贝叶斯


贝叶斯公式推导

提到贝叶斯公式,首先需要从条件概率说起,因为它是基于条件概率发展而来的。那么什么是条件概率呢?
举个例子:现有A,B两个事件,A发生的概率为P(A),B发生的概率为P(B),条件概率是指A在B发生的条件下发生的概率,表示为P(A|B),因为这里只有两个事件,因此:
P ( A ∣ B ) = P ( A B ) P ( B ) P(A|B)=\frac{P(AB)}{P(B)} P(AB)=P(B)P(AB)
相反的,有:
P ( B ∣ A ) = P ( A B ) P ( A ) P(B|A)=\frac{P(AB)}{P(A)} P(BA)=P(A)P(AB)
该公式也可以推广到任意有穷多个事件。由此我们来推导贝叶斯公式,设B1,B2,……,Bn是一一组完备事件组,则对任一事件A,P(A)> 0,有
P ( B i ∣ A ) = P ( A B i ) P ( A ) = P ( B i ) P ( A ∣ B i ) ∑ P ( B i ) P ( A ∣ B i ) P(Bi|A)=\frac{P(AB_{i})}{P(A)}=\frac{P(B_{i})P(A|B_{i})}{\sum P(B_{i})P(A|B_{i})} P(BiA)=P(A)P(ABi)=P(Bi)P(ABi)P(Bi)P(ABi)

至此,我们得出了贝叶斯公式。

朴素贝叶斯的一般过程

  1. 收集数据:任何方法。
  2. 准备数据:需要数值型或者布尔型数据。
  3. 分析数据:有大量特征时,绘制特征作用性不大,此时使用直方图效果更好。
  4. 训练算法:计算不同的独立特征的条件概率。
  5. 测试算法:计算错误率
  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):  # 文档中出现的不重复词的词汇表
    vocabSet = set([])  # set数据类型
    for ducument in dataSet:
        vocabSet = vocabSet | set(ducument)  # 取并集
    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  # 返回文档向量,若输入文档内某单词存在于词汇表里,则其下表所在的值为1
    
def trainNB0(trainMatrix, trainCategory):  # 输入样本矩阵,类别标签
    numTrainDocs = len(trainMatrix)
    numWords = len(trainMatrix[0])
    pAbusive = sum(trainCategory) / float(numTrainDocs)  # 计算侮辱性文档出现的概率
    p0Num = ones(numWords)
    p1Num = ones(numWords)
    p0Denom = p1Denom = 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])
    p1Vect = log(p1Num / p1Denom)  # 侮辱性文档中出现侮辱性词汇的频率,取对数避免数值过小溢出

    p0Vect = log(p0Num / p0Denom)  # 非侮辱性文档中出现侮辱性词汇的频率

    return p0Vect, p1Vect, pAbusive

    

测试代码

def testingNB0():   # 测试文档分类
    listOPosts, listClasses = loadDataSet()
    myVocabList = createVocabList(listOPosts)
    trainMat = []
    for postinDoc in listOPosts:
        trainMat.append(setOfWords2Vec(myVocabList, postinDoc))
    p0v, p1v, pAb = trainNB0(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))

在这里插入图片描述

朴素贝叶斯过滤垃圾邮件

过滤垃圾邮件也是通文本分类一般,需要先从;文本内容中得到字符串列表,然后生成词向量。

函数实现

def textParse(bigString):  # 处理文本为小写且只包含数字和字母
    listOfTokens = re.split("\W+", bigString)
    return [tok.lower() for tok in listOfTokens if len(tok) > 2]

测试代码

def spamTest():
    docList = []
    classList = []
    fullText = []
    for i in range(1, 26):
        wordList = textParse(
            open("D://python//PyCode//machinelearninginaction//Ch04//email//spam//%d.txt" % i).read())  # 逐个读取spam里的文本文件
        docList.append(wordList)
        fullText.extend(wordList)
        classList.append(1)
        wordList = textParse(
            open("D://python//PyCode//machinelearninginaction//Ch04\email//ham//%d.txt" % i).read())  # 逐个读取ham里的文本文件
        docList.append(wordList)
        fullText.extend(wordList)
        classList.append(0)
    vocabList = createVocabList(docList)
    trainingSet = list(range(50))  # 0-49的列表
    testSet = []
    for i in range(10):
        randIndex = int(random.uniform(0, len(trainingSet)))
        testSet.append(trainingSet[randIndex])
        del (trainingSet[randIndex])
    trainMat = []
    trainClasses = []
    for docIndex in trainingSet:
        trainMat.append(setOfWords2Vec(vocabList, docList[docIndex]))
        trainClasses.append(classList[docIndex])
    p0v, p1v, pSpam = trainNB0(array(trainMat), array(trainClasses))
    errorCount = 0
    for docIndex in testSet:
        wordVector = setOfWords2Vec(vocabList, docList[docIndex])
        if classifyNB(array(wordVector), p0v, p1v, pSpam) != classList[docIndex]:
            errorCount += 1
    print("the error rate is: ", float(errorCount / len(testSet)))
    
def spamTest_times():   # 多次测试
    for i in range(10):
        spamTest()

第一个函数textParse()接受一个大字符串并将其解析为字符串列表。该函数就去掉少于两个字符的字符串,并将所有字符串转换成小写。
第二个函数spamTest()对贝叶斯垃圾邮件分类器进行自动化处理。导入spam(非垃圾邮件)和ham(垃圾邮件),并将它们解析为此列表。从50个样本中抽取10个作为测试集,剩余部分作为训练集,这个过程被称为留存交叉验证。接下来用for循环遍历训练集的内容,并用文档分类时写的setOfWords2Vec()函数来构建词条向量,将其传入trainNB0()函数中用于计算分类所需高i率。然后遍历测试集,对其中每封电子邮件进行分类。最后计算触错误的百分比。

测试结果

训练集数:10
在这里插入图片描述
训练集数:25
在这里插入图片描述
训练集数:40
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值