数据挖掘 文本分类 知乎问题单分类(四):分类
经过前几部分的准备,现在我们终于要到最后使用模型分类的时刻了。这里我们使用了多项式朴素贝叶斯分类器和SVM分类器进行分类。
朴素贝叶斯
贝叶斯定理1
贝叶斯定理是关于随机事件A和B的条件概率的一则定理。
贝叶斯分类
贝叶斯分类方法的新实例分类目标是在给定描述实例的属性值
<a1,a2…an>下,得到最可能的目标值VMAP。
上式中的有两个数据项需要估计:
(1)P(vj)
常常是计算每个目标值vj出现在训练数据中的频率。
(2)P(a1,...an/vj)
除非有一个非常大的训练数据集,否则应用频率的方法无
法获得可靠的估计。
朴素贝叶斯分类器(Naive Bayes)
为了解决上面第二个数据项需要非常大的训练数据集,且计算量巨大的问题。我们引入了朴素贝叶斯:
朴素贝叶斯分类器的假定:在给定目标值下,属性值之间相互条件独立
。换言之,给定实例的目标值情况下,观察到联合的a1, a2…an的概率正好是对每个单独属性的概率乘积
:
利用频率方法,从训练数据中估计不同P(ai|vj)项的所需样本数比要估计P(a1,…,an|vj)项所需的量小得多 。从而我们能得到下面所饰的朴素贝叶斯分类器的定义。
朴素贝叶斯分类器的定义:
其中vNB表示朴素贝叶斯分类器输出的目标值。
朴素贝叶斯文本分类例子
假定我们共有1000个训练文档,其中700个分类为dislike,300个分类为like,现在要对下面的新文档进行分类:
- This is an example document for the naive Bayes classifier. This document contains only one paragraph, or two sentences.
朴素贝叶斯进行文本分类就如上面所示,但是有几点需要说明:
- 注意此处贝叶斯分类器隐含的独立性假设并不成立。通常,某个位置上出现某个单词的概率与前后位置上出现的单词是相关的
- 虽然此处独立性假设不精确,但别无选择,否则要计算的概率项极为庞大。
- 另外实践中,朴素贝叶斯学习器在许多文本分类问题中性能非常好
朴素贝叶斯文本分类算法
训练算法:
学习算法:
朴素贝叶斯如何利用向量空间模型进行分类计算?
-
生成类别标签,统计某一文档属于某一类的概率。即
P(vj)
。这个可通过训练集的标签y_train
进行计算。例如:{0:0.1,1:0.9} (键为类别标签,键值为该类的文档数所占比例) -
将训练集TF-IDF矩阵中属于相同类别的文档向量相加,形成m*n的矩阵,m代表类别数,n代表词典数。同时为了防止后面出现乘0的情况,我们将矩阵中
所有元素都加上1
。例如:
[[2, 3, 1]
[1, 2, 2]] -
将每一个词的权重除以该类所有词的总权重。(这个要注意,这里的总权重其实
加上了 |vocabulary|
,即词袋的大小)。此时矩阵中的每个元素都对应一个P(wk|vj)
例如:
[[2/6, 3/6, 1/6]
[1/5, 2/5, 2/5]] -
上面都是训练阶段,下面的就是测试阶段。对测试集每条文本对应的TF-IDF,计算:
这里vNB
就是预测的结果,这样就可以对文本进行分类了。
但是这里有一个问题就是,如果直接使用上述的公式,因为P(ai|vj)
都小于1,这样最后所有的概率相乘可能导致小到计算机无法表示,所以我们将连乘部分加上log,因为log(x1*x2*x3) = log(x1)+ log(x2)+ log(x3)
,所以就不会出现上述问题,并且log函数单调增,不会影响最终结果。
代码实现
这里我们使用了sklearn多项式朴素贝叶斯进行分类,具体代码如下:
data = pd.read_csv("data/data_seg.csv")
x_train, x_test, y_train, y_test = train_test_split(data['seg'], data['type'], test_size = 0.5, shuffle=True, random_state=1)
tfidf_vec = TfidfVectorizer( stop_words=stop_words, max_features=1000)
cv_fit = tfidf_vec.fit_transform(data['seg'].astype(str))
train_vec = tfidf_vec.transform(x_train.astype(str))
test_vec = tfidf_vec.transform(x_test.astype(str))
# 贝叶斯模型训练
nb_clf = MultinomialNB()
nb_clf.fit(train_vec, y_train)
# 贝叶斯模型测试
print(nb_clf.score(test_vec, y_test))
分类结果:
SVM
SVM的具体原理这里就不再介绍了,有兴趣同学可以去 《统计学习方法》
2上的原理,上面讲的很详细。
我们使用的仍然是sklearn的库SVC(C-Support Vector Classification.)
,具体代码如下:
svc_clf = SVC(kernel='rbf', class_weight='balanced', gamma="scale")
svc_clf.fit(train_vec, y_train)
# 输出测试结果
print(svc_clf.score(test_vec, y_test))
其实我们使用了GridSearchCV
进行超参数选择,具体代码如下:
svc = SVC(kernel='rbf', class_weight='balanced',)
c_range = np.logspace(-5, 15, 11, base=2)
gamma_range = np.logspace(-9, 3, 13, base=2)
# 网格搜索交叉验证的参数范围,cv=3,3折交叉
param_grid = [{'kernel': ['rbf'], 'C': c_range, 'gamma': gamma_range}]
grid = GridSearchCV(svc, param_grid, cv=3, n_jobs=4)
# 训练模型
clf = grid.fit(train_vec, y_train)
# 计算测试集精度
score = grid.score(test_vec, y_test)
print('精度为%s' % score)
SVM的分来结果如下图所示,比朴素贝叶斯稍微好一点。