机器学习算法——朴素贝叶斯算法

一、朴素贝叶斯算法介绍

        1、朴素贝叶斯算法概述

        朴素贝叶斯算法是一种经典的概率分类算法,它基于贝叶斯定理和特征独立性假设。该算法常被用于文本分类、垃圾邮件过滤、情感分析等领域。

        朴素贝叶斯算法的核心思想是通过已知类别的训练样本集,学习出每个类别的概率分布模型,然后根据待分类样本的特征,利用贝叶斯定理计算出样本属于各个类别的后验概率,最终选择具有最大后验概率的类别作为分类结果。

        在朴素贝叶斯算法中,特征之间被假设为相互独立,这是为了简化计算。尽管这个假设在现实问题中并不总是成立,但朴素贝叶斯算法仍然表现出良好的分类效果。

        2、贝叶斯公式

        贝叶斯公式(Bayes' theorem)是概率论中的重要定理,用于计算在给定某一事件发生的条件下,另一事件发生的概率。用数学语言表达就是:支持某项属性的事件发生得愈多,则该属性成立的可能性就愈大。该公式的数学表达如下所示:

P(A|B) = \frac{P(B|A) \cdot P(A)}{P(B)}

其中:

  • ( P(A|B) ) 表示在事件 B 发生的条件下事件 A 发生的概率,称为后验概率(posterior probability)。
  • ( P(B|A) ) 表示在事件 A 发生的条件下事件 B 发生的概率,称为似然度(likelihood)。
  • ( P(A) ) 和 ( P(B) ) 分别表示事件 A 和事件 B 单独发生的概率,分别称为先验概率(prior probability)。

        先验概率:即基于统计的概率,是基于以往历史经验和分析得到的结果,不需要依赖当前发生的条件。

        后验概率:则是从条件概率而来,由因推果,是基于当下发生了事件之后计算的概率,依赖于当前发生的条件。

        条件概率:记事件A发生的概率为P(A),事件B发生的概率为P(B),则在B事件发生的前提下,A事件发生的概率即为条件概率,记为P(A|B),读作“在B条件下A的概率”。

        联合概率:表示两个事件共同发生的概率。A与B的联合概率表示为P(AB),或者P(A,B),或者P(A∩B)。

        3、朴素贝叶斯算法的原理

        朴素贝叶斯分类器是一类简单的概率分类器,在强(朴素)独立性假设的条件下运用贝叶斯公式来计算每个类别的后验概率,假设每个特征之间没有联系。

        通俗的解释:已知结果(先验概率),结果与在此结果为条件下出现的现象(条件概率)相乘的到结果和现象同时发生的联合概率。除以现象单独发生的概率,就得出在某现象发生的条件下,发生结果的概率(后验概率)

        它的原理可以简单概括如下:

  • 贝叶斯定理: 贝叶斯定理描述了在已知一些条件下计算另一条件概率的关系。对于分类问题,它表示了在观察到特征值 (x) 的情况下,某个类别 (c) 的概率,即 (P(c|x))。

  • 特征条件独立假设: 朴素贝叶斯分类器假设给定类别的情况下,各个特征之间是相互独立的,也就是说特征之间不存在关联性。这个假设使得分类器的计算变得简单,并且易于实现。

  • 分类决策规则: 根据贝叶斯定理和特征条件独立假设,可以计算样本属于每个类别的后验概率 (P(c|x)),然后选择具有最大后验概率的类别作为样本的分类结果。

  • 参数估计: 在实际应用中,需要通过训练数据集来估计先验概率 (P(c)) 和条件概率 (P(x|c))。常见的估计方法包括最大似然估计和拉普拉斯平滑等。

二、朴素贝叶斯算法实现垃圾邮件分类

        1、实现步骤

        (1)、收集数据:提供文本文件               

        (2)、准备数据:将文本文件解析成词条向量

        (3)、分析数据:检查词条确保解析的正确性

        (4)、训练算法:使用之前建立的trainNB0()函数

        (5)、测试算法:使用classifyNB(),并且构建一个新的测试函数来计算文档集的错误率

        (6)、使用算法:构建一个完整的程序对一组文档进行分类,并显示错误率

        

        2、代码实现

                准备数据

                 垃圾邮件和正常邮件都有各25个,它们都是以文本文件txt的格式存储

图2-1

图2-3

                图2-3就是一份垃圾邮件的示例

               文本切分

                拿到一份很长的数据文本之后,我们需要对其进行切分,提取到各个单词,我们可以通过下面代码的方式来实现:

mySent='This book is the best book on python or M.L. I have ever laid eyes upon.'
print(mySent.split())
import re
mySent='This book is the best book on python or M.L. I have ever laid eyes upon.'
regEX=re.compile('\\W+')
listOfTokens=regEX.split(mySent)
print(listOfTokens)
import re
mySent='This book is the best book on python or M.L. I have ever laid eyes upon.'
regEX=re.compile('\\W+')
listOfTokens=regEX.split(mySent)
print([tok for tok in listOfTokens if len(tok)>0])
print([tok.lower() for tok in listOfTokens if len(tok)>0])

                代码的运行结果如下图所示:

图2-3

                可以发现通过正则表达式来进行切分并且将字符串全部转换成小写,去掉标点符号可以很好的将一串长文本切分成各个小单词

def textParse(bigString):  
    import re
    listOfTokens = re.split(r'\W*', bigString)  
    return [tok.lower() for tok in listOfTokens if len(tok) > 2] 

textParse(bigString) 函数用于将文本进行分词处理,并转换为小写形式。

                文本文件解析

                我们不仅仅要将字符串拆分成各个单词,我们还要讲各个句子转换成向量

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

                

createVocabList(dataSet) 函数通过遍历数据集,创建一个不重复词汇的列表。

setOfWords2Vec(vocabList, inputSet) 函数将文本转换为词向量表示形式,其中向量的每个元素表示对应词汇在文本中是否出现。

                训练算法
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
    p0Num=np.ones(numWords)
    p1Num=np.ones(numWords)
    p0Denom=2.0 
    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=p1Num/p1Denom
    # p0Vect=p0Num/p0Denom
    p1Vect=np.log(p1Num/p1Denom)
    p0Vect=np.log(p0Num/p0Denom)
 
    return  p0Vect,p1Vect,pABusive

trainNB0(trainMatrix, trainCategory) 函数通过朴素贝叶斯算法计算侮辱性文字和正常言论的条件概率,并得到类别标签的先验概率。

                贝叶斯分类
#贝叶斯分类函数
def classifyNB(vec2Classify,p0Vec,p1Vec,pClass1):
    p1=sum(vec2Classify*p1Vec)+np.log(pClass1)
    p0=sum(vec2Classify*p0Vec)+np.log(1-pClass1)
    if p1>p0:
        return 1
    else:
        return 0

classifyNB(vec2Classify, p0Vec, p1Vec, pClass1) 函数根据贝叶斯分类规则,计算输入文本属于侮辱性文字和正常言论的概率,并返回分类结果。

                垃圾邮件分类器的实现
def spamTest():
    docList = []
    classList = []
    fullText = []
    for i in range(1, 26):  # 遍历25个txt文件
        wordList = textParse(open('D:/实验报告/机器学习/朴素贝叶斯/email/spam/%d.txt' % i,'r',encoding='latin1').read())  # 读取每个垃圾邮件,并字符串转换成字符串列表
        docList.append(wordList)
        fullText.append(wordList)
        classList.append(1)  # 标记垃圾邮件,1表示垃圾文件
        wordList = textParse(open('D:/实验报告/机器学习/朴素贝叶斯/email/ham/%d.txt' % i,'r',encoding='latin1').read())  # 读取每个非垃圾邮件,并字符串转换成字符串列表
        docList.append(wordList)
        fullText.append(wordList)
        classList.append(0)  # 标记正常邮件,0表示正常文件
    vocabList = createVocabList(docList)  # 创建词汇表,不重复
    trainingSet = list(range(50))
    testSet = []  # 创建存储训练集的索引值的列表和测试集的索引值的列表
    for i in range(10):  # 从50个邮件中,随机挑选出40个作为训练集,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(np.array(trainMat), np.array(trainClasses))  # 训练朴素贝叶斯模型
    errorCount = 0  # 错误分类计数
    for docIndex in testSet:  # 遍历测试集
        wordVector = setOfWords2Vec(vocabList, docList[docIndex])  # 测试集的词集模型
        if classifyNB(np.array(wordVector), p0V, p1V, pSpam) != classList[docIndex]:  # 如果分类错误
            errorCount += 1  # 错误计数加1
            # print("分类错误的测试集:",docList[docIndex])
    print('错误率:%.2f%%' % (float(errorCount) / len(testSet) * 100))

spamTest() 函数是整个垃圾邮件分类器的主要流程,它读取垃圾邮件和正常邮件数据集,并进行训练集和测试集的划分。然后利用朴素贝叶斯算法进行模型训练,并对测试集进行分类预测,最终输出分类错误率。

                实验结果

图2-4

                实验分析

当我们运行这段代码进行垃圾邮件分类实验时,会得到一个错误率的输出结果。这个错误率代表了分类器在测试集上的分类准确度,即被错误分类的邮件所占的比例。

通过观察错误率,我们可以对实验结果进行一些分析:

  • 如果错误率很低(接近0%),意味着分类器在识别垃圾邮件方面表现出色,具有较高的准确性。这是一个理想的结果,说明分类器能够有效地区分垃圾邮件和正常邮件。

  • 如果错误率较高(超过10%或更高),则意味着分类器在垃圾邮件分类方面表现较差,准确性较低。这可能是由于数据集的特点或者分类算法的选择问题导致的。需要进一步考虑改进算法、调整参数或使用更复杂的特征工程方法来提高分类器的性能。

此外,还可以对分类错误的样本进行分析,了解分类器的误判情况。例如,查看被错误分类为垃圾邮件的正常邮件,或者被错误分类为正常邮件的垃圾邮件。这可以帮助我们发现分类器的弱点,并进一步优化算法。

需要注意的是,这段代码只是一个简单的垃圾邮件分类器的示例,实际应用中可能需要更复杂的特征工程、模型选择和调优等步骤来提高分类器的性能。

        3、实验小结
  • 特征处理的重要性:对文本数据进行适当的预处理和特征提取是分类任务中的重要一环。在这个实验中,我们将文本转化为词向量表示,利用词汇出现的频率作为特征,从而实现邮件的分类。

  • 朴素贝叶斯分类器的应用:朴素贝叶斯算法是一种简单且有效的分类算法,它基于贝叶斯定理和假设特征之间相互独立。在这个实验中,我们使用朴素贝叶斯分类器来对垃圾邮件进行分类,通过计算条件概率和先验概率来得到分类结果。

  • 错误率分析的重要性:通过观察错误率,我们可以对分类器的性能进行评估。较低的错误率意味着分类器具有较高的准确性,而较高的错误率则需要进一步改进分类器。此外,还可以对分类错误的样本进行分析,从中发现分类器的弱点,并尝试改进算法或调整参数来提高分类器的性能。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阿K还阔以

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值