一、朴素贝叶斯的核心思路
朴素贝叶斯的核心是贝叶斯公式 + 特征条件独立假设
由于我们只需要比较不同类别的后验概率(不需要精确值),可以忽略分母 
对于西瓜分类任务:
类别:好瓜=是 / 好瓜=否
特征:离散特征(色泽、根蒂等)+ 连续特征(密度、含糖率)

二、Python 代码实现
步骤 1:准备训练数据
先把题目中的西瓜数据集转成 Python 可处理的格式:

import numpy as np
from collections import defaultdict

# 训练数据集(对应题目中的17个样本)
train_data = [
    {"色泽": "青绿", "根蒂": "蜷缩", "敲声": "浊响", "纹理": "清晰", "脐部": "凹陷", "触感": "硬滑", "密度": 0.697, "含糖率": 0.460, "好瓜": "是"},
    {"色泽": "乌黑", "根蒂": "蜷缩", "敲声": "沉闷", "纹理": "清晰", "脐部": "凹陷", "触感": "硬滑", "密度": 0.774, "含糖率": 0.376, "好瓜": "是"},
    {"色泽": "乌黑", "根蒂": "蜷缩", "敲声": "浊响", "纹理": "清晰", "脐部": "凹陷", "触感": "硬滑", "密度": 0.634, "含糖率": 0.264, "好瓜": "是"},
    {"色泽": "青绿", "根蒂": "蜷缩", "敲声": "沉闷", "纹理": "清晰", "脐部": "凹陷", "触感": "硬滑", "密度": 0.608, "含糖率": 0.318, "好瓜": "是"},
    {"色泽": "浅白", "根蒂": "蜷缩", "敲声": "浊响", "纹理": "清晰", "脐部": "凹陷", "触感": "硬滑", "密度": 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, "好瓜": "否"}
]

# 分离好瓜和坏瓜样本
good_melons = [sample for sample in train_data if sample["好瓜"] == "是"]
bad_melons = [sample for sample in train_data if sample["好瓜"] == "否"]
total_samples = len(train_data)

步骤 2:计算先验概率
先验概率是 “好瓜”/“坏瓜” 在训练集中的占比:

# 先验概率 P(好瓜=是) 和 P(好瓜=否)
P_good = len(good_melons) / total_samples
P_bad = len(bad_melons) / total_samples

步骤 3:处理离散特征(计算类条件概率)
离散特征包括:色泽、根蒂、敲声、纹理、脐部、触感。我们统计每个类别下,特征取某值的频率(加入拉普拉斯平滑避免概率为 0)。

# 定义离散特征及所有可能取值(用于拉普拉斯平滑)
discrete_features = ["色泽", "根蒂", "敲声", "纹理", "脐部", "触感"]
feat_value_options = {
    "色泽": ["青绿", "乌黑", "浅白"],
    "根蒂": ["蜷缩", "稍蜷", "硬挺"],
    "敲声": ["浊响", "沉闷", "清脆"],
    "纹理": ["清晰", "稍糊", "模糊"],
    "脐部": ["凹陷", "稍凹", "平坦"],
    "触感": ["硬滑", "软粘"]
}

def calc_discrete_probs(melons, feat_options):
    """计算离散特征的类条件概率(带拉普拉斯平滑)"""
    probs = defaultdict(dict)
    total = len(melons)
    for feat in discrete_features:
        # 统计该特征在当前类别中的出现次数
        count = defaultdict(int)
        for melon in melons:
            count[melon[feat]] += 1
        # 拉普拉斯平滑:分子+1,分母+该特征的取值个数
        option_num = len(feat_options[feat])
        for val in feat_options[feat]:
            probs[feat][val] = (count.get(val, 0) + 1) / (total + option_num)
    return probs

# 好瓜/坏瓜的离散特征概率
good_discrete_probs = calc_discrete_probs(good_melons, feat_value_options)
bad_discrete_probs = calc_discrete_probs(bad_melons, feat_value_options)

步骤 4:处理连续特征(高斯分布假设)
连续特征(密度、含糖率)假设服从正态分布,我们先计算每个类别下连续特征的均值和方差,再用正态分布概率密度函数计算概率。

def gaussian_prob(x, mean, var):
    """计算正态分布下x的概率密度"""
    if var == 0:
        return 0  # 避免方差为0的极端情况
    exponent = np.exp(-(np.power(x - mean, 2) / (2 * var)))
    return (1 / (np.sqrt(2 * np.pi * var))) * exponent

def calc_continuous_stats(melons):
    """计算连续特征的均值和方差"""
    stats = {}
    continuous_features = ["密度", "含糖率"]
    for feat in continuous_features:
        values = [melon[feat] for melon in melons]
        stats[feat] = (np.mean(values), np.var(values, ddof=0))  # ddof=0:总体方差
    return stats

# 好瓜/坏瓜的连续特征统计量(均值、方差)
good_continuous_stats = calc_continuous_stats(good_melons)
bad_continuous_stats = calc_continuous_stats(bad_melons)

步骤 5:实现分类器
根据朴素贝叶斯公式,计算测试样本属于 “好瓜” 和 “坏瓜” 的后验概率,取较大值作为分类结果。

def classify(test_sample):
    """
    朴素贝叶斯分类函数
    参数:test_sample - 测试样本(字典)
    返回:"是"(好瓜)或 "否"(坏瓜)
    """
    # 计算“好瓜”的后验概率
    good_posterior = P_good
    # 乘离散特征的类条件概率
    for feat in discrete_features:
        val = test_sample[feat]
        good_posterior *= good_discrete_probs[feat][val]
    # 乘连续特征的概率密度
    for feat in ["密度", "含糖率"]:
        val = test_sample[feat]
        mean, var = good_continuous_stats[feat]
        good_posterior *= gaussian_prob(val, mean, var)

    # 计算“坏瓜”的后验概率
    bad_posterior = P_bad
    for feat in discrete_features:
        val = test_sample[feat]
        bad_posterior *= bad_discrete_probs[feat][val]
    for feat in ["密度", "含糖率"]:
        val = test_sample[feat]
        mean, var = bad_continuous_stats[feat]
        bad_posterior *= gaussian_prob(val, mean, var)

    # 比较后验概率,返回分类结果
    return "是" if good_posterior > bad_posterior else "否"

步骤 6:测试分类器
用题目中的 “测 1” 样本验证效果:

# 测试样本(测1)
test_sample = {
    "色泽": "青绿",
    "根蒂": "蜷缩",
    "敲声": "浊响",
    "纹理": "清晰",
    "脐部": "凹陷",
    "触感": "硬滑",
    "密度": 0.697,
    "含糖率": 0.460
}

# 分类结果
result = classify(test_sample)
print(f"测试样本的分类结果:{'好瓜' if result == '是' else '坏瓜'}")

三、总结
通过 Python 实现的朴素贝叶斯分类器,成功判断出 “测 1” 是好瓜,和理论计算结果一致。
朴素贝叶斯的优点是简单高效,适合小数据集;缺点是依赖 “特征独立” 假设(实际中特征可能相关)。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐