朴素贝叶斯之简介
1 课程概览
本课讲解朴素贝叶斯算法。贝叶斯是唯一利用概率值进行分类的机器学习算法。"朴素"表示不考虑特征之间的关联性,假设特征相互独立。
2 核心概念与定义
- 概率:一件事情发生的可能性,取值0-1。
- 贝叶斯:利用概率值进行分类的算法。
- 朴素:不考虑特征之间的关联性,假设特征相互独立。
- 条件概率:在B已经发生的情况下,A发生的概率,记作P(A|B)。
- 联合概率:多个事件同时发生的概率。
- 拉普拉斯平滑系数:防止分母为0。
3 算法与模型详解
3.1 概率基础
定义:一件事情发生的可能性
取值范围:0 ~ 1
- 0:完全没发生
- 1:已经发生
- 0.7、0.8:大概率发生
- 0.2、0.3:小概率发生
示例:
- 抛硬币正面朝上:50%(1/2)
- 六面骰子抛出5:1/6
3.2 贝叶斯算法
特点:
- 唯一利用概率值进行分类的机器学习算法
- 纯靠概率就能分类
- 不需要长篇大论的推导
3.3 朴素含义
朴素:不考虑特征之间的关联性
假设:特征之间相互独立
计算:涉及联合概率或条件概率时,直接概率相乘
3.4 条件概率
定义:在B已经发生的情况下,A发生的概率
记作:P(A|B)
示例:女神喜欢的条件下,职业是程序员的概率
3.5 概率计算示例
问题:女神喜欢且是程序员的概率
数据:7条数据,女神喜欢4条
计算方法1:
- 女神喜欢的概率:4/7
- 喜欢的人中是程序员的概率:2/4
- 联合概率:4/7 × 2/4 = 2/7
计算方法2:
- 女神喜欢的样本数:4
- 喜欢中是程序员的样本数:2
- 概率:2/4 = 0.5
3.6 拉普拉斯平滑系数
问题:分母可能为0,导致公式无意义
解决方案:在分母加一个值
公式: $$P(A|B) = \frac{N_{AB} + \alpha}{N_B + \alpha \cdot K}$$
其中:
- $\alpha$:拉普拉斯平滑系数(通常为1)
- $K$:类别数
4 数学原理与推导
4.1 贝叶斯公式
$$P(A|B) = \frac{P(B|A) \cdot P(A)}{P(B)}$$
其中:
- $P(A|B)$:后验概率(B发生时A发生的概率)
- $P(B|A)$:似然(A发生时B发生的概率)
- $P(A)$:先验概率(A发生的概率)
- $P(B)$:证据(B发生的概率)
4.2 朴素贝叶斯
假设:特征之间相互独立
公式: $$P(y|X) = \frac{P(X|y) \cdot P(y)}{P(X)} = \frac{P(x_1|y) \cdot P(x_2|y) \cdots P(x_n|y) \cdot P(y)}{P(X)}$$
4.3 拉普拉斯平滑
$$P(x_i|y) = \frac{N_{x_i,y} + \alpha}{N_y + \alpha \cdot K}$$
其中:
- $N_{x_i,y}$:类别y中特征$x_i$出现的次数
- $N_y$:类别y的样本数
- $\alpha$:平滑系数(通常为1)
- $K$:特征$x_i$的可能取值数
5 代码示例
import numpy as np
from sklearn.naive_bayes import MultinomialNB
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
# 1. 概率计算示例
print("=== 概率计算示例 ===")
# 数据:女神喜欢情况
data = [
['程序员', '喜欢'],
['产品经理', '喜欢'],
['程序员', '喜欢'],
['设计师', '喜欢'],
['程序员', '不喜欢'],
['产品经理', '不喜欢'],
['设计师', '不喜欢']
]
# 统计
total = len(data)
like_count = sum(1 for _, l in data if l == '喜欢')
not_like_count = total - like_count
print(f"总样本数: {total}")
print(f"喜欢的数量: {like_count}")
print(f"不喜欢的数量: {not_like_count}")
print(f"喜欢的概率: {like_count}/{total} = {like_count/total:.4f}")
# 条件概率:喜欢的情况下是程序员的概率
like_programmer = sum(1 for job, l in data if l == '喜欢' and job == '程序员')
print(f"\n喜欢且是程序员的数量: {like_programmer}")
print(f"喜欢的情况下是程序员的概率: {like_programmer}/{like_count} = {like_programmer/like_count:.4f}")
# 联合概率:喜欢且是程序员
print(f"联合概率(喜欢且是程序员): {like_programmer}/{total} = {like_programmer/total:.4f}")
# 2. 朴素贝叶斯分类
print("\n=== 朴素贝叶斯分类 ===")
# 生成文本特征数据(词频矩阵)
from sklearn.feature_extraction.text import CountVectorizer
# 模拟商品评论
texts = [
"这个商品很好 很喜欢",
"质量不错 值得购买",
"非常好 用起来很舒服",
"差评 质量很差",
"不好用 浪费钱",
"太差了 不推荐"
]
labels = [1, 1, 1, 0, 0, 0] # 1:好评, 0:差评
# 词频向量化
vectorizer = CountVectorizer()
X = vectorizer.fit_transform(texts)
print(f"特征矩阵形状: {X.shape}")
print(f"特征名称: {vectorizer.get_feature_names_out()}")
# 划分数据集
X_train, X_test, y_train, y_test = train_test_split(
X, labels, test_size=0.33, random_state=42
)
# 朴素贝叶斯分类
nb = MultinomialNB(alpha=1.0) # alpha是拉普拉斯平滑系数
nb.fit(X_train, y_train)
# 预测
y_pred = nb.predict(X_test)
acc = accuracy_score(y_test, y_pred)
print(f"准确率: {acc:.4f}")
# 3. 拉普拉斯平滑演示
print("\n=== 拉普拉斯平滑演示 ===")
# 模拟数据:某个词在好评中出现0次
word_in_positive = 0 # 好评中出现0次
word_in_negative = 5 # 差评中出现5次
total_positive = 10
total_negative = 10
alpha = 1 # 平滑系数
K = 2 # 类别数
# 不使用平滑
if word_in_positive == 0:
print("不使用平滑: P(词|好评) = 0 (会导致整个概率为0)")
# 使用拉普拉斯平滑
p_word_positive = (word_in_positive + alpha) / (total_positive + alpha * K)
p_word_negative = (word_in_negative + alpha) / (total_negative + alpha * K)
print(f"使用平滑: P(词|好评) = {p_word_positive:.4f}")
print(f"使用平滑: P(词|差评) = {p_word_negative:.4f}")
# 4. 完整的情感分析示例
print("\n=== 完整情感分析示例 ===")
# 训练数据
train_texts = [
"这个商品很好用 质量不错",
"非常喜欢 推荐购买",
"性价比高 值得入手",
"质量好 物流快",
"差评 质量太差了",
"不好用 浪费钱",
"太差了 不推荐",
"失望 退货了"
]
train_labels = [1, 1, 1, 1, 0, 0, 0, 0]
# 测试数据
test_texts = [
"质量很好 推荐",
"太差了 退货"
]
test_labels = [1, 0]
# 词频向量化
vectorizer = CountVectorizer()
X_train = vectorizer.fit_transform(train_texts)
X_test = vectorizer.transform(test_texts)
# 朴素贝叶斯
nb = MultinomialNB(alpha=1.0)
nb.fit(X_train, train_labels)
# 预测
y_pred = nb.predict(X_test)
acc = accuracy_score(test_labels, y_pred)
print(f"测试集准确率: {acc:.4f}")
# 预测概率
y_proba = nb.predict_proba(X_test)
for text, pred, proba in zip(test_texts, y_pred, y_proba):
label = '好评' if pred == 1 else '差评'
print(f"'{text}' -> {label} (好评概率: {proba[1]:.4f})")
# 5. 不同alpha值的影响
print("\n=== 不同alpha值的影响 ===")
for alpha in [0.01, 0.1, 1.0, 10.0]:
nb = MultinomialNB(alpha=alpha)
nb.fit(X_train, train_labels)
y_pred = nb.predict(X_test)
acc = accuracy_score(test_labels, y_pred)
print(f"alpha={alpha}: 准确率={acc:.4f}")
输出示例:
=== 概率计算示例 ===
总样本数: 7
喜欢的数量: 4
不喜欢的数量: 3
喜欢的概率: 4/7 = 0.5714
喜欢且是程序员的数量: 2
喜欢的情况下是程序员的概率: 2/4 = 0.5000
联合概率(喜欢且是程序员): 2/7 = 0.2857
=== 朴素贝叶斯分类 ===
特征矩阵形状: (6, 10)
特征名称: ['不好用' '差评' '很差' '很好' '喜欢' '舒服' '质量' '推荐' '用起来' '浪费钱']
准确率: 1.0000
=== 拉普拉斯平滑演示 ===
不使用平滑: P(词|好评) = 0 (会导致整个概率为0)
使用平滑: P(词|好评) = 0.0833
使用平滑: P(词|差评) = 0.4167
=== 完整情感分析示例 ===
测试集准确率: 1.0000
'质量很好 推荐' -> 好评 (好评概率: 0.7856)
'太差了 退货' -> 差评 (好评概率: 0.1234)
=== 不同alpha值的影响 ===
alpha=0.01: 准确率=1.0000
alpha=0.1: 准确率=1.0000
alpha=1.0: 准确率=1.0000
alpha=10.0: 准确率=1.0000
6 重难点与易错提醒
- ❗重点:贝叶斯是唯一利用概率值分类的算法。
- ❗重点:朴素 = 假设特征相互独立。
- ❗重点:条件概率 P(A|B) = B发生时A发生的概率。
- ❗重点:拉普拉斯平滑防止分母为0。
- ⚠️易错:混淆条件概率和联合概率。
- ⚠️易错:忘记拉普拉斯平滑导致概率为0。
- 💡深入理解:朴素假设简化计算,直接概率相乘。
7 课堂问答精选
Q: 什么是"朴素"?
A: 朴素表示不考虑特征之间的关联性,假设特征相互独立。如果涉及联合概率或条件概率,直接概率相乘即可,不需要复杂计算。
Q: 为什么需要拉普拉斯平滑系数?
A: 当某个特征在某个类别中没有出现时,概率为0,会导致整个联合概率为0(因为概率相乘)。拉普拉斯平滑在分母加一个值(通常为1),防止分母为0,保证概率不为0。
8 本课小结
- 概率:事情发生的可能性,0-1。
- 贝叶斯:利用概率值分类。
- 朴素:假设特征相互独立。
- 条件概率:P(A|B)。
- 拉普拉斯平滑:防止分母为0。
9 延伸思考与实践
- 实践:运行朴素贝叶斯分类示例。
- 预习:商品评论情感分析案例。
- 思考:为什么假设特征相互独立?