sklearn朴素贝叶斯分类器_sklearn-如何用好Multinomial来做文本分类

v2-37da8d2d3561f5222dad62db3ae729bc_1440w.jpg?source=172ae18b

看了sklearn中多项式朴素贝叶斯的实现过程,得到了这样一个结论:sklearn中的多项式朴素贝叶斯类是专门为文本分类设计的,如果将朴素贝叶斯应用到其他非文本领域的分类,则需要精心设计输入的数据矩阵,否则训练的过程根本就不再是朴素贝叶斯的计算过程。这也就说明为啥很多做非文本机器学习的面试中,根本就不问朴素贝叶斯,或许他根本就不知道sklearn库的实现过程,硬往代码里套结果肯定是错的,然后就说其他模型比朴素贝叶斯好。后续的实践篇里,再把朴素贝叶斯应用到“的”、“地”、“得”误用识别中,首先这个方法曾经在实践的过程中用过,但是效果不理想,最近在整理的时候,发现好想当时用错了模型,这次重新整理了思路,到时候看看是否能使准确率达到80%以上。现在想到的,这里可能还涉及到一个不平衡分类的问题,因为“的”字使用率比“地”、“得”的使用率高很多。

好了,进入今天的正题。我们在介绍朴素贝叶斯原理的文章中,举过一个完整的朴素贝叶斯文本分类示例,请看baiziyu:朴素贝叶斯算法——多项式朴素贝叶斯,写到这里加几句题外话,我看专栏里大家点赞比较多的是特征选择和文本聚类示例,似乎觉得文本分类太简单了,而且我写的文本分类都是用的朴素贝叶斯,现在想想朴素贝叶斯恐怕是我实践中用的最多的一个分类模型了。我还是极力推荐大家用朴素贝叶斯。在模型选择的文章中表达过,文本分类重头戏在文本的表示上,在分类特征的选择上,表示意思是将文本的语义完整地表示成数值向量,选择指的是选出那些对特定分类应用有区分性的词语或跨字ngrams,还有一点就是准确标注的数量要足够,而不是把重头戏放在模型上,前边3个条件没有满足的情况下,谈模型的优劣是没有太大意义的。

回到主题,现在我们用sklearn库实现前边的示例

sklearn中的多项式朴素贝叶斯的实现是按照线性模型来做的,具体请看baiziyu:sklearn-MultinomialNB。由于这里我们预测的类别只有2个,所以按照线性分类来说只需要1个分类器,因此系数矩阵是1行的,也就是coef_属性是1行的矩阵。但我们猜测内部还是一个有两行的矩阵,否则无法计算属于另一个类别的概率值。这里我们利用sklearn训练得到的模型的系数矩阵演示计算p(c=Japan)的过程。

首先,定义数据集

# 训练集

接着,我们进行文本表示。这里多说一句,sklearn的多项式朴素贝叶斯需要文本的表示采用CountVectorizer类,如果用TfidfVectorizer后续的计算都将是错误的,所以请大家注意。不要认为tf-idf表示的词袋模型好就乱用,在这里我们只能用词语频次的词袋模型。原因当然很简单,因为似然估计公式是 P(ti|c)=c类文档集中词语ti出现次数/c类文档集中词语总数,后边的MultinomialNB模型就是根据输入的数据矩阵做统计的,因此矩阵中元素只能表示为词语在文本中出现次数。

rom sklearn.feature_extraction.text import CountVectorizer
tf = CountVectorizer()
X = tf.fit_transform(texts)

之后,我们实例化并训练模型

from sklearn.naive_bayes import MultinomialNB
m = MultinomialNB(fit_prior=True)
m.fit(X, y)

训练完毕后,我们查看一下训练出的模型的截距intercept_和系数coef_

tf.get_feature_names()返回
['beijing', 'chinese', 'japan', 'macao', 'shanghai', 'tokyo']
m.intercept_ = -1.38629436
m.coef_ = [-2.19722458, -1.5040774 , -1.5040774 , -2.19722458, -2.19722458,-1.5040774 ]

在这里说明一下截距和系数的计算过程,以及他们和前边示例里计算过程的对应关系

v2-0b94a161243a4caad2242f7f988f8ae9_b.jpg

从该图我们就可以看出,截距实际上就是我们前边示例里计算的类别先验概率,系数就是前边示例里计算的针对每个词种的似然概率。

之后,我们来表示测试集

X_test = tf.transform(test)
对应的矩阵为
[0 3 1 0 0 1]

最后,看预测过程,实际上这个过程就对应我们前边示例中后验概率P(c!=China|Chinese Chinese Chinese Tokyo Japan)的计算过程,只是那里我们用的是概率乘积,这里我们用的是概率的自然对数的和。

prob_log = b + w*x

In [18]: b
Out[18]: -1.38629436
In [19]: w
Out[19]: 
array([-2.19722458, -1.5040774 , -1.5040774 , -2.19722458, -2.19722458,
       -1.5040774 ])
In [20]: x
Out[20]: array([0, 3, 1, 0, 0, 1])
In [21]: b + np.dot(w,x)
Out[21]: -8.90668136

大家可以算一算,exp(-8.90668136)的值,看看跟我们前边示例中的计算值是否一致,肯定一致,必须的。

至此,就是sklearn中对多项式朴素贝叶斯的实现过程,可以对比一下前边的计算方法,只是所有概率值都取自然对数ln,所有概率相乘都变成取对数相加,会发现两种计算的过程是一致的。总结到这里,我们其实已经能够看出,sklearn中的多项式朴素贝叶斯就是针对文本分类而设计的,如果我们要应用多项式朴素贝叶斯到其他领域需要好好设计输入数据的向量化,否则计算过程就跟朴素贝叶斯的原理不一致了。还需要注意的是,sklearn为了使预测的两个类别的概率之和等于1,引入了规范化过程。

最后,我们说一下sklearn增加的规范化过程(使预测到两个类别的概率和为1)

In [1]: import numpy as np
In [2]: jll = np.array([np.log(0.000299), np.log(0.000135)])
In [3]: jll
Out[3]: array([-8.11506698, -8.91023578])
In [4]: log_prob_x = np.log(sum(np.exp(jll)))
In [5]: log_prob_x
Out[5]: -7.742466023863869
In [6]: log_proba = jll - np.atleast_2d(log_prob_x)
In [7]: log_proba
Out[7]: array([[-0.37260096, -1.16776976]])
In [8]: proba = np.exp(log_proba)
In [9]: proba
Out[9]: array([[0.68894009, 0.31105991]])

好了,到这里所有的计算过程就介绍清楚了,大家可以看看notebook上的完整运行结果

https://github.com/baiziyuandyufei/text_classification_tradition/blob/master/Chap2/sklearn-MultinomialNB文本分类示例.ipynb​github.com

到这里今天的内容就全部介绍完毕了。真心的希望这篇文章能够让大家对朴素贝叶斯重新开始感兴趣,它也真的是目前为止上手最快,易于理解,易于查找badcase原因,时间复杂度适中,空间复杂度适中的一个分类模型,应该值得好好应用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值