全部版块 我的主页
论坛 新商科论坛 四区(原工商管理论坛) 商学院 创新与战略管理
93 0
2025-12-01

朴素贝叶斯算法详解与实战

在众多机器学习分类算法中,朴素贝叶斯(Naive Bayes) 虽然名字听起来“简单”,实则是一种极具实用价值的模型。它基于概率理论构建,结构清晰、实现容易,常被用作初学者入门的经典范例。本文将深入剖析其核心原理,并结合西瓜数据集进行逐步推导与实现,帮助你彻底掌握这一经典算法。

核心优势

  • 简洁高效:逻辑直观,计算开销小,是学习分类任务的理想起点
  • 理论扎实:建立在贝叶斯定理之上,具备严谨的概率统计基础
  • 运行快速:训练和预测阶段均表现优异,适用于实时场景
  • 适应小样本:即使训练数据有限,仍能保持良好的分类性能
  • 易于实现:代码实现简明,适合快速原型开发与教学演示

典型应用场景

  • 文本分类:如垃圾邮件识别、情感倾向判断
  • 医疗辅助诊断:疾病风险评估、病情初步筛查
  • 推荐系统:用户行为偏好建模与预测
  • 基础分类问题:例如本文使用的西瓜品质判断任务

数学原理概述

朴素贝叶斯基于贝叶斯定理进行概率推理:

P(Y|X) = \frac{P(X|Y)P(Y)}{P(X)}

其中各项含义如下:

  • P(Y|X):后验概率,表示在已知特征 X 的条件下,样本属于类别 Y 的概率
  • P(X|Y):似然,即在类别 Y 中观察到特征 X 的可能性
  • P(Y):先验概率,反映类别 Y 在整体中的分布频率
  • P(X):证据因子,为特征 X 出现的总概率,通常作为归一化常数处理

该算法被称为“朴素”的原因在于其强假设——所有特征在给定类别下相互独立。这一假设使得联合概率可分解为各特征条件概率的乘积:

P(X|Y) = P(x|Y) × P(x|Y) × … × P(x|Y)

从而大大简化了高维特征下的概率计算过程。

西瓜数据集案例分析

我们采用经典的西瓜数据集(共17条记录),包含以下特征信息:

特征 类型 说明
色泽 离散 青绿 / 乌黑 / 浅白
根蒂 离散 蜷缩 / 稍蜷 / 硬挺
敲声 离散 浊响 / 沉闷 / 清脆
纹理 离散 清晰 / 稍糊 / 模糊
脐部 离散 凹陷 / 稍凹 / 平坦
触感 离散 硬滑 / 软粘
密度 连续 数值型(范围0.0~1.0)
含糖率 连续 数值型(范围0.0~1.0)
好瓜 标签 是 / 否(目标变量)

针对不同类型特征,采用不同的概率估计方法:

  • 离散特征:使用频率统计结合平滑技术
  • 连续特征:假设服从高斯分布,利用均值与方差建模

离散特征处理:多项式朴素贝叶斯

适用于离散取值的特征,尤其常见于文本分类中的词频建模。

条件概率计算公式为:

P(x|y) = (Ny + α) / (Ny + αn)

参数解释:

  • P(x|y):在类别 y 下,特征 x 出现的概率
  • Ny:类别 y 的样本中,特征 x 出现的次数
  • Ny:类别 y 所有样本中所有特征的总出现次数
  • n:特征总数
  • α:平滑参数,常用拉普拉斯平滑(α=1)避免零概率问题

连续特征处理:高斯朴素贝叶斯

假设连续型特征在每个类别下服从正态分布。

概率密度函数表达式为:

P(x|y) = \frac{1}{\sqrt{2\pi\sigma_y^2}} \exp\left(-\frac{(x_i - \mu_y)^2}{2\sigma_y^2}\right)

相关参数定义:

  • μy:类别 y 下特征 x 的均值
  • σy:类别 y 下特征 x 的标准差
  • x:待预测样本的当前特征值

参数估计方式:

  • 均值 μy = (1/Ny) × Σx(y) (j 从 1 到 Ny
  • 方差 σy = (1/Ny) × Σ(x(y) - μy) (j 从 1 到 Ny

代码实现部分

import pandas as pd
import numpy as np

以下数据集包含了西瓜的多个属性,用于判断是否为好瓜。数据中的特征分为离散型和连续型两类,分别进行处理以构建混合朴素贝叶斯模型。

原始数据结构如下:

从数据中提取出离散特征与连续特征,其中离散特征包括:色泽、根蒂、敲声、纹理、脐部、触感;连续特征包括:密度、含糖率。标签列为“好瓜”,表示该样本是否为优质西瓜。

具体特征划分如下:

  • 离散特征(分类属性):色澤、根蒂、敲声、纹理、脐部、触感
  • 连续特征(数值属性):密度、含糖率
  • 目标标签:好瓜

在建模前,确保所有离散特征列的数据类型为字符串,以便正确统计各类别的出现频率。

[此处为图片2]

构建一个支持混合特征类型的朴素贝叶斯分类器——MixedNaiveBayesWithDetail。该类初始化时定义了先验概率、离散特征的条件概率以及连续特征的高斯分布参数存储结构。

训练过程包含以下步骤:

  1. 计算每个类别(是/否)的先验概率,即该类样本占总样本的比例。
  2. 对每一个离散特征,统计其在不同类别下的条件概率。采用频次估计方法,计算某特征值在给定类别下出现的概率。
  3. 对于连续特征,假设其服从高斯分布,计算每个类别下各连续特征的均值与方差,作为后续概率密度计算的依据。

在拟合模型时,首先遍历所有类别,计算先验分布。接着针对每个离散特征列,建立嵌套字典结构,记录每种取值在各个类别中的条件概率。

[此处为图片3]

对于连续特征部分,在每个类别下分别计算“密度”和“含糖率”的均值与标准差,并保存至 continuous_params 字典中,供预测阶段使用。

整个模型基于贝叶斯公式进行联合概率建模,结合离散特征的多项式模型与连续特征的高斯模型,实现对混合类型数据的有效分类。

# 创建并训练模型
nb = MixedNaiveBayesWithDetail()
nb.fit(X_discrete, X_continuous, y)

# 测试样本:测1(即训练集第1个样本)
new_sample = {
    '色澤': '青绿',
    '根蒂': '蜷缩',
    '敲声': '浊响',
    '纹理': '清晰',
    '脐部': '凹陷',
    '触感': '硬滑',
    '密度': 0.697,
    '含糖率': 0.460
}



def _gaussian_pdf(self, x, mean, var):
    """
    计算给定均值和方差下,x处的高斯概率密度函数值。
    若方差为0,则退化为确定性情况。
    """
    if var == 0:
        return 1.0 if x == mean else 1e-10
    coeff = 1.0 / np.sqrt(2 * np.pi * var)
    exponent = -0.5 * ((x - mean) ** 2) / var
    return coeff * np.exp(exponent)

def predict_with_detail(self, X_discrete_row, X_continuous_row):
    print("=" * 60)
    print("???? 开始预测样本:")
    for col in X_discrete_row.index:
        print(f"  {col}: {X_discrete_row[col]}")
    for col in X_continuous_row.index:
        print(f"  {col}: {X_continuous_row[col]:.3f}")
    print("-" * 60)

    log_probs = {}
    probs = {}

    for c in self.priors.keys():
        prior = self.priors[c]
        log_prior = np.log(prior)
        log_prob = log_prior
        prob = prior

        print(f"\n类别: '{c}'")
        print(f"  先验概率 P({c}) = {prior:.4f} (log = {log_prior:.4f})")

        # 处理离散特征
        for col in X_discrete_row.index:
            val = X_discrete_row[col]
            if val in self.discrete_probs[col] and c in self.discrete_probs[col][val]:
                p = self.discrete_probs[col][val][c]
            else:
                p = 1e-10  # 拉普拉斯平滑或未登录项处理
            log_p = np.log(p)
            log_prob += log_p
            prob *= p
            print(f"  P({col}={val} | {c}) = {p:.4f} (log = {log_p:.4f})")

        # 处理连续特征
        for col in X_continuous_row.index:
            x = X_continuous_row[col]
            mean, var = self.continuous_params[col][c]
            p = self._gaussian_pdf(x, mean, var)
            log_p = np.log(p)
            log_prob += log_p
            prob *= p
            print(f"  P({col}={x:.3f} | {c}) = {p:.6f} (log = {log_p:.4f})")
            print(f"    → 高斯分布参数: μ={mean:.4f}, σ?={var:.4f}")

        log_probs[c] = log_prob
        probs[c] = prob
        print(f"  联合概率 P(样本|{c})P({c}) = {prob:.2e} (log = {log_prob:.4f})")

    print("\n" + "=" * 60)
    print(" 最终比较(使用对数概率避免下溢):")
    for c in log_probs:
        print(f"  log P({c} | 样本) ∝ {log_probs[c]:.4f}")

    best_class = max(log_probs, key=log_probs.get)
    print(f"\n 预测结果: '{best_class}'")
    return best_class

[此处为图片2]

data_c = X_continuous.loc[y == c, col]
mean = data_c.mean()
var = data_c.var(ddof=0)  # 使用总体方差,与教材定义保持一致
self.continuous_params[col][c] = (mean, var)

cont_input = pd.Series([new_sample[f] for f in features_continuous], index=features_continuous)
discrete_input = pd.Series([new_sample[f] for f in features_discrete], index=features_discrete)
pred = nb.predict_with_detail(discrete_input, cont_input)

运行结果如下所示:

二维码

扫码加我 拉你入群

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

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

栏目导航
热门文章
推荐文章

说点什么

分享

扫码加好友,拉您进群
各岗位、行业、专业交流群