朴素贝叶斯分类

问题引入

设一个数据集为D={(X1, Y1), (X2, Y2), …, (Xn, Yn)},其中样本Xi的可由m个特征表示,即Xi=(Xi1, Xi2, , Xim)(一般要离散特征,对于连续特征的情况见后续的注意事项);而Yi为样本标签,Yi∈{C1,C2, …, Ck},i=1,2, …, n.

现有一个新样本X# = (X#1, X#2, , X#m),在给定的数据集D的基础上估计其所属的类别标签Y#(即对其进行分类,也即估计条件概率P(Y# | X#) )。

算法理论(问题分析)

1.贝叶斯定理

贝叶斯定理给出:

朴素贝叶斯分类实现垃圾短信识别——python自行实现和sklearn接口调用_特征独立假设

由于P(X#)对于所有类别都是相同的(因为这里是在比较不同类别的后验概率),所以选择忽略它,而只专注于计算

朴素贝叶斯分类实现垃圾短信识别——python自行实现和sklearn接口调用_特征独立假设_02

2. 朴素贝叶斯的假设

朴素贝叶斯分类器假设样本特征之间相互独立,即:

朴素贝叶斯分类实现垃圾短信识别——python自行实现和sklearn接口调用_垃圾短信_03

忽略分母P(X#)且应用该假设之后,

朴素贝叶斯分类实现垃圾短信识别——python自行实现和sklearn接口调用_特征独立假设_04

3. 计算概率

计算

朴素贝叶斯分类实现垃圾短信识别——python自行实现和sklearn接口调用_垃圾短信_05

朴素贝叶斯分类实现垃圾短信识别——python自行实现和sklearn接口调用_贝叶斯定理_06

…………

朴素贝叶斯分类实现垃圾短信识别——python自行实现和sklearn接口调用_sklearn_07

k个“概率值”的最大值对应的Ck即为最后所预测的样本X#的标签。

这里使用所给定的数据集D的“频率”代替“概率”:

朴素贝叶斯分类实现垃圾短信识别——python自行实现和sklearn接口调用_贝叶斯定理_08

其中,朴素贝叶斯分类实现垃圾短信识别——python自行实现和sklearn接口调用_sklearn_09为D中标签为Ck的样本数量,n为D中的样本总数,

朴素贝叶斯分类实现垃圾短信识别——python自行实现和sklearn接口调用_贝叶斯定理_10

计算的是类别Ck中样本的第j个特征的值为X#j的样本数(也即D中类别为Ck且第j个特征的值为X#j的样本的数量)。

另外,在实际应用中,为了防止出现“零概率”(D中不一定有足够的样本数量造成的),实际使用的计算中需要加入平滑处理,如拉普拉斯平滑:

朴素贝叶斯分类实现垃圾短信识别——python自行实现和sklearn接口调用_特征独立假设_11

其中,K为标签的种数(即样本的标签共用K种),Aj为X#j所有可能取值的个数(即样本的第j个特征共有Aj种取值),j=1,2, …, m。

. 注意事项

朴素贝叶斯分类器假设特征之间相互独立,虽然这在实际应用中往往不成立,但它在许多情况下仍然表现良好。

对于连续特征,通常假设它们服从某种分布(如高斯分布),并计算该分布的参数(如均值和方差),然后使用这些参数来估计条件概率。

拉普拉斯平滑或其他平滑技术可以帮助处理零概率问题,提高模型的鲁棒性。

示例实验-垃圾信息识别

数据准备

原数据文件:SMSSpamCollection,每行表示一个样本(文本标签,文本单词,用Tab格隔开)。样本总数为5574,分两类(ham、spam分别表示正常短信、垃圾短信)。

朴素贝叶斯分类实现垃圾短信识别——python自行实现和sklearn接口调用_特征独立假设_12

SMSSpamCollection部分内容

加载数据集并拆分为训练集、测试集:

from sklearn.feature_extraction.text import CountVectorizer
from sklearn.model_selection import train_test_split

# 加载SMS垃圾短信数据集
with open('SMSSpamCollection', 'r', encoding='utf8') as f:
 sms = [line.split('\t') for line in f]
y, x = zip(*sms)
# 为了测试可以先取少量样本
# n = 100
# y, x = y[:n], x[:n]
print(len(x))
y = [1 if label == 'spam' else 0 for label in y