(本文所使用的 Python 库和版本号: Python 3.6, Numpy 1.14, scikit-learn 0.19, matplotlib 2.2, NLTK 3.3)
前面我们学习了很多用 NLP 进行文本的分词, 文本分块, 创建词袋模型等, 这些步骤可以认为是 NLP 文本处理的基础, 此处我们来看 NLP 的一个非常重要的应用, 对文本使用监督学习进行自动分类.
1. 20 Newsgroups 数据集介绍
本文要使用 NLP 中非常经典的一个数据集: 20 Newsgroups. 这个数据集是国际标准数据集之一, 专门用于文本分类, 文本挖掘, 和信息检索等领域, 类似于传统机器学习所用的 Iris 鸢尾花数据集一样, 可以通过官方网址 http://qwone.com/~jason/20Newsgroups/ 来下载和了解具体内容.
20 Newsgroups 包含有 20 个类别的已经标注好的样本, 总样本数量大约 2 万. 这 20 个类别分别为:
这个数据集有三个版本, 其主要内容和区别为:
: 最原始的没有修改过的一个版本.
: bydate 版本, 按照时间分类, 分为训练集 (60%) 和测试集 (40%) 两部分, 不包含重复文档和新闻组名. 一共有 18846 个样本(或称为文档)
: 不包含重复样本, 只有来源和主题, 一共有 18828 个样本.
sklearn 中有两种加载方式, 第一种是 sklearn.dataset.fetch_20newsgroups, 返回一个可以被文本特征提取器 (CountVectorizer) 自定义参数提取特征的原始文本序列, 第二种是 sklearn.datasets.fetch_20newsgroups_vectorized, 返回一个已提取特征的文本序列, 即不需要使用特征提取器.
注: 以上内容主要参考博客
此处我们只下载第二个版本, 下载后得到 20news-bydate.tar.gz 文件, 解压后得到两个文件夹, 如下:
这两个文件夹每一个都有 20 个子文件夹, 对应于 20 个不同类别. 每个类别下面有几百个文档, 即样本, 每个文档都不长, 比如一个文档 (样本) 的内容为:
这个数据集的加载方式已经被 sklearn 集成到代码中了, 主要的接口是 sklearn.dataset.fetch_20newsgroups, 其默认加载第二个版本. 这个函数的参数有: subset 有三个选择 train,test,all, 选择数据的类型. category 是选择新闻的类型, remove 是可以选择去除 ('headers', 'footers', 'quotes') 这三个文章的选项. 其他不重要.
- # 认识 20newsgroups 数据集
- from sklearn.datasets import fetch_20newsgroups
- # dataset=fetch_20newsgroups(subset='all')
- # 自动下载第二个版本 20news-bydate.tar.gz
- # print(len(dataset.data)) # dataset_X 的样本数
- # print(dataset.target_names) # dataset_y 的名称, 标签名称
- # train_set=fetch_20newsgroups(subset='train') # 仅仅提取中间的 train set
- # test_set=fetch_20newsgroups(subset='test')
- # 如果仅仅需要其中的某几个类别, 可以用
- sample_cate = ['alt.atheism', 'soc.religion.christian',
- 'comp.graphics', 'sci.med', 'rec.sport.baseball'] # 只取 5 个类别
- train_set = fetch_20newsgroups(subset='train',categories=sample_cate,
- shuffle=True, random_state=42,
- remove = ('headers', 'footers', 'quotes'))
- test_set = fetch_20newsgroups(subset='test', categories=sample_cate,
- shuffle=True, random_state=42,
- remove = ('headers', 'footers', 'quotes'))
- print(len(train_set.data), len(test_set.data)) # 2854 1899
- print(train_set.target_names) # 只有五个类别
------------------------------------- 输 --------- 出 --------------------------------
2854 1899 ['alt.atheism', 'comp.graphics', 'rec.sport.baseball', 'sci.med', 'soc.religion.christian']
-------------------------------------------- 完 -------------------------------------
2. 构建分类器
2.1 准备数据集
- # 1, 准备数据集
- category_map = {'misc.forsale': 'Sales', 'rec.motorcycles': 'Motorcycles',
- 'rec.sport.baseball': 'Baseball', 'sci.crypt': 'Cryptography',
- 'sci.space': 'Space'}
- from sklearn.datasets import fetch_20newsgroups
- train_set=fetch_20newsgroups(subset='train',categories=category_map.keys(),
- shuffle=True,random_state=42,
- remove = ('headers', 'footers', 'quotes'))
- test_set=fetch_20newsgroups(subset='test',categories=category_map.keys(),
- shuffle=True,random_state=42,
- remove = ('headers', 'footers', 'quotes'))
- # 获取到的 train_set 包含有 2968 个样本,
- print('train sample num:', len(train_set.data)) # 2968
- print(train_set.target_names) # 确保是我们要提取的这五个类别
- print('test sample num:', len(test_set.data)) # 1975
-------------- 输 --------- 出 ----------
train sample num: 2968 ['misc.forsale', 'rec.motorcycles', 'rec.sport.baseball', 'sci.crypt', 'sci.space'] test sample num: 1975
------------------- 完 -----------------
2.2 特征提取
此处我们用 TfidfVectorizer 来进行特征提取, 关于 TfidfVectorizer 可以参考我的上一篇文章[火炉炼 AI] 机器学习 038-NLP 创建词袋模型 https://www.cnblogs.com/RayDean/p/9767001.html .
直接上代码:
- from sklearn.feature_extraction.text import TfidfVectorizer
- vectorizer = TfidfVectorizer(stop_words='english',lowercase=True)
- train_vector = vectorizer.fit_transform(train_set.data)
- print(train_vector.shape) # (2968, 31206)
- # 此处相当于有 2968 个词袋, 对这些词袋进行 TfidfVectorizer 进行特征提取,
- # 得到最具典型的一些单词, 这些单词的个数有 31206 个, 故而得到 (2968, 30206) 矩阵
- # 矩阵中的元素表示这个单词在该词袋中出现的 tf-idf 权重, 值越大, 表示该单词越重要.
2.3 定义模型, 训练模型
- # 定义模型, 训练特征
- from sklearn.naive_bayes import MultinomialNB
- classifier=MultinomialNB(alpha=.01, fit_prior = False)
- classifier.fit(train_vector,train_set.target)
2.4 查看模型在测试集上的表现
- # 查看这个数据集在 test_set 上的表现
- from sklearn import metrics
- test_vector=vectorizer.transform(test_set.data)
- print(test_vector.shape)
- pred=classifier.predict(test_vector)
- F1_score=metrics.f1_score(test_set.target, pred, average='micro')
- print('test set F1 score:',F1_score)
------------------ 输 --------- 出 -------------
(1975, 31206) test set F1 score: 0.8774683544303797
------------------------- 完 ----------------
3. 用 GridSearch 优化参数
- # 用 GridSearchCV 优化参数
- from sklearn.model_selection import GridSearchCV
- from sklearn.metrics import classification_report
- parameters = {
- 'fit_prior':(True, False), 'alpha':(0.01,0.05,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0)
- }
- clf = GridSearchCV(classifier,parameters,cv=5,scoring='precision_macro',n_jobs=-1)
- clf.fit(train_vector, train_set.target)
- print("Best param_set found on train set: {}".format(clf.best_params_))
- print("Detailed classification report on test set:")
- y_true, y_pred = test_set.target, clf.predict(test_vector)
- print(classification_report(y_true, y_pred))
------------------------------------- 输 --------- 出 --------------------------------
- Best param_set found on train set: {'alpha': 0.05, 'fit_prior': True} Detailed classification report on test set: precision recall f1-score support
- 0 0.92 0.89 0.91 390
- 1 0.80 0.91 0.85 398
- 2 0.93 0.88 0.91 397
- 3 0.90 0.88 0.89 396
- 4 0.91 0.88 0.89 394
avg / total 0.89 0.89 0.89 1975
-------------------------------------------- 完 -------------------------------------
从分类报告中可以看出, 结果最好的是第 0 类和第 2 类, F1 为 0.91, 最差的是第 1 类, F1 值只有 0.85.
######################## 小 ********** 结 ###############################
1, 用 NLP 进行文本分类, 和传统机器学习的主要区别在于前面特征的提取, 一旦提取特征, 后面模型的建立, 训练, 测试, 分类报告等都一样.
2, 对文本进行特征的提取有两种: CountVectorizer 和 TfidfVectorizer, 但是 TfidfVectorizer 使用的最多, 对文本量非常大的情况更加准确, 故而此处我只用 TfidfVectorizer 来提取特征.
3, 有一个地方很容易忽视: 测试集在用 predict 之前, 一定要用 vectorizer.transform 进行转换, 这个过程就像是对数据进行归一化等, 需要对 train_X 和 test_X 都要进行处理.
#################################################################
注: 本部分代码已经全部上传到 (我的 GitHub https://github.com/RayDean/MachineLearning ) 上, 欢迎下载.
来源: https://juejin.im/post/5bc6e5dff265da0ab2285b9b