楼主: creamapple
55 0

[学科前沿] 机器学习:基于朴素贝叶斯的西瓜分类实践 [推广有奖]

  • 0关注
  • 0粉丝

准贵宾(月)

小学生

14%

还不是VIP/贵宾

-

威望
0
论坛币
998 个
通用积分
0.0253
学术水平
0 点
热心指数
0 点
信用等级
0 点
经验
40 点
帖子
3
精华
0
在线时间
0 小时
注册时间
2018-10-17
最后登录
2018-10-17

楼主
creamapple 发表于 2025-12-12 11:29:37 |AI写论文

+2 论坛币
k人 参与回答

经管之家送您一份

应届毕业生专属福利!

求职就业群
赵安豆老师微信:zhaoandou666

经管之家联合CDA

送您一个全额奖学金名额~ !

感谢您参与论坛问题回答

经管之家送您两个论坛币!

+2 论坛币
作为机器学习初学阶段的重要算法之一,朴素贝叶斯分类器凭借其清晰的理论基础和高效的运算能力,广泛应用于各类分类任务中。本实验以经典的西瓜数据集为基础,构建并实现一个朴素贝叶斯分类模型,完成对“好瓜”与“坏瓜”的预测任务,从而深入掌握贝叶斯定理及特征条件独立假设的实际应用。

一、实验原理说明

1. 基本思想

该分类器的核心依据是贝叶斯定理,通过计算每个类别的后验概率,并选择概率最大的类别作为最终预测结果。所谓“朴素”,即假设所有特征之间相互独立,这一简化显著降低了联合概率的计算难度,使得模型在有限样本下仍能高效运行。

2. 关键公式表达

贝叶斯定理用于计算后验概率: 为了进行分类决策,采用后验概率最大化原则: 针对离散特征可能出现的概率为零问题,引入拉普拉斯平滑处理: 对于连续型特征(如密度、含糖率),使用高斯分布建模其概率密度函数:

3. 数据集描述

实验所用西瓜数据集共包含17个训练样本,每个样本具有8个属性特征:其中6个为离散变量——色泽、根蒂、敲声、纹理、脐部、触感;2个为连续变量——密度和含糖率。分类标签为“好瓜”或“坏瓜”。测试样本选取自训练集中第一个标记为“好瓜”的实例,用以验证模型的准确性。

二、代码实现过程

1. 数据预处理

首先整理原始训练数据与测试样本,明确各特征的数据类型及其取值范围,同时标注目标类别:
import numpy as np?
from collections import defaultdict?
    ("浅白", "蜷缩", "浊响", "清晰", "凹陷", "硬滑", 0.556, 0.215, "是"),?
    ("青绿", "稍蜷", "浊响", "清晰", "稍凹", "软粘", 0.403, 0.237, "是"),?
    ("乌黑", "稍蜷", "浊响", "稍糊", "稍凹", "软粘", 0.481, 0.149, "是"),?
    ("乌黑", "稍蜷", "浊响", "清晰", "稍凹", "硬滑", 0.437, 0.211, "是"),?
    # 坏瓜(否)?
    ("乌黑", "稍蜷", "沉闷", "稍糊", "稍凹", "硬滑", 0.666, 0.091, "否"),?
    ("青绿", "硬挺", "清脆", "清晰", "平坦", "软粘", 0.243, 0.267, "否"),?
    ("浅白", "硬挺", "清脆", "模糊", "平坦", "硬滑", 0.245, 0.057, "否"),?
    ("浅白", "蜷缩", "浊响", "模糊", "平坦", "软粘", 0.343, 0.099, "否"),?
    ("青绿", "稍蜷", "浊响", "稍糊", "凹陷", "硬滑", 0.639, 0.161, "否"),?
    ("浅白", "稍蜷", "沉闷", "稍糊", "凹陷", "硬滑", 0.657, 0.198, "否"),?
    ("乌黑", "稍蜷", "浊响", "清晰", "稍凹", "软粘", 0.360, 0.370, "否"),?
    ("浅白", "蜷缩", "浊响", "模糊", "平坦", "硬滑", 0.593, 0.042, "否"),?
    ("青绿", "蜷缩", "沉闷", "稍糊", "稍凹", "硬滑", 0.719, 0.103, "否"),?
]?
?
# 测试样本?
test_sample = ("青绿", "蜷缩", "浊响", "清晰", "凹陷", "硬滑", 0.697, 0.460)

2. 分类器结构设计

采用面向对象编程方式封装朴素贝叶斯分类器,包含训练模块、概率估计模块以及预测功能模块:
class NaiveBayesClassifier:
    def __init__(self, alpha=1):
        self.alpha = alpha  # 拉普拉斯平滑系数
        self.class_count = defaultdict(int)  # 类别计数
        self.discrete_feat_stats = defaultdict(lambda: defaultdict(lambda: defaultdict(int)))  # 离散特征统计
        self.continuous_feat_stats = defaultdict(lambda: defaultdict(dict))  # 连续特征统计(均值、方差)
        self.discrete_feat_names = ["色泽", "根蒂", "敲声", "纹理", "脐部", "触感"]
        self.continuous_feat_names = ["密度", "含糖率"]
        self.total_samples = 0

    def fit(self, data):
        """训练模型,统计各类别和特征的概率分布"""
        self.total_samples = len(data)
        for sample in data:
            label = sample[-1]
            self.class_count[label] += 1
            # 统计离散特征(前6个)
            for i in range(6):
                feat_val = sample[i]
                self.discrete_feat_stats[label][self.discrete_feat_names[i]][feat_val] += 1
            # 收集并计算连续特征的均值和方差
            density_data = [s[6] for s in data if s[-1] == label]
            sugar_data = [s[7] for s in data if s[-1] == label]
            self.continuous_feat_stats[label]["密度"] = {
                "mean": np.mean(density_data),
                "var": np.var(density_data) if np.var(density_data) != 0 else 1e-6
            }
            self.continuous_feat_stats[label]["含糖率"] = {
                "mean": np.mean(sugar_data),
                "var": np.var(sugar_data) if np.var(sugar_data) != 0 else 1e-6
            }

    def _laplace_smooth(self, label, feat_name, feat_val):
        """拉普拉斯平滑计算离散特征的条件概率 P(feat=val | label)"""
        count = self.discrete_feat_stats[label][feat_name].get(feat_val, 0)
        class_total = self.class_count[label]
        feat_vals = set([s[self.discrete_feat_names.index(feat_name)] for s in train_data])
        feat_size = len(feat_vals)
        return (count + self.alpha) / (class_total + self.alpha * feat_size)

    def _gaussian_prob(self, label, feat_name, feat_val):
        """高斯分布计算连续特征的条件概率 P(feat=val | label)"""
        stats = self.continuous_feat_stats[label][feat_name]
        mean, var = stats["mean"], stats["var"]
        exponent = np.exp(-(feat_val - mean) ** 2 / (2 * var))
        return (1 / np.sqrt(2 * np.pi * var)) * exponent

    def predict(self, sample):
        """预测样本类别,返回结果和概率详情"""
        posteriors = {}
        prob_details = {}  # 存储各特征的条件概率详情

        for label in self.class_count.keys():
            # 先验概率 P(label)
            prior = self.class_count[label] / self.total_samples
            prob_details[label] = {"先验概率": prior}
            current_prob = prior

            # 离散特征条件概率(累乘)
            for i in range(6):
                feat_name = self.discrete_feat_names[i]
                feat_val = sample[i]
                cond_prob = self._laplace_smooth(label, feat_name, feat_val)
                prob_details[label][f"{feat_name}={feat_val}"] = cond_prob
                current_prob *= cond_prob

            # 连续特征条件概率(累乘)
            for i, feat_name in enumerate(self.continuous_feat_names):
                feat_val = sample[6 + i]
                cond_prob = self._gaussian_prob(label, feat_name, feat_val)
                prob_details[label][f"{feat_name}={feat_val}"] = cond_prob
                current_prob *= cond_prob

            posteriors[label] = current_prob

        # 取后验概率最大的类别
        pred_label = max(posteriors, key=posteriors.get)
        return pred_label, posteriors, prob_details

3. 模型训练与分类预测

执行训练流程,统计先验概率与各类别下的特征条件概率,并基于测试样本输入完成分类推理:
if __name__ == "__main__":
    # 初始化并训练模型
    nb = NaiveBayesClassifier(alpha=1)
    nb.fit(train_data)
    # 预测测试样本
    pred_label, posteriors, prob_details = nb.predict(test_sample)

    # 格式化输出结果
    print("=" * 60)
    print("朴素贝叶斯分类预测结果(西瓜数据集)")
    print("=" * 60)
    # 输出各类别概率详情
    for label in ["是", "否"]:
        print(f"\n【{label}(好瓜={label})】")
        for feat, prob in prob_details[label].items():
            if "先验概率" in feat:
                print(f"  {feat}: {prob:.6f}")
            else:
                print(f"  P({feat}|好瓜={label}): {prob:.6f}")
        post_prob = posteriors[label]
        print(f"  后验联合概率: {post_prob:.10f}")

    print("\n" + "=" * 60)
    print(f"最终分类结果:该样本是【{pred_label}】好瓜")
    print("=" * 60)

三、实验结果分析

1. 输出展示

模型输出如下所示:

2. 结果解读

- **先验概率分析**: 在训练集中,“好瓜”出现频率为0.470588,“坏瓜”为0.529412,表明负样本略多于正样本。 - **离散特征条件概率观察**: 对于“好瓜”类别,“纹理=清晰”的条件概率高达0.727273,“色泽=青绿”为0.363636;而在“坏瓜”中,“纹理=清晰”的概率仅为0.250000,符合现实判断逻辑——纹理越清晰越可能为优质瓜。 - **连续特征概率对比**: 当含糖率为0.46时,“好瓜”对应的条件概率为0.669114,远高于“坏瓜”的0.042478,说明该特征对分类具有较强判别力。 - **后验联合概率比较**: 测试样本下,“好瓜”的后验联合概率为0.0216587546,而“坏瓜”仅为0.0000494475,因此模型正确将其判定为“好瓜”,与预期一致。

四、完整源码

(此处省略具体代码部分)

五、总结与反思

1. 学习收获

- 深入理解了朴素贝叶斯分类器的工作机制,掌握了如何将贝叶斯定理运用于实际分类任务。 - 掌握了混合特征类型的处理方法:对离散特征应用拉普拉斯平滑防止零概率问题,对连续特征则利用高斯分布拟合其概率密度。 - 实践了面向对象的设计思路,将整个分类流程封装成类结构,提升了代码的模块化程度和可维护性。

2. 存在问题与改进方向

- 特征间完全独立的假设在现实中往往不成立,这可能限制模型性能。未来可探索更复杂的模型如贝叶斯网络,以放松此约束。 - 拉普拉斯平滑参数α默认设为1,但不同取值可能影响泛化效果,后续可通过交叉验证寻找最优参数。 - 连续特征的概率分布假设除高斯外,也可尝试其他分布形式(如均匀分布等),评估其对分类结果的影响。

3. 应用前景拓展

尽管朴素贝叶斯模型结构简单,但在文本分类、垃圾邮件过滤、情感倾向识别等领域表现优异。其优势在于训练速度快、对小样本适应性强,且无需复杂调参,是入门级机器学习实践中极具代表性的算法案例。 本次实验不仅帮助我实现了从理论到代码的转化,也让我更加体会到“简单即有效”的算法设计理念。未来将继续深入学习更多机器学习方法,进一步挖掘其背后的数学逻辑与工程实践价值。
二维码

扫码加我 拉你入群

请注明:姓名-公司-职位

以便审核进群资格,未注明则拒绝

关键词:朴素贝叶斯 机器学习 贝叶斯 collections Continuous

您需要登录后才可以回帖 登录 | 我要注册

本版微信群
jg-xs1
拉您进交流群
GMT+8, 2025-12-22 01:44