首页 > 其他分享 >【机器学习】朴素贝叶斯分类器

【机器学习】朴素贝叶斯分类器

时间:2024-06-06 11:12:06浏览次数:26  
标签:... frac spam num 贝叶斯 分类器 垃圾邮件 model 朴素

目录

源代码文件请点击此处

条件概率的定义和公式

  • 条件概率:事件 \(B\) 已发生条件下事件 \(A\) 发生的概率,记为 \(P(A|B)\),即

\[P(A|B) = \frac{P(AB)}{P(B)} \]

  • 乘法定理:

\[P(AB) = P(A) P(B|A) \]

  • 全概率公式:

\[\begin{aligned} P(B) &= P(A_1)P(B|A_1) + P(A_2)P(B|A_2) + ... + P(A_n)P(B|A_n) \\ &= \sum_{i=1}^{n} P(A_i)P(B|A_i) \end{aligned} \]

  • 贝叶斯(Bayes)公式(逆概率公式):

\[\begin{aligned} P(A_i|B) &= \frac{P(A_iB)}{P(B)} \\ &= \frac{P(A_i)P(B|A_i)}{P(A_1)P(B|A_1) + P(A_2)P(B|A_2) + ... + P(A_n)P(B|A_n)} \\ &= \frac{P(A_i)P(B|A_i)}{\sum_{i=1}^{n} P(A_i)P(B|A_i)} \end{aligned} \]

  • 独立概率的乘法规则:事件 \(A\) 和事件 \(B\) 必须相互独立,即一个事件的发生不会影响另一个事件的发生,此时有

\[P(AB) = P(A) P(B) \\ P(A|B) = P(A|\overline{B}) = P(A) \\ P(B|A) = P(B|\overline{A}) = P(B) \]

  • 一些小技巧:
    • \(P(A) = P(A|B) + P(A|\overline{B})\)
    • \(P(AB|C) = P(A|C) P(B|C)\)

先验概率和后验概率

定义:

  • 先验概率:开始时,我们手中没有任何信息,只能计算一个初始概率。
  • 事件:新的事件发生,有了新的信息。
  • 后验概率:根据这些新信息和先验概率可以得到更好的概率估计。

例如,我们想得知今天下雨的概率:

  • 先验概率:开始时,我们手中没有任何信息,只能粗略估计今天下雨的概率为 20%。
  • 事件:我们在亚马逊雨林中。
  • 后验概率:因此,今天下雨的概率被修正为 70%。

让我们再看以下例子。

【例】某种诊断癌症的试验具有如下效果:被诊断者有癌症,试验反应为阳性的概率为0.95;被诊断者没有癌症,试验反应为阴性的概率为 0.95。现对自然人群进行普查,设被试验的人群中患有癌症的概率为0.005,求:已知试验反应为阳性,该被诊断者确有癌症的概率。

【解】概率树如下:

graph LR A[所有患者] --0.005--> B[患有癌症] A[所有患者] --0.995--> C[没有癌症] B[患有癌症] --0.95--> D[试验反应为阳性] B[患有癌症] --0.05--> E[试验反应为阴性] C[没有癌症] --0.05--> F[试验反应为阳性] C[没有癌症] --0.95--> G[试验反应为阴性]

设 \(A\) 表示“患有癌症”,\(\overline{A}\) 表示“患有癌症”;\(B\) 表示“试验反应为阳性”,\(\overline{B}\) 表示“试验反应为阴性”。由题意得

\[P(A) =0.005, P(\overline{A}) = 0.995 \\ P(B|A) = 0.95, P(\overline{B}|\overline{A}) = 0.05 \\ P(B|\overline{A}) = 1 - P(\overline{B}|\overline{A}) = 0.95 \]

由贝叶斯公式得:

\[\begin{aligned} P(A|B) &= \frac{P(AB)}{P(B)} \\ &= \frac{P(A)P(B|A)}{P(A)P(B|A) + P(\overline{A})P(B|\overline{A})} \\ &= 0.087 \end{aligned} \]

通过以上例子可知:

  • 先验概率:根据对自然人群的普查,被试验的人群中患有癌症的概率为0.005(同样,没有癌症的概率为0.995)。
  • 事件:患者接受了试验,且结果为阳性。
  • 后验概率:在得到试验反应为阳性后,该被诊断者确有癌症的概率被修正为 0.087。

使用朴素贝叶斯(Naive Bayes)算法检测垃圾邮件

设电子邮件有 \(n\) 个单词 \(x_1, x_2, ..., x_n\),则邮件是垃圾邮件的概率为:

\[P(垃圾邮件 | x_1, x_2, ..., x_n) = \frac{P(x_1, x_2, ..., x_n | 垃圾邮件) P(垃圾邮件)}{P(x_1, x_2, ..., x_n | 垃圾邮件) P(垃圾邮件) + P(x_1, x_2, ..., x_n | 非垃圾邮件) P(非垃圾邮件)} \]

假设所有单词的出现都是独立的,则有:

\[P(x_1, x_2, ..., x_n | 垃圾邮件) = P(x_1 | 垃圾邮件) P(x_2 | 垃圾邮件) ... P(x_n | 垃圾邮件) = \prod_i^n P(x_i | 垃圾邮件) \\ P(x_1, x_2, ..., x_n | 非垃圾邮件) = P(x_1 | 非垃圾邮件) P(x_2 | 非垃圾邮件) ... P(x_n | 非垃圾邮件) = \prod_i^n P(x_i | 非垃圾邮件) \]

根据条件概率公式有:

\[P(x_i | 垃圾邮件) = \frac{P(出现 x_i 的垃圾邮件)}{P(垃圾邮件)} = \frac{出现 x_i 的垃圾邮件数}{电子邮件总数} \cdot \frac{电子邮件总数}{垃圾邮件总数} = \frac{出现 x_i 的垃圾邮件数}{垃圾邮件总数} \\ 同理,P(x_i | 非垃圾邮件) = \frac{出现 x_i 的非垃圾邮件数}{非垃圾邮件总数} \\ \]

所以:

\[P(垃圾邮件 | x_1, x_2, ..., x_n) = \frac{\frac{垃圾邮件总数}{电子邮件总数} \cdot \prod_i^n \frac{出现 x_i 的垃圾邮件数}{垃圾邮件总数} }{\frac{垃圾邮件总数}{电子邮件总数} \cdot \prod_i^n \frac{出现 x_i 的垃圾邮件数}{垃圾邮件总数} + \frac{垃圾邮件总数}{电子邮件总数} \cdot \prod_i^n \frac{出现 x_i 的非垃圾邮件数}{非垃圾邮件总数}} \]

化简得:

\[P(垃圾邮件 | x_1, x_2, ..., x_n) = \frac{垃圾邮件总数 \cdot \prod_i^n \frac{出现 x_i 的垃圾邮件数}{垃圾邮件总数} }{垃圾邮件总数 \cdot \prod_i^n \frac{出现 x_i 的垃圾邮件数}{垃圾邮件总数} + 非垃圾邮件总数 \cdot \prod_i^n \frac{出现 x_i 的非垃圾邮件数}{非垃圾邮件总数}} \]

代码如下:

import pandas as pd
import numpy as np
import pickle
import os

pkl_dir = os.path.dirname(os.path.abspath(__file__))
pkl_file = 'emails_words_count.pkl'

'''
该函数用于将邮件中所有单词变为小写,并将出现过的单词转换为列表
输出如下所示:左边为邮件文本,右边为出现过的单词的列表
 text  ...                                              words
0  Subject: naturally irresistible your corporate...  ...  [love, are, 100, even, isguite, %, to, and, yo...
1  Subject: the stock trading gunslinger  fanny i...  ...  [group, penultimate, tanzania, bedtime, edt, s...
2  Subject: unbelievable new homes made easy  im ...  ...  [complete, loan, rate, this, subject:, 3, adva...
'''
def process_email(text):
    text = text.lower()
    return list(set(text.split()))


'''
【建立模型】记录每个单词分别在垃圾邮件和非垃圾邮件中的出现次数
输入:
  - emails:电子邮件数据集
输出:
  - model:二维数组,大小为 (每个邮件的不重复单词个数, 2)
    - [word]['spam']:记录该单词出现在垃圾邮件中的个数
    - [word]['ham']:记录该单词出现在非垃圾邮件中的个数
'''
def words_count(emails):
    pkl_path = pkl_dir + '/' + pkl_file
    if os.path.exists(pkl_path):
        with open(pkl_path, 'rb') as f:
            model = pickle.load(f)
        return model

    model = {} # 该字典记录了每个单词分别在垃圾邮件和非垃圾邮件中的出现次数

    for index, email in emails.iterrows(): # 遍历所有的邮件
        for word in email['words']: # 检测该邮件中的每一个单词
            if word not in model:  # 如果字典中没有这个单词
                model[word] = {'spam': 1, 'ham': 1}  # 初始化为 1,防止后面计算概率时除数为零
            else:                  # 如果字典中已有这个单词
                if email['spam'] == 1:  # 如果该邮件是垃圾邮件
                    model[word]['spam'] += 1
                else:               # 如果该邮件是非垃圾邮件
                    model[word]['ham'] += 1

    with open(pkl_path, 'wb') as f:
        pickle.dump(model, f)

    return model


'''
【推理预测】预测指定邮件是否为垃圾邮件
输入:
  - email:待预测的电子邮件文本
  - model:
  - num_spam:数据集中垃圾邮件的总数
  - num_ham:数据集中非垃圾邮件的总数
'''
def predict_naive_bayes(email, model, num_spam, num_ham):
    email = email.lower() # 待预测邮件文本全部小写化
    words = set(email.split()) # 生成单词列表

    # 计算邮件的总数
    # total = num_ham + num_spam

    # 计算概率
    spams, hams = [1.0], [1.0]
    for word in words:
        if word in model:
            spams.append(model[word]['spam'] / num_spam)
            hams.append(model[word]['ham'] / num_ham)
        # np.prod():计算数组中所有元素的乘积
        prod_spams = np.prod(spams) * num_spam
        prod_hams = np.prod(hams) * num_ham

    return prod_spams / (prod_hams + prod_spams)

# ============================= 主程序 main ===================================
if __name__ == '__main__':
    emails = pd.read_csv('emails.csv')
    emails['words'] = emails['text'].apply(process_email)

    num_emails = len(emails)
    num_spam = sum(emails['spam'])
    num_ham = num_emails - num_spam

    print("邮件总数:", num_emails)
    print("垃圾邮件数:", num_spam)
    print("邮件是垃圾邮件的先验概率:", num_spam / num_emails) # 计算先验概率
    print()

    # 记录每个单词分别在垃圾邮件和非垃圾邮件中的出现次数
    model = words_count(emails)

    # 出现单词 lottery 的邮件是垃圾邮件的概率?
    sum = model['lottery']['spam'] + model['lottery']['ham']
    print("单词 lottery 出现在邮件的次数:", model['lottery'])
    print("出现单词 lottery 的邮件是垃圾邮件的概率:", model['lottery']['spam'] / sum)

    # 出现单词 sale 的邮件是垃圾邮件的概率?
    sum = model['sale']['spam'] + model['sale']['ham']
    print("单词 sale 出现在邮件的次数:", model['sale'])
    print("出现单词 sale 的邮件是垃圾邮件的概率:", model['sale']['spam'] / sum)

    email1 = "Hi mom how are you"
    email2 = "buy cheap lottery easy money now"
    email3 = "meet me at the lobby of the hotel at nine am"
    email4 = "asdfgh"  # 不包含字典中任何一个单词,其为垃圾邮件的概率等于先验概率
    email5 = "As the sun rose, I packed my bags with essentials like a camera, a water bottle, and a few snacks. Excited and ready for the adventure, I hopped into my car and set the GPS to Laojun Mountain. The drive was a pleasant one, with lush green fields and rolling hills passing by the window."

    result = predict_naive_bayes(email5, model, num_spam, num_ham)
    print(result)

标签:...,frac,spam,num,贝叶斯,分类器,垃圾邮件,model,朴素
From: https://www.cnblogs.com/Mount256/p/18234739

相关文章

  • 一切模型皆可联邦化:高斯朴素贝叶斯代码示例
    联邦学习是一种分布式的机器学习方法,其中多个客户端在一个中央服务器的协调下合作训练模型,但不共享他们的本地数据。一般情况下我们对联邦学习的理解都是大模型和深度学习模型才可以进行联邦学习,其实基本上只要包含参数的机器学习方法都可以使用联邦学习的方法保证数据隐私。所以......
  • matlab贝叶斯隐马尔可夫hmm模型实现|附代码数据
    原文链接:http://tecdat.cn/?p=7973原文出处:拓端数据部落公众号  最近我们被客户要求撰写关于贝叶斯隐马尔可夫hmm的研究报告,包括一些图形和统计输出。贝叶斯隐马尔可夫模型是一种用于分割连续多变量数据的概率模型。该模型将数据解释为一系列隐藏状态生成。每个状态都是重尾......
  • matlab贝叶斯隐马尔可夫hmm模型实现|附代码数据
    原文链接:http://tecdat.cn/?p=7973原文出处:拓端数据部落公众号  最近我们被客户要求撰写关于贝叶斯隐马尔可夫hmm的研究报告,包括一些图形和统计输出。贝叶斯隐马尔可夫模型是一种用于分割连续多变量数据的概率模型。该模型将数据解释为一系列隐藏状态生成。每个状态都是重尾......
  • 【高斯噪声图像去噪】基于贝叶斯多尺度方法对三维图像进行去噪研究(Matlab代码实现)
    ......
  • 《庆余年算法番外篇》:范闲通过贝叶斯推理找到太子火烧史家镇的证据
    剧情背景在《庆余年2》中史家镇是李云睿和二皇子向北齐走私的重要通道,太子派人把史家镇烧成灰烬,最后嫁祸于二皇子,加大范闲对二皇子的恨意,坐收渔翁之利,意图销毁所有证据。范闲接到任务,需要在被毁的镇子里找到蛛丝马迹,通过贝叶斯推理分析这些线索,找出太子犯罪的确凿证据。......
  • 算法课程笔记——素数朴素判定&埃氏筛法
    算法课程笔记——素数朴素判定&埃氏筛法sqrt返回浮点数,而且这样可防溢出优化i*i会更快......
  • 数据分享|R语言逻辑回归、Naive Bayes贝叶斯、决策树、随机森林算法预测心脏病|附代码
    全文链接:http://tecdat.cn/?p=23061最近我们被客户要求撰写关于预测心脏病的研究报告,包括一些图形和统计输出。这个数据集可以追溯到1988年,由四个数据库组成。克利夫兰、匈牙利、瑞士和长滩。"目标"字段是指病人是否有心脏病。它的数值为整数,0=无病,1=有病数据集信息:目标:主......
  • R语言航班延误影响预测分析:lasso、决策树、朴素贝叶斯、QDA、LDA、缺失值处理、k折交
    全文链接:http://tecdat.cn/?p=32760原文出处:拓端数据部落公众号航班延误是航空公司、旅客和机场管理方面都面临的一个重要问题。航班延误不仅会给旅客带来不便,还会对航空公司和机场的运营产生负面影响。因此,对航班延误的影响因素进行预测分析,对于航空公司、旅客和机场管理方面都......
  • 贝叶斯推断架构实现
    贝叶斯推断基础贝叶斯方法提出了一个概率框架来描述如何将新的观察结果整合到决策过程中。传统的贝叶斯推断的二进制算术结构中,后验概率的计算需要大量的乘、除、加。先验概率(由历史求因):根据以往经验和分析得到的概率,观测数据前某一不确定量的先验概率分布,通常指模型的参数\(\th......
  • 机器学习之朴素贝叶斯
    朴素贝叶斯是一种基于贝叶斯定理的分类算法,常用于解决文本分类和垃圾邮件过滤等问题。它的"朴素"体现在对每个特征之间的条件独立性的假设,即假设给定目标值的情况下,每个特征都是相互独立的。尽管这个假设在实际问题中并不总是成立,但朴素贝叶斯的简单性和高效性使其在实践中仍然表......