机器学习——朴素贝叶斯分类

本文介绍了朴素贝叶斯分类的基本原理,包括贝叶斯定理、先验后验概率以及生成式和判别式模型的区别。重点展示了朴素贝叶斯分类器在垃圾邮件分类中的应用,包括训练模型、特征选择(如TF-IDF)以及评估指标。同时,文章强调了朴素贝叶斯算法的简单性、高效性和可扩展性,但提到了过拟合和泛化能力的改进需求。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

        贝叶斯分类是一类分类算法的总称,这类算法均以贝叶斯定理为基础,故统称为贝叶斯分类。朴素朴素贝叶斯分类是贝叶斯分类中最简单,也是常见的一种分类方法

 一、朴素贝叶斯
1. 贝叶斯定理

        贝叶斯理论是以18世纪的一位神学家托马斯.贝叶斯(Thomas Bayes)命名。通常,事件A在事件B(发生)的条件下的概率,与事件B在事件A(发生)的条件下的概率是不一样的。然而,这两者是有确定的关系的,贝叶斯定理就是这种关系的陈述。

其核心算法

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

  • 先验概率

        先验概率是在考虑任何新证据之前,基于先前的经验、知识或信息而获得的概率。这是在收集新数据或进行实证研究之前,对某个事件或假设的初始信仰或估计。先验概率通常基于以往的观察、领域专业知识或其他可用信息。

        例如,考虑一个掷硬币的例子。如果我们没有任何信息,我们可能会将正面和反面的概率都估计为0.5,这是一个无偏见的先验概率。但如果我们知道硬币是公正的,我们的先验概率可能会更强烈地偏向0.5。

  • 后验概率

        后验概率是在考虑了新的证据或数据之后,基于先前的先验概率经过更新得到的概率。在贝叶斯统计学中,后验概率是通过使用贝叶斯定理来结合先验概率和新的证据(数据)而得到的。

2.生成式模型

        生成式模型的目标是对整个数据分布进行建模,即学习如何生成数据。它关注的是数据的生成过程,以及给定一些条件,如何生成样本数据。生成式模型试图从训练数据中学习数据的潜在分布。

特点:

  • 能够生成新的样本,因为它们学习了数据的生成过程。
  • 在处理缺失数据或生成新样本时有优势。
  • 在某些情况下,生成式模型对噪声和变化的鲁棒性较好。
3. 判别式模型

        判别式模型关注的是对不同类别之间的决策边界进行建模,即学习类别之间的差异。它们通过学习输入数据与相应类别之间的映射关系,来做出对新样本的分类决策。 

特点:

  • 专注于学习类别之间的差异,因此在分类任务上通常表现较好。
  • 通常对噪声和变化的鲁棒性相对较差。
  • 不能生成新的样本,因为它们并未学习数据的生成过程。
4.朴素贝叶斯分类器

        在分类问题中,我们考虑一个样本属于某一类别的概率。假设有一个样本X,有特征 (X = (x_1, x_2, \ldots, x_n)),而类别标签为C。朴素贝叶斯分类器的任务是计算给定特征的条件下属于类别C的概率,即 (P(C|X))。

其公式可重写为

        P(c|x) = \frac{P(x|c) \times P(c)}{P(x)}

        朴素贝叶斯算法假设所有特征在给定类别的条件下是相互独立的。这被称为朴素贝叶斯的"朴素"之处,因为在实际问题中,很少有特征是完全独立的。这一假设简化了概率计算,但也是朴素贝叶斯算法的一个局限。

5.MAP分类准则

        MAP(最大后验概率)分类准则是一种用于分类问题的方法,它基于贝叶斯理论和条件概率来进行决策。MAP分类准则旨在选择具有最大后验概率的类别作为最终的分类结果。

二、垃圾邮件分类
1.训练朴素贝叶斯分类器的模型
  • ham_countspam_count分别用于统计正常邮件和垃圾邮件的词汇总数。
  • ham_word_countspam_word_count是用于记录每个词汇在正常邮件和垃圾邮件中出现的次数的字典,使用defaultdict初始化,确保不存在的词汇有默认值为
  • 通过循环遍历正常邮件文件夹中的每封邮件。
  • 使用codecs.open打开文件,读取邮件内容。
  • 将邮件内容按空格分割成单词,然后遍历每个单词,更新ham_word_count中该单词的出现次数,并增加ham_count的计数。
def train():
    ham_count = 0
    spam_count = 0
    ham_word_count = defaultdict(int)
    spam_word_count = defaultdict(int)

    # 遍历正常邮件文件夹,统计词汇频率
    for i in range(1, 26):
        file_path = os.path.join(ham_folder, str(i) + '.txt')
        with codecs.open(file_path, 'r', encoding='gbk') as f:
            email_content = f.read()
            words = email_content.split()
            for word in words:
                ham_word_count[word] += 1
                ham_count += 1

    # 遍历垃圾邮件文件夹,统计词汇频率
    for i in range(1, 26):
        file_path = os.path.join(spam_folder, str(i) + '.txt')
        with codecs.open(file_path, 'r', encoding='gbk') as f:
            email_content = f.read()
            words = email_content.split()
            for word in words:
                spam_word_count[word] += 1
                spam_count += 1

    # 计算每个词汇在正常邮件和垃圾邮件中出现的概率
    ham_prob = {}
    spam_prob = {}
    for word in ham_word_count:
        ham_prob[word] = ham_word_count[word] / ham_count
    for word in spam_word_count:
        spam_prob[word] = spam_word_count[word] / spam_count

    # 计算正常邮件和垃圾邮件的先验概率
    total_count = ham_count + spam_count
    ham_prior_prob = ham_count / total_count
    spam_prior_prob = spam_count / total_count

    return ham_prob, spam_prob, ham_prior_prob, spam_prior_prob
2.进行邮件分类
  • classify 函数接收一封邮件的内容 email_content 以及之前计算得到的概率和先验概率作为参数。
  • 将邮件内容按空格分割成单词存储在 words 列表中。
  • ham_score 和 spam_score 分别初始化为先验概率 ham_prior_prob 和 spam_prior_prob
  • 通过循环遍历邮件中的每个单词,在 ham_prob 和 spam_prob 中查找对应单词的概率,并乘到 ham_score 和 spam_score 上。
  • 最后根据得分比较判断邮件分类为 "正常邮件" 或 "垃圾邮件
  • classify_emails 函数遍历了所有的邮件文件,分别从正常邮件和垃圾邮件文件夹中读取每一封邮件。
  • 对每一封邮件,它调用 classify 函数进行分类,并打印出该邮件的分类结果。这里通过文件路径读取邮件内容,然后调用 classify 函数来确定邮件的分类结果。
# 进行分类操作
def classify(email_content, ham_prob, spam_prob, ham_prior_prob, spam_prior_prob):
    words = email_content.split()
    ham_score = ham_prior_prob
    spam_score = spam_prior_prob

    for word in words:
        if word in ham_prob:
            ham_score *= ham_prob[word]
        if word in spam_prob:
            spam_score *= spam_prob[word]

    # 判断分类结果
    if ham_score > spam_score:
        return "正常邮件"
    else:
        return "垃圾邮件"


# 读取每封邮件进行分类
def classify_emails(ham_prob, spam_prob, ham_prior_prob, spam_prior_prob):
    for i in range(1, 26):
        file_path = os.path.join(ham_folder, str(i) + '.txt')
        with codecs.open(file_path, 'r', encoding='gbk') as f:
            email_content = f.read()
            result = classify(email_content, ham_prob, spam_prob, ham_prior_prob, spam_prior_prob)
            print(f"文件 {file_path} 分类结果: {result}")

    for i in range(1, 26):
        file_path = os.path.join(spam_folder, str(i) + '.txt')
        with codecs.open(file_path, 'r', encoding='gbk') as f:
            email_content = f.read()
            result = classify(email_content, ham_prob, spam_prob, ham_prior_prob, spam_prior_prob)
            print(f"文件 {file_path} 分类结果: {result}")
3.使用TF-IDF进行特征选择:
  • 创建了 TfidfVectorizer 对象,用于将文本数据转换为TF-IDF特征。
  • 创建了两个空列表 X 和 y,分别用于存储文本数据和相应的类别标签。
  • 通过循环读取正常邮件和垃圾邮件文件,将邮件内容添加到 X 列表,同时将相应的类别标签添加到 y 列表。
  • 使用 fit_transform 方法将文本数据转换为TF-IDF特征矩阵 X
  • 类似于正常邮件的遍历过程,这里用于统计垃圾邮件中每个单词的出现次数,同时增加spam_count的计数。
  • 通过循环遍历正常邮件和垃圾邮件的词汇频率字典,计算每个词汇在对应类别中的概率。
def train_with_feature_selection():
    # 使用TF-IDF进行特征选择
    vectorizer = TfidfVectorizer()
    X = []
    y = []

    # 读取正常邮件
    for i in range(1, 26):
        file_path = os.path.join(ham_folder, str(i) + '.txt')
        with codecs.open(file_path, 'r', encoding='gbk') as f:
            email_content = f.read()
            X.append(email_content)
            y.append(0)  # 0 表示正常邮件

    # 读取垃圾邮件
    for i in range(1, 26):
        file_path = os.path.join(spam_folder, str(i) + '.txt')
        with codecs.open(file_path, 'r', encoding='gbk') as f:
            email_content = f.read()
            X.append(email_content)
            y.append(1)  # 1 表示垃圾邮件

    X = vectorizer.fit_transform(X)
 4.运行结果

5. 完整代码
import os
import codecs
from collections import defaultdict
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.naive_bayes import MultinomialNB
from sklearn.model_selection import train_test_split
from sklearn import metrics


# 定义文件路径
ham_folder = r'D:\QQ\Ch04\email\ham'
spam_folder = r'D:\QQ\Ch04\email\spam'

# 统计词汇出现频率和计算概率
def train():
    ham_count = 0
    spam_count = 0
    ham_word_count = defaultdict(int)
    spam_word_count = defaultdict(int)

    # 遍历正常邮件文件夹,统计词汇频率
    for i in range(1, 26):
        file_path = os.path.join(ham_folder, str(i) + '.txt')
        with codecs.open(file_path, 'r', encoding='gbk') as f:
            email_content = f.read()
            words = email_content.split()
            for word in words:
                ham_word_count[word] += 1
                ham_count += 1

    # 遍历垃圾邮件文件夹,统计词汇频率
    for i in range(1, 26):
        file_path = os.path.join(spam_folder, str(i) + '.txt')
        with codecs.open(file_path, 'r', encoding='gbk') as f:
            email_content = f.read()
            words = email_content.split()
            for word in words:
                spam_word_count[word] += 1
                spam_count += 1

    # 计算每个词汇在正常邮件和垃圾邮件中出现的概率
    ham_prob = {}
    spam_prob = {}
    for word in ham_word_count:
        ham_prob[word] = ham_word_count[word] / ham_count
    for word in spam_word_count:
        spam_prob[word] = spam_word_count[word] / spam_count

    # 计算正常邮件和垃圾邮件的先验概率
    total_count = ham_count + spam_count
    ham_prior_prob = ham_count / total_count
    spam_prior_prob = spam_count / total_count

    return ham_prob, spam_prob, ham_prior_prob, spam_prior_prob


# 进行分类操作
def classify(email_content, ham_prob, spam_prob, ham_prior_prob, spam_prior_prob):
    words = email_content.split()
    ham_score = ham_prior_prob
    spam_score = spam_prior_prob

    for word in words:
        if word in ham_prob:
            ham_score *= ham_prob[word]
        if word in spam_prob:
            spam_score *= spam_prob[word]

    # 判断分类结果
    if ham_score > spam_score:
        return "正常邮件"
    else:
        return "垃圾邮件"


# 读取每封邮件进行分类
def classify_emails(ham_prob, spam_prob, ham_prior_prob, spam_prior_prob):
    for i in range(1, 26):
        file_path = os.path.join(ham_folder, str(i) + '.txt')
        with codecs.open(file_path, 'r', encoding='gbk') as f:
            email_content = f.read()
            result = classify(email_content, ham_prob, spam_prob, ham_prior_prob, spam_prior_prob)
            print(f"文件 {file_path} 分类结果: {result}")

    for i in range(1, 26):
        file_path = os.path.join(spam_folder, str(i) + '.txt')
        with codecs.open(file_path, 'r', encoding='gbk') as f:
            email_content = f.read()
            result = classify(email_content, ham_prob, spam_prob, ham_prior_prob, spam_prior_prob)
            print(f"文件 {file_path} 分类结果: {result}")


# 特征选择和优化方法
def train_with_feature_selection():
    # 使用TF-IDF进行特征选择
    vectorizer = TfidfVectorizer()
    X = []
    y = []

    # 读取正常邮件
    for i in range(1, 26):
        file_path = os.path.join(ham_folder, str(i) + '.txt')
        with codecs.open(file_path, 'r', encoding='gbk') as f:
            email_content = f.read()
            X.append(email_content)
            y.append(0)  # 0 表示正常邮件

    # 读取垃圾邮件
    for i in range(1, 26):
        file_path = os.path.join(spam_folder, str(i) + '.txt')
        with codecs.open(file_path, 'r', encoding='gbk') as f:
            email_content = f.read()
            X.append(email_content)
            y.append(1)  # 1 表示垃圾邮件

    X = vectorizer.fit_transform(X)

    # 划分数据集
    X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

    # 训练朴素贝叶斯分类器
    clf = MultinomialNB()
    clf.fit(X_train, y_train)

    # 预测
    y_pred = clf.predict(X_test)

    # 输出分类结果和评估指标
    print("分类精度:", metrics.accuracy_score(y_test, y_pred))
    print("精确率:", metrics.precision_score(y_test, y_pred))
    print("召回率:", metrics.recall_score(y_test, y_pred))
    print("F1 分数:", metrics.f1_score(y_test, y_pred))


# 主函数
def main():
    train_with_feature_selection()


if __name__ == '__main__':
    main()
 三、小结

        可以看出,朴素贝叶斯分类器在垃圾邮件过滤方面表现出色,可以有效地将垃圾邮件与正常邮件区分开。尽管取得了较好的实验结果,但需要关注模型是否过拟合。考虑采取措施提高模型的泛化能力。朴素贝叶斯分类算法是一种简单而有效的机器学习算法,在许多实际应用中都表现良好。其优点:

  • 简单有效:朴素贝叶斯算法易于实现和理解,适用于处理大型数据集。
  • 高效性:由于特征条件独立假设,朴素贝叶斯分类器可以在相对短的时间内进行训练和预测。
  • 可扩展性:适用于大规模的多类别分类问题,对于文本分类等任务尤其有效。
  • 对小规模数据表现良好:即使在小规模数据集上,朴素贝叶斯分类器通常也能取得不错的表现。

        总体而言,朴素贝叶斯分类器在垃圾邮件分类任务上展现出了良好的性能,但实验结果的稳健性和泛化能力仍是需要进一步研究和改进的方向。 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值