机器学习:用 Python 实现朴素贝叶斯分类器 西瓜品质预测实战

朴素贝叶斯是基于贝叶斯定理与特征条件独立假设的经典分类算法,因其简单高效、对小规模数据表现优异,常被用于分类场景。本文将以 “西瓜品质分类” 为例,用 Python 实现朴素贝叶斯分类器,区分 “好瓜” 与 “坏瓜”。

一、核心思路

朴素贝叶斯的核心是贝叶斯定理:P(Y∣X)=P(X)P(X∣Y)P(Y)​,其中:

  • P(Y):先验概率(如 “好瓜 = 是” 的概率);
  • P(X∣Y):条件概率(特征 X 在类别 Y 下的概率);
  • P(Y∣X):后验概率(样本 X 属于类别 Y 的概率)。

针对西瓜数据集的特点,需区分两种特征处理方式:

  1. 离散特征(色泽、根蒂、敲声等):用 “拉普拉斯平滑” 计算条件概率,避免概率为 0;
  2. 连续特征(密度、含糖率):假设服从正态分布,通过均值、标准差计算概率密度。

最终比较 “好瓜” 和 “坏瓜” 的后验概率,概率大的即为预测类别。

二、完整实现代码

import numpy as np
from scipy.stats import norm  # 用于计算正态分布的概率密度

# ---------------------- 1. 准备训练数据和测试样本 ----------------------
# 训练数据(对应表格中1-17号样本)
train_data = [
    # 色泽, 根蒂, 敲声, 纹理, 脐部, 触感, 密度, 含糖率, 好瓜(1=是,0=否)
    ["青绿", "蜷缩", "浊响", "清晰", "凹陷", "硬滑", 0.697, 0.460, 1],
    ["乌黑", "蜷缩", "沉闷", "清晰", "凹陷", "硬滑", 0.774, 0.376, 1],
    ["乌黑", "蜷缩", "浊响", "清晰", "凹陷", "硬滑", 0.634, 0.264, 1],
    ["青绿", "蜷缩", "沉闷", "清晰", "凹陷", "硬滑", 0.608, 0.318, 1],
    ["浅白", "蜷缩", "浊响", "清晰", "凹陷", "硬滑", 0.556, 0.215, 1],
    ["青绿", "稍蜷", "浊响", "清晰", "稍凹", "软粘", 0.403, 0.237, 1],
    ["乌黑", "稍蜷", "浊响", "稍糊", "稍凹", "软粘", 0.481, 0.149, 1],
    ["乌黑", "稍蜷", "浊响", "清晰", "稍凹", "硬滑", 0.437, 0.211, 1],
    ["乌黑", "稍蜷", "沉闷", "稍糊", "稍凹", "硬滑", 0.666, 0.091, 0],
    ["青绿", "硬挺", "清脆", "清晰", "平坦", "软粘", 0.243, 0.267, 0],
    ["浅白", "硬挺", "清脆", "模糊", "平坦", "硬滑", 0.245, 0.057, 0],
    ["浅白", "蜷缩", "浊响", "模糊", "平坦", "软粘", 0.343, 0.099, 0],
    ["青绿", "稍蜷", "浊响", "稍糊", "凹陷", "硬滑", 0.639, 0.161, 0],
    ["浅白", "稍蜷", "沉闷", "稍糊", "凹陷", "硬滑", 0.657, 0.198, 0],
    ["乌黑", "稍蜷", "浊响", "清晰", "稍凹", "软粘", 0.360, 0.370, 0],
    ["浅白", "蜷缩", "浊响", "模糊", "平坦", "硬滑", 0.593, 0.042, 0],
    ["青绿", "蜷缩", "沉闷", "稍糊", "稍凹", "硬滑", 0.719, 0.103, 0],
]

# 测试样本(测1)
test_sample = ["青绿", "蜷缩", "浊响", "清晰", "凹陷", "硬滑", 0.697, 0.460]


# ---------------------- 2. 分离“好瓜=是”和“好瓜=否”的样本 ----------------------
good_melons = [d for d in train_data if d[-1] == 1]  # 好瓜样本
bad_melons = [d for d in train_data if d[-1] == 0]   # 坏瓜样本

total = len(train_data)
P_good = len(good_melons) / total  # 好瓜的先验概率
P_bad = len(bad_melons) / total    # 坏瓜的先验概率


# ---------------------- 3. 计算离散特征的条件概率(拉普拉斯平滑) ----------------------
# 离散特征的索引(色泽、根蒂、敲声、纹理、脐部、触感)
discrete_features = [0, 1, 2, 3, 4, 5]
feature_names = ["色泽", "根蒂", "敲声", "纹理", "脐部", "触感"]

def calc_discrete_prob(samples, feature_idx, feature_val):
    """计算离散特征的条件概率(拉普拉斯平滑)"""
    feature_values = [d[feature_idx] for d in samples]
    count = feature_values.count(feature_val)
    # 拉普拉斯平滑:分子+1,分母+特征的可能取值数
    unique_vals = len(set(feature_values))
    return (count + 1) / (len(samples) + unique_vals)


# ---------------------- 4. 计算连续特征的正态分布参数(均值、标准差) ----------------------
def calc_normal_params(samples, feature_idx):
    """计算连续特征的均值和标准差"""
    values = [d[feature_idx] for d in samples]
    mean = np.mean(values)
    std = np.std(values, ddof=1)  # 样本标准差(ddof=1)
    return mean, std

# 好瓜的密度、含糖率的正态分布参数
good_density_mean, good_density_std = calc_normal_params(good_melons, 6)
good_sugar_mean, good_sugar_std = calc_normal_params(good_melons, 7)

# 坏瓜的密度、含糖率的正态分布参数
bad_density_mean, bad_density_std = calc_normal_params(bad_melons, 6)
bad_sugar_mean, bad_sugar_std = calc_normal_params(bad_melons, 7)


# ---------------------- 5. 计算测试样本的后验概率 ----------------------
# 计算“好瓜=是”的后验概率
P_good_given_test = P_good
for idx in discrete_features:
    val = test_sample[idx]
    P_good_given_test *= calc_discrete_prob(good_melons, idx, val)
# 乘以连续特征的概率密度
P_good_given_test *= norm.pdf(test_sample[6], good_density_mean, good_density_std)
P_good_given_test *= norm.pdf(test_sample[7], good_sugar_mean, good_sugar_std)

# 计算“好瓜=否”的后验概率
P_bad_given_test = P_bad
for idx in discrete_features:
    val = test_sample[idx]
    P_bad_given_test *= calc_discrete_prob(bad_melons, idx, val)
# 乘以连续特征的概率密度
P_bad_given_test *= norm.pdf(test_sample[6], bad_density_mean, bad_density_std)
P_bad_given_test *= norm.pdf(test_sample[7], bad_sugar_mean, bad_sugar_std)


# ---------------------- 6. 输出预测结果 ----------------------
print(f"测试样本属于好瓜的后验概率:{P_good_given_test:.6f}")
print(f"测试样本属于坏瓜的后验概率:{P_bad_given_test:.6f}")
prediction = "是" if P_good_given_test > P_bad_given_test else "否"
print(f"预测结果:该西瓜是好瓜吗?{prediction}")

三、关键步骤解析

1. 数据预处理

将西瓜数据集整理为结构化列表,分离 “好瓜” 和 “坏瓜” 样本,为后续概率计算做准备。

2. 先验概率计算

直接通过 “好瓜 / 坏瓜样本数 ÷ 总样本数” 得到先验概率,反映数据集里 “好瓜”“坏瓜” 的基础分布。

3. 离散特征处理

对色泽、根蒂等离散特征,采用拉普拉斯平滑

  • 解决 “某个特征值未出现在训练集中,导致条件概率为 0” 的问题;
  • 公式:P(X_{i}|Y)=\frac{count(X_{i},Y)+1}{count(Y)+N}(N 为特征的唯一取值数)。

4. 连续特征处理

密度、含糖率是连续值,假设其服从正态分布:

  1. 计算训练集中 “好瓜 / 坏瓜” 下该特征的均值、标准差;
  2. 用正态分布概率密度函数 f(x) = \frac{1}{\sqrt{2\pi}\sigma}e^{-\frac{(x-\mu)^2}{2\sigma^2}} 计算测试样本的概率密度。

5. 后验概率计算与预测

结合先验概率和所有特征的条件概率(离散 + 连续),得到测试样本属于 “好瓜”“坏瓜” 的后验概率,取概率更大的类别作为预测结果。

四、运行结果与分析

测试样本属于好瓜的后验概率:0.037281
测试样本属于坏瓜的后验概率:0.000078
预测结果:该西瓜是好瓜吗?是

测试样本与训练集中 “好瓜” 样本完全一致,模型正确预测为 “好瓜”,结果符合预期。

五、常见问题解决

1. 缺少 scipy 模块

代码中scipy.stats.norm用于正态分布计算,若报错No module named 'scipy',执行安装命令:

pip install scipy

2. 环境不一致问题

若已安装 scipy 仍报错,大概率是 VS Code/PyCharm 使用的 Python 解释器与安装 scipy 的环境不一致:

  • VS Code:Ctrl+Shift+P → 输入 “Python: Select Interpreter” → 选择安装了 scipy 的环境。

六、拓展与优化

  1. 批量预测:封装预测逻辑为函数,遍历多个测试样本实现批量分类;
  2. 特征扩展:增加更多西瓜特征(如大小、重量),提升模型泛化能力;
  3. 模型对比:与决策树、逻辑回归等算法对比,验证朴素贝叶斯的效果。

总结

本文通过西瓜品质分类案例,完整实现了 “离散特征 + 连续特征” 混合场景下的朴素贝叶斯分类器。核心要点是:离散特征用拉普拉斯平滑避免概率为 0,连续特征假设正态分布计算概率密度,最终通过后验概率比较完成分类。朴素贝叶斯虽简单,但在特征独立假设成立的场景下,能以极低的计算成本实现较好的分类效果,是入门机器学习分类算法的绝佳选择。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值