本案例旨在用新闻主题分类这一简单任务演示机器学习的一般流程。具体地,我们使用了一个搜狐新闻数据集。使用 Python 的 jieba 分词工具对中文新闻进行了分词处理。然后使用 Scikit-learn 工具的 K近邻算法构建 KNN 模型。最后对新闻分类的效果进行了简单的分析。
搜狐中文新闻数据存放在 train_sample_utf8.csv 和 test_sample_utf8.csv 两个文件中,在后面的分析中我们分别当做训练集和测试集来使用。我们首先使用 Pandas
中的 read_csv
函数读取。
import pandas as pd
%matplotlib inline
raw_train = pd.read_csv("./input/train_sample_utf8.csv",encoding="utf8")
raw_test = pd.read_csv("./input/test_sample_utf8.csv",encoding="utf8")
查看两个文件的前五行数据。
raw_train.head(5)
raw_test.head(5)
raw_train.shape
raw_test.shape
可见,训练集包含 5521 条新闻,测试集中包含 3111 条新闻。那么,训练集和测试集中,不同主题的新闻分布如何?我们可以借助 DataFrame
某列的 value_counts
方法完成统计。然后使用 plot
函数进行可视化显示。
import matplotlib.pyplot as plt
plt.figure(figsize=(15, 8))
plt.subplot(1, 2, 1)
raw_train["分类"].value_counts().sort_index().plot(kind="barh",title='训练集新闻主题分布')
plt.subplot(1, 2, 2)
raw_test["分类"].value_counts().sort_index().plot(kind="barh",title='测试集新闻主题分布')
一共包含 12 种主题的新闻,无论是在训练集还是测试集,各个主题的新闻分布较均衡。
由于新闻为中文,再进一步进行处理之前,我们需要先对新闻内容进行分词。简单来说,分词就是将连在一起的新闻内容中的词进行分割。这里我们使用 Python 中一个著名的中文分析器 jieba
完成这项任务。为了后续方便,我们封装一个 news_cut
函数,它接受的输入为新闻内容,输出为分词后的结果。分词后,词与词之间使用空格进行分隔。
import jieba
def news_cut(text):
return " ".join(list(jieba.cut(text)))
#简单测试下分词效果
test_content = "六月初的一天,来自深圳的中国旅游团游客纷纷拿起相机拍摄新奇刺激的好莱坞环球影城主题公园场景。"
print(news_cut(test_content))
现在利用封装的分词函数,对训练集和测试集中的新闻内容进行分词处理,分词结果保存到对应 DataFrame 对象的 ”分词文章“ 一列。这里我们使用了 Pandas
中的 Series
对象的 map
函数。它能够接受一个函数,对 Series
中的每一个元素作为该函数的输入,然后将函数的输出返回。
raw_train["分词文章"] = raw_train["文章"].map(news_cut)
raw_test["分词文章"] = raw_test["文章"].map(news_cut)
raw_test.head(5)
#加载停用词
stop_words = []
file = open("./input/stopwords.txt")
for line in file:
stop_words.append(line.strip())
file.close()
from sklearn.feature_extraction.text import CountVectorizer
vectorizer = CountVectorizer(stop_words=stop_words)
X_train = vectorizer.fit_transform(raw_train["分词文章"])
X_test = vectorizer.transform(raw_test["分词文章"])
使用 sklearn
中 neighbors
模块的 KNeighborsClassifier
类构建一个 KNN 分类器。我们将邻居数 n_neighbors
设置为 5 。使用邻居的标签进行投票时,用预测样本与邻居样本的距离的倒数作为权重。然后使用 fit
方法,在训练集中训练模型。
from sklearn.neighbors import KNeighborsClassifier
knn = KNeighborsClassifier(n_neighbors=5,weights="distance")
knn.fit(X_train, raw_train["分类"])
模型训练完成后,可以使用 predict
方法对测试集中的样本进行预测,得到预测标签列表 Y_test
。
Y_test = knn.predict(X_test)
下面使用混淆矩阵来分析模型在测试样本上的表现。混淆矩阵从样本的真实标签和模型预测标签两个维度对测试集样本进行分组统计,然后以矩阵的形式展示。借助混淆矩阵可以很好地分析模型在每一类样本上的分类效果。为了更直观地分析,我们借助 Python 中可视化包 seaborn
提供的 heatmap
函数,将混淆矩阵可视化。
from sklearn.metrics import confusion_matrix
import seaborn as sns
import matplotlib.pyplot as plt
fig, ax = plt.subplots(figsize=(9, 7))
## 设置正常显示中文
sns.set(font='SimHei')
## 绘制热力图
ax = sns.heatmap(confusion_matrix(raw_test["分类"].values,Y_test),linewidths=.5,cmap="Greens",
annot=True, fmt='d',xticklabels=knn.classes_, yticklabels=knn.classes_)
ax.set_ylabel('真实')
ax.set_xlabel('预测')
ax.xaxis.set_label_position('top')
ax.xaxis.tick_top()
ax.set_title('混淆矩阵热力图')
这还不是一个完美的新闻主题分类器,这个分类器倾向于将主题预测为"教育"或"文化"。要获得更好的效果,我们可能还需要做很多工作,例如更好的文本预处理和表示,尝试不同的 K 值的效果,甚至利用其它的机器学习算法等。感兴趣的同学可以自己进一步进行尝试。