朴素贝叶斯和其他绝大多数的分类算法都不同。对于大多数的分类算法,比如决策树,KNN,逻辑回归,支持向量机等,他们都是判别方法,也就是直接学习出特征输出Y和特征X之间的关系,要么是决策函数Y=f(X),要么是条件分布P(Y|X)。但是朴素贝叶斯却是生成方法,也就是直接找出特征输出Y和特征X的联合分布P(X,Y),然后用P(Y|X)=P(X,Y)/P(X)得出。
P(A|B) = P(A,B) / P(B) ---------条件概率:在事件B发生的前提下,A发生的概率
P(B|A) = P(A,B) / P(A)
所以:P(A,B) = P(A|B)P(B) = P(B|A)P(A)
所以贝叶斯公式:P(A|B) = (P(B|A)P(A)) / P(B) = P(A) * (P(B|A) / P(B))
这里:P(A) 为先验概率,即在B事件之前,对A事件概率的一个判断;P(A|B) 为后验概率,即B事件发生后,对事件A概率的重新评估;(P(B|A) / P(B)) 为可能性函数,这是一个调整因子,使得预估概率跟接近真实概率
公式可以理解为:P(A|B) = (P(B|A)P(A)) / P(B) ==> P(A|b1,b2,b3…) = (P(b1,b2,b3…|A)P(A)) / P(b1,b2,b3…)
即:在出现特征b1,b2,b3…的条件下,A事件发生的概率
当b1,b2,b3…事件相互独立的前提下:P(b1,b2,b3…|A) = P(b1|A)P(b2|A)P(b3|A)…
在计算后验概率的时,我们只需要计算分子的那两项即可,因为分母都是一样的。
1、对于P(A = Ck),比较简单,通过极大似然估计我们很容易得到P(A = Ck)为样本类别Ck出现的频率,即样本类别Ck出现的次数mk除以样本总数m。
2、P(bi|A = Ck),这取决于我们的先验条件:
a) 如果我们的bi是离散的值,那么我们可以假设bi符合多项式分布,这样得到 P(bi|A = Ck) 是在样本类别Ck中,特征bi出现的频率。即:
P(bi|A = Ck) = m_ki/M_k
其中M_k为样本类别Ck总的特征计数,而m_ki为类别为Ck的样本中,第i维特征bi出现的计数。
某些时候,可能某些类别在样本中没有出现,这样可能导致P(bi|A = Ck)为0,这样会影响后验的估计,为了解决这种情况,我们引入了拉普拉斯平滑,即此时有:
P(bi|A = Ck) = (m_ki+λ) / (M_k+Ojλ)
其中λ为一个大于0的常数,常常取为1。Oj为第j个特征的取值个数。
b) 如果我们我们的bi是非常稀疏的离散值,即各个特征出现概率很低,这时我们可以假设bi符合伯努利分布,即特征bi出现记为1,不出现记为0。即只要bi出现即可,我们不关注bi的次数。这样得到P(bi|A = Ck) 是在样本类别Ck中,bi出现的频率。此时有:
P(bi|A = Ck) = P(bi|A = Ck)bi + (1−P(bi|A = Ck))(1−bi)
其中,bi取值为0和1。
c)如果我们我们的bi是连续值,我们通常取bi的先验概率为正态分布,即在样本类别Ck中,bi的值符合正态分布。这样P(bi|A = Ck)的概率分布是:
其中μk和σ2k是正态分布的期望和方差,可以通过极大似然估计求得。μk为在样本类别Ck中,所有bi的平均值。σ2k为在样本类别Ck中,所有bi的方差。对于一个连续的样本值,带入正态分布的公式,就可以求出概率分布了。
问题:从上面的例子我们得到娱乐概率为0,这是不合理的,如果词频列表里面有很多出现次数都为0,很可能计算结果都为零
在scikit-learn中,一共有3个朴素贝叶斯的分类算法类。
分别是GaussianNB,MultinomialNB和BernoulliNB。其中GaussianNB就是先验为高斯分布的朴素贝叶斯,MultinomialNB就是先验为多项式分布的朴素贝叶斯,而BernoulliNB就是先验为伯努利分布的朴素贝叶斯。
这三个类适用的分类场景各不相同,一般来说,如果样本特征的分布大部分是连续值,使用GaussianNB会比较好。如果如果样本特征的分大部分是多元离散值,使用MultinomialNB比较合适。而如果样本特征是二元离散值或者很稀疏的多元离散值,应该使用BernoulliNB。
# 朴素贝叶斯进行文本分类
from sklearn.datasets import fetch_20newsgroups
from sklearn.model_selection import train_test_split
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.naive_bayes import MultinomialNB
news = fetch_20newsgroups()
# 进行数据分割
x_train, x_test, y_train, y_test = train_test_split(news.data, news.target, test_size=0.2)
tf = TfidfVectorizer()
# 对数据集进行特征抽取
x_train = tf.fit_transform(x_train)
x_test = tf.transform(x_test) # 按照x_train的特征进行转换
# 进行朴素贝叶斯算法的预测
mlt = MultinomialNB(alpha=1.0)
mlt.fit(x_train, y_train)
print(mlt.predict(x_test))
print(mlt.score(x_test, y_test))
[ 9 2 16 ... 11 11 14]
0.8440123729562528