一、朴素贝叶斯算法概述
朴素贝叶斯(Naive Bayes)是一种基于贝叶斯定理的简单概率分类算法,它假设特征之间相互独立("朴素"的含义)。尽管这个假设在现实中很少成立,但该算法在许多实际应用中表现优异,特别是在文本分类领域。
1.1 贝叶斯定理回顾
贝叶斯定理的数学表达式为:
其中:
-
P(A|B) 是后验概率
-
P(B|A) 是似然
-
P(A) 是先验概率
-
P(B) 是边际概率
1.2 朴素贝叶斯分类器
对于分类问题,我们可以将贝叶斯定理改写为:
其中X是特征向量(x₁, x₂, ..., xₙ)。由于朴素贝叶斯假设特征间相互独立,因此:
二、scikit-learn中的朴素贝叶斯实现
scikit-learn提供了三种主要的朴素贝叶斯分类器变体:
-
GaussianNB:用于连续数据,假设特征服从正态分布
-
MultinomialNB:用于离散计数数据,如文本分类中的词频
-
BernoulliNB:适用于二元/布尔特征数据
2.1 GaussianNB API详解
参数说明
class sklearn.naive_bayes.GaussianNB(*, priors=None, var_smoothing=1e-09)
-
priors:类的先验概率。如果指定,则不根据数据调整先验
-
var_smoothing:所有特征的最大方差部分,添加到方差计算中以提高数值稳定性
属性说明
-
class_prior_:每个类的概率
-
class_count_:每个类的训练样本数量
-
theta_:每个类每个特征的均值
-
sigma_:每个类每个特征的方差
-
epsilon_:方差的绝对加值
示例代码
from sklearn.naive_bayes import GaussianNB
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score# 加载数据集
iris = load_iris()
X = iris.data # 特征矩阵
y = iris.target # 目标向量# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)# 创建高斯朴素贝叶斯分类器
gnb = GaussianNB(priors=None, # 不指定先验概率,让模型从数据中学习var_smoothing=1e-9 # 默认值
)# 训练模型
gnb.fit(X_train, y_train)# 预测测试集
y_pred = gnb.predict(X_test)# 计算准确率
accuracy = accuracy_score(y_test, y_pred)
print(f"模型准确率: {accuracy:.2f}")# 查看模型参数
print("\n类先验概率:", gnb.class_prior_)
print("\n每个类的样本数量:", gnb.class_count_)
print("\n每个特征的均值:\n", gnb.theta_)
print("\n每个特征的方差:\n", gnb.sigma_)
2.2 MultinomialNB API详解
参数说明
class sklearn.naive_bayes.MultinomialNB(*, alpha=1.0, fit_prior=True, class_prior=None)
-
alpha:平滑参数(拉普拉斯/Lidstone平滑),默认为1.0
-
fit_prior:是否学习类的先验概率。若为False,则使用统一先验
-
class_prior:类的先验概率。如果指定,则不根据数据调整先验
属性说明
-
class_log_prior_:每个类的对数概率
-
feature_log_prob_:给定类别的特征(对数)概率
-
class_count_:每个类的训练样本数量
-
feature_count_:每个类每个特征的数量
示例代码
from sklearn.naive_bayes import MultinomialNB
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.datasets import fetch_20newsgroups
from sklearn.metrics import classification_report# 加载20个新闻组数据集
categories = ['alt.atheism', 'soc.religion.christian', 'comp.graphics', 'sci.med']
newsgroups_train = fetch_20newsgroups(subset='train', categories=categories)
newsgroups_test = fetch_20newsgroups(subset='test', categories=categories)# 将文本转换为词频向量
vectorizer = CountVectorizer()
X_train = vectorizer.fit_transform(newsgroups_train.data)
X_test = vectorizer.transform(newsgroups_test.data)
y_train = newsgroups_train.target
y_test = newsgroups_test.target# 创建多项式朴素贝叶斯分类器
mnb = MultinomialNB(alpha=1.0, # 拉普拉斯平滑fit_prior=True, # 学习类先验概率class_prior=None # 不指定先验
)# 训练模型
mnb.fit(X_train, y_train)# 预测测试集
y_pred = mnb.predict(X_test)# 打印分类报告
print(classification_report(y_test, y_pred, target_names=newsgroups_train.target_names))# 查看模型参数
print("\n类对数概率:", mnb.class_log_prior_)
print("\n特征对数概率形状:", mnb.feature_log_prob_.shape)
2.3 BernoulliNB API详解
参数说明
class sklearn.naive_bayes.BernoulliNB(*, alpha=1.0, binarize=0.0, fit_prior=True, class_prior=None)
-
alpha:平滑参数,默认为1.0
-
binarize:将特征二值化的阈值。None表示假设输入已经由二进制向量组成
-
fit_prior:是否学习类的先验概率
-
class_prior:类的先验概率
属性说明
-
class_log_prior_:每个类的对数概率
-
feature_log_prob_:给定类别的特征(对数)概率
-
class_count_:每个类的训练样本数量
-
feature_count_:每个类每个特征的数量
示例代码
from sklearn.naive_bayes import BernoulliNB
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.datasets import fetch_20newsgroups
from sklearn.metrics import accuracy_score# 加载数据
categories = ['alt.atheism', 'soc.religion.christian']
newsgroups_train = fetch_20newsgroups(subset='train', categories=categories)
newsgroups_test = fetch_20newsgroups(subset='test', categories=categories)# 将文本转换为二进制特征向量(出现/不出现)
vectorizer = CountVectorizer(binary=True)
X_train = vectorizer.fit_transform(newsgroups_train.data)
X_test = vectorizer.transform(newsgroups_test.data)
y_train = newsgroups_train.target
y_test = newsgroups_test.target# 创建伯努利朴素贝叶斯分类器
bnb = BernoulliNB(alpha=1.0, # 平滑参数binarize=None, # 数据已经是二进制的fit_prior=True # 学习类先验
)# 训练模型
bnb.fit(X_train, y_train)# 预测测试集
y_pred = bnb.predict(X_test)# 计算准确率
accuracy = accuracy_score(y_test, y_pred)
print(f"模型准确率: {accuracy:.2f}")# 查看模型参数
print("\n类对数概率:", bnb.class_log_prior_)
print("\n特征对数概率形状:", bnb.feature_log_prob_.shape)
三、朴素贝叶斯实战案例:垃圾邮件分类
3.1 数据准备
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.feature_extraction.text import TfidfVectorizer# 加载数据集
# 假设我们有一个CSV文件,包含"text"列和"label"列(0=正常邮件,1=垃圾邮件)
data = pd.read_csv('spam_dataset.csv')# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(data['text'], data['label'], test_size=0.2, random_state=42
)# 使用TF-IDF向量化文本
vectorizer = TfidfVectorizer(max_features=5000, # 只使用前5000个最常见的词stop_words='english', # 移除英文停用词ngram_range=(1, 2) # 使用单个词和双词组合
)X_train_vec = vectorizer.fit_transform(X_train)
X_test_vec = vectorizer.transform(X_test)
3.2 模型训练与评估
from sklearn.naive_bayes import MultinomialNB
from sklearn.metrics import classification_report, confusion_matrix, roc_auc_score# 创建并训练模型
model = MultinomialNB(alpha=0.1) # 使用较小的平滑参数
model.fit(X_train_vec, y_train)# 预测测试集
y_pred = model.predict(X_test_vec)
y_pred_proba = model.predict_proba(X_test_vec)[:, 1] # 预测为垃圾邮件的概率# 评估模型
print("分类报告:")
print(classification_report(y_test, y_pred))print("\n混淆矩阵:")
print(confusion_matrix(y_test, y_pred))print(f"\nAUC分数: {roc_auc_score(y_test, y_pred_proba):.4f}")
3.3 模型解释
import numpy as np# 获取特征名称
feature_names = np.array(vectorizer.get_feature_names_out())# 找出对"垃圾邮件"分类最重要的特征
spam_log_prob = model.feature_log_prob_[1, :] # 垃圾邮件类的特征对数概率
ham_log_prob = model.feature_log_prob_[0, :] # 正常邮件类的特征对数概率# 计算对数概率比
log_prob_ratio = spam_log_prob - ham_log_prob# 获取最重要的20个特征
top_20_spam_indices = log_prob_ratio.argsort()[-20:][::-1]
top_20_spam_features = feature_names[top_20_spam_indices]
top_20_spam_scores = log_prob_ratio[top_20_spam_indices]print("最重要的20个垃圾邮件特征:")
for feature, score in zip(top_20_spam_features, top_20_spam_scores):print(f"{feature}: {score:.2f}")
四、朴素贝叶斯的优缺点
4.1 优点
-
简单高效:训练和预测速度都非常快
-
对小规模数据表现良好:即使数据量较少也能工作得不错
-
适合高维数据:特别是文本分类等场景
-
可解释性强:可以轻松查看哪些特征对分类贡献最大
4.2 缺点
-
特征独立性假设:现实中特征往往相关,这可能导致性能下降
-
对输入数据分布敏感:如果数据分布与假设不符(如非高斯分布使用GaussianNB),性能会受影响
-
零概率问题:测试集中出现训练集中未出现的类别时,概率为0
五、常见问题与解决方案
5.1 如何处理连续特征?
-
使用GaussianNB,它假设连续特征服从正态分布
-
对特征进行离散化(分箱),然后使用MultinomialNB或BernoulliNB
-
进行数据变换使其更接近正态分布
5.2 如何解决零概率问题?
-
使用平滑技术(如拉普拉斯平滑)
-
添加伪计数
-
使用back-off模型
5.3 如何选择朴素贝叶斯变体?
-
文本数据:通常使用MultinomialNB
-
二进制/布尔特征:使用BernoulliNB
-
连续特征:使用GaussianNB
六、总结
朴素贝叶斯是一种简单但强大的分类算法,特别适合文本分类和高维数据。通过scikit-learn提供的API,我们可以轻松实现不同变体的朴素贝叶斯分类器。虽然它有特征独立性假设的局限性,但在许多实际应用中仍然表现优异。
在实践中,建议:
-
根据数据类型选择合适的朴素贝叶斯变体
-
调整平滑参数以获得更好的性能
-
结合TF-IDF等文本特征提取方法处理文本数据
-
使用交叉验证评估模型性能
希望本篇博客能帮助你理解和应用朴素贝叶斯分类器!