基于 sklearn 的传统机器学习在搜狗新闻数据的文本分类实践

sklearn is good tool.

1. 背景

在sklearn下比较各个传统机器学习模型在文本分类任务上的表现。

2. 数据准备

数据源依旧来自搜狗的新闻数据,由于机器的性能,本文只用到了一个星期的数据。

数据清洗

从搜狗下载的新闻数据格式为xml,从HTML标签中提取标签和正文的工作在基于 Tensorflow 的 TextCNN 在搜狗新闻数据的文本分类实践一文中已经完成,不再赘述。因为在本次实验中不再使用基于字符级的思想,而是基于词,所以还要对数据做分词、去噪清洗操作。

分词:使用jieba分词工具,因为在分词时数据是单条单条处理的,所以速度会比较慢,对原始数据采用多进程分词,能节省不少的时间。你可以把多进程理解为把任务列表扔给进程池,“这是交给你的任务,你们赶紧给我办好!”,然后进程池的工人们就迅速过来认领任务,并同时开始工作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# coding: utf-8

import jieba

stopwords_path = 'stopwords.txt'


class CutWord(object):
def __init__(self, stopwords_path=stopwords_path):
self.stopwords_path = stopwords_path

def add_dictionary(self, dict_list):
map(lambda x: jieba.load_userdict(x), dict_list)

def seg_sentence(self, sentence, stopwords_path=None):
if not stopwords_path:
stopwords_path = self.stopwords_path

def stopwords_list(file_path):
stopwords = [line.strip() for line in open(file_path, 'r').readlines()]
return stopwords

segmented_sentence = jieba.cut(sentence.strip())
stopwords_list = stopwords_list(stopwords_path)
out_str = ''

for word in segmented_sentence:
if word not in stopwords_list:
out_str += word
out_str += ' '
return out_str

多进程分词:

1
2
3
4
5
6
7
8
9
from multiprocessing import Pool

pool = Pool(processes=6)
for file_path, write_path in zip(file_list, write_list):
paths = [file_path, write_path]
pool.apply_async(seg_file, (paths,))
pool.close()
pool.join()
print('Word segment finished...')

去噪:原始数据中有标点符号、停用词等噪声,通过加载外部停用词文件过滤掉这一部分的噪声。为了方便,把这两个功能整合成为一个工具类CutWord,在其他程序中直接调用使用即可。

分词、去噪清洗工作完毕,看看各个类别下的数据分布,占比最多的前四个是体育、新闻、商业和娱乐,其余8个类别的新闻占比均不足5%,数据量比较小。因为在这之前我用该数据做了二分类的任务,发现分类效果实在太好了,1万多的测试数据只有十几个分错了,好得有点不真实,所以,我决定拿占比排名前4类的数据来做实验。

image

数据切分

每个类别新闻按照5000条训练集、500条验证集、1000条测试集提取,所以总共有训练集:验证集:测试集为20000:2000:4000。

特征提取

sklearn中常用的文本特征提取方法有tfidf,将文本转换为文档-词项矩阵,矩阵中的元素,可以使用词频也可以使用tfidf值。为了获得更好的效果,本次试验的文本特征提取用到了全量的数据。

1
2
3
4
5
6
def tf_idf(contents):
"""提取文本特征tf-idf"""
vectorizer = CountVectorizer(min_df=1e-5)
transformer = TfidfTransformer()
tfidf = transformer.fit_transform(vectorizer.fit_transform(contents))
return tfidf

3. 模型训练

3.1 logistic regression

logitstic regression的背景知识参考我的笔记:机器学习算法系列(3)Logistic Regression | Thinking Realm

为了有更好地优化参数,选用了更有效的交叉验证的LogisticRegressionCV模型,cv设置为10,训练的时间略长;n_jobs设置为-1,利用起所有的CPU核心。

1
2
3
4
5
6
lr_model = LogisticRegressionCV(solver='newton-cg', multi_class='multinomial', cv=10, n_jobs=-1)
lr_model.fit(x_train[:20000], y_train[:20000])

y_pred = lr_model.predict(x_train[20000:24000])
print(metrics.confusion_matrix(y_train[20000:24000], y_pred))
print(classification_report(y_train[20000:24000], y_pred, target_names=['business', 'sports', 'news', 'yule']))

训练结果如下,模型在测试集上的表现还不错,除了体育的准确率为89%,其余的类别的指标都在90%以上。读不懂报告,参考:读懂sklearn的classification_report

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[[924  84   0   0]
[ 51 941 16 16]
[ 1 14 963 5]
[ 3 16 5 961]]
precision recall f1-score support

business 0.94 0.92 0.93 1008
sports 0.89 0.92 0.91 1024
news 0.98 0.98 0.98 983
yule 0.98 0.98 0.98 985

micro avg 0.95 0.95 0.95 4000
macro avg 0.95 0.95 0.95 4000
weighted avg 0.95 0.95 0.95 4000

3.2 线性支持向量机

支持向量机的背景知识参考我的系列笔记:

1
2
3
4
5
6
svm_model = SGDClassifier(n_jobs=-1)
svm_model.fit(x_train[:20000], y_train[:20000])

y_pred = svm_model.predict(x_train[20000:24000])
print(metrics.confusion_matrix(y_train[20000:24000], y_pred))
print(classification_report(y_train[20000:24000], y_pred, target_names=['business', 'sports', 'news', 'yule']))

强大如支持向量机,30秒不到就完成了训练,按照性价比,完全可以把LogisticRegressionCV摁在地上摩擦。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[[889 118   0   1]
[ 67 922 17 18]
[ 2 12 962 7]
[ 1 14 4 966]]
precision recall f1-score support

business 0.93 0.88 0.90 1008
sports 0.86 0.90 0.88 1024
news 0.98 0.98 0.98 983
yule 0.97 0.98 0.98 985

micro avg 0.93 0.93 0.93 4000
macro avg 0.94 0.94 0.94 4000
weighted avg 0.94 0.93 0.93 4000

3.3 朴素贝叶斯

朴素贝叶斯的背景知识参考我的系列笔记:机器学习算法系列(7)朴素贝叶斯法 | Thinking Realm

速度飞快,效果还行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[[908  99   0   1]
[129 842 15 38]
[ 2 14 948 19]
[ 6 17 4 958]]
precision recall f1-score support

business 0.87 0.90 0.88 1008
sports 0.87 0.82 0.84 1024
news 0.98 0.96 0.97 983
yule 0.94 0.97 0.96 985

micro avg 0.91 0.91 0.91 4000
macro avg 0.91 0.92 0.91 4000
weighted avg 0.91 0.91 0.91 4000

4. 模型对比

  • 文本分类任务,支持向量机的表现可以吊打其他模型
  • 一般的数据集的分类任务,各个模型的表现差距不是特别明显,用法大同小异
  • 在结巴分词下逐条分词速度很慢,考虑多进程来解决
  • 该实验用到的数据量不大,当数据量上升,场景复杂化,参数优化必不可少
觉得还不错?赞助一下~
0%