以二分类多项式朴素贝叶斯模型为例说明特征选择的原理。通过前边朴素贝叶斯sklearn实践部分我们可以看到,对于二分类问题来说,sklearn中只使用一个线性分类器f(x)=wx+b,这里显然w是一个一维的向量,它是分类器的参数,x是待预测文本的TF法向量化表示,b表示该分类器所预测的两个类别中的一个类别的出现概率。显然w各维表示的词语的似然概率p(w|c),p(w|c)的值越大说明类别c产生这个词语的可能越大,也就是说这个词语更能表征这个类别。通过上边的分析,我们不难想到,可以通过设一定的系数值阈值来实现特征选择,对于系数值大于设定阈值的词项予以保留,对于系数值小于设定阈值的词项予以去除,实现了特征选择的目的。
在SelectFromModel类中特征选择之前对系数做了绝对值操作,这叫做1范数正则化,我们都知道正则化的操作是避免线性模型过拟合问题的,但是对于朴素贝叶斯来说这样的操作是不符合原理的。因为朴素贝叶斯根本就不涉及过拟合的问题,因为它根本就没有通过迭代最小化误差的思想。反而由于取了绝对值再去做阈值筛选,筛选出来的反倒是要被过滤的。原因是朴素贝叶斯的所有概率值都去了对数,则所有系数值都为负值且值越小概率越小,但是由于绝对值的操作,使得概率值变为正值,而且对数曲线在0-1区间内变为减函数,于是值越小反而概率越大。综上,对于SelectFromModel这个类特征选择,只能给他传递线性模型,比如线性SVM。这里我们给出利用SelectFromModel思想的朴素贝叶斯模型特征选择方法代码
# 定义文本集
In [1]: texts = ['Chinese Beijing Chinese',
...: 'Chinese Chinese Shanghai',
...: 'Chinese Macao',
...: 'Tokyo Japan Chinese']
...:
# 定义类别
In [2]: y = [-1, -1, -1, 1]
# 训练集向量化
In [3]: from sklearn.feature_extraction.text import CountVectorizer
In [4]: tf = CountVectorizer()
In [5]: X = tf.fit_transform(texts)
# 训练朴素贝叶斯模型
In [6]: from sklearn.naive_bayes import MultinomialNB
In [7]: m = MultinomialNB(fit_prior=True)
In [8]: m.fit(X, y)
Out[8]: MultinomialNB(alpha=1.0, class_prior=None, fit_prior=True)
# 打印特征词向量
In [9]: tf.get_feature_names()
Out[9]: ['beijing', 'chinese', 'japan', 'macao', 'shanghai', 'tokyo']
# 打印系数向量
In [10]: m.coef_
Out[10]:
array([[-2.19722458, -1.5040774 , -1.5040774 , -2.19722458, -2.19722458,
-1.5040774 ]])
# 使用系数向量各维度值的均值作为阈值
In [11]: import numpy as np
In [12]: threshold = np.mean(m.coef_)
In [13]: threshold
Out[13]: -1.850650987056247
# 输出选择出的词语
In [14]: for term, w_value in zip(tf.get_feature_names(), m.coef_[0]):
...: if w_value >= threshold:
...: print(term, end=' ')
...:
chinese japan tokyo
今天的内容主要说了SelectFromModel只能传入线性分了模型,而不能传入朴素贝叶斯模型,基于朴素贝叶斯原理做出了这个结论,想找到一个例子来证明这么理解是对的,但是没有找到,如果小伙伴觉得这个结论有问题,欢迎留言。