SKlearn Twenty Newsgroups 文本分类数据下载和详细步骤
# 读取数据
# 数据压缩包下载地址 https://ndownloader.figshare.com/files/5975967
# 1.将20newsbydate.tar.gz 放在/data/workspace/test/tf/data/20news_home 目录下,
# 2.修改/usr/local/python3/lib/python3.6/site-packages/sklearn/datasets/twenty_newsgroups.py、
# def _download_20newsgroups(target_dir, cache_path):
# ...
# #logger.info("Downloading dataset from %s (14 MB)", ARCHIVE.url)
# #archive_path = _fetch_remote(ARCHIVE, dirname=target_dir)
# archive_path = os.path.join(target_dir, r"20newsbydate.tar.gz")
# ...
# 3.执行程序会自动解压/data/workspace/test/tf/data/20news_home/20newsbydate.tar.gz,
# 解压出20news-bydate-test,20news-bydate-train
# 并在目录下生成20news-bydate.pkz缓存文件,并删除20newsbydate.tar.gz,20news-bydate-test,
# 20news-bydate-train 这三个文件
# 之后运行程序会一直使用缓存文件20news-bydate.pkz,不需要再下载数据
from sklearn.datasets import fetch_20newsgroups
categories = ['alt.atheism', 'soc.religion.christian','comp.graphics', 'sci.med']
twenty_train = fetch_20newsgroups(data_home='/data/workspace/test/tf/data',subset='train',
categories=categories,shuffle=True,random_state=42)
# 对文本进行分词统计
# 在训练集中每一个出现在任意文中的单词分配一个特定的整数 id(比如,通过建立一个从单词到整数索引的字典)。
# 对于每个文档 #i,计算每个单词 w 的出现次数并将其存储在 X[i, j] 中作为特征 #j 的值,其中 j 是在字典中词 w 的索引。
# (1) 停用词的配置:也可默认配置count_vec=CountVectorizer(stop_words=None) ,stop_words=None表示不去掉停用词;
# 如果是英文的话,停用词不需要构建直接 count_vec=CountVectorizer(stop_words=’english’)则去掉英语停用词
from sklearn.feature_extraction.text import CountVectorizer
count_vect = CountVectorizer()
X_train_counts = count_vect.fit_transform(twenty_train.data)
print(X_train_counts)
# (0, 230) 1 第0个文档,词典中索引为230的元素, 出现次数1
# (0, 12541) 1
# (0, 3166) 1
# (0, 14085) 1
# (0, 20459) 1
# (0, 35416) 1
# (0, 3062) 1
# (0, 2326) 2
# (0, 177) 2
print("shape",X_train_counts.shape)
# shape (2257, 35788)
print("------------------------------------------------------------------")
#词频
# 出现次数的统计是非常好的开始,但是有个问题:长的文本相对于短的文本有更高的单词平均出现次数,
# 尽管他们可能在描述同一个主题。为了避免这些潜在的差异,只需将各文档中每个单词的出现次数除以该文档中所有单词的总数:
# 这些新的特征称之为词频 tf (Term Frequencies)。
# 另一个在词频的基础上改良是,降低在该训练文集中的很多文档中均出现的单词的权重,从而突出那些仅在该训练文集中在
# 一小部分文档中出现的单词的信息量。这种方法称为 tf–idf ,全称为 “Term Frequency times Inverse Document Frequency” 。
from sklearn.feature_extraction.text import TfidfTransformer
# tf_transformer = TfidfTransformer(use_idf=False).fit(X_train_counts)
# X_train_tf = tf_transformer.transform(X_train_counts)
# print(X_train_tf)
tfidf_transformer = TfidfTransformer()
X_train_tfidf = tfidf_transformer.fit_transform(X_train_counts)
print(X_train_tfidf)
# (0, 35416) 0.1348710554299733 第0个文档,词典中索引为35416的元素,词频0.1348710554299733
# (0, 35312) 0.0312703097833574
# (0, 34775) 0.034481472140846715
# (0, 34755) 0.043341654399042764
# (0, 33915) 0.0999409997803694
# (0, 33597) 0.06567578043186388
# (0, 33572) 0.09313007554599557
# (0, 33256) 0.11819702490105698
# (0, 32493) 0.07283773941616518
print("shape",X_train_tfidf.shape)
# shape (2257, 35788)
print("------------------------------------------------------------------")
#朴素贝叶斯分类
# 现在我们有了我们的特征,我们可以训练一个分类器来预测一个帖子所属的类别。 让我们从 朴素贝叶斯 分类器开始.
# 该分类器为该任务提供了一个好的基准(baseline). scikit-learn 包含了该分类器的若干变种;
# 最适用在该问题上的变种是多项式分类器:
from sklearn.naive_bayes import MultinomialNB
clf = MultinomialNB().fit(X_train_tfidf, twenty_train.target)
# 为了尝试预测新文档所属的类别,我们需要使用和之前同样的步骤来抽取特征。
# 不同之处在于,我们在transformer调用 transform 而不是 fit_transform ,因为这些特征已经在训练集上进行拟合了:
docs_new = ['God is love', 'OpenGL on the GPU is fast']
X_new_counts = count_vect.transform(docs_new)
X_new_tfidf = tfidf_transformer.transform(X_new_counts)
predicted = clf.predict(X_new_tfidf)
for doc, category in zip(docs_new, predicted):
print('%r => %s' % (doc, twenty_train.target_names[category]))
# 在测试集上的性能评估
import numpy as np
twenty_test = fetch_20newsgroups(data_home='/data/workspace/test/tf/data',subset='test',
categories=categories, shuffle=True, random_state=42)
docs_test = twenty_test.data
# 为了使得 向量化(vectorizer) => 转换器(transformer) => 分类器(classifier) 过程更加简单,
# scikit-learn 提供了一个 Pipeline 类,操作起来像一个复合分类器:
# 名称 vect, tfidf 和 clf (分类器)都是任意的。
from sklearn.pipeline import Pipeline
# 朴素贝叶斯 MultinomialNB在测试集上的性能评估
text_clf = Pipeline([('vect', CountVectorizer()),
('tfidf', TfidfTransformer()),
('clf', MultinomialNB()),])
text_clf.fit(twenty_train.data, twenty_train.target)
predicted = text_clf.predict(docs_test)
print(np.mean(predicted == twenty_test.target))
# 支持向量机(SVM) SGDClassifier 在测试集上的性能评估
# 1..SGD主要应用在大规模稀疏数据问题上,经常用在文本分类及自然语言处理。假如数据是稀疏的,
# 该模块的分类器可轻松解决如下问题:超过10^5的训练样本、超过10^5的features。利用梯度来求解参数。
# 2.损失函数
# loss=”hinge”: (soft-margin) 线性SVM.
# loss=”modified_huber”: 带平滑的hinge loss.
# loss=”log”: logistic 回归
# 3.通过penalty参数,可以设置对应的惩罚项。SGD支持下面的罚项:
# penalty=”l2”: 对coef_的L2范数罚项
# penalty=”l1”: 对coef_的L1范数罚项
# penalty=”elasticnet”: L2和L1的convex组合; (1 - l1_ratio) * L2 + l1_ratio * L1
from sklearn.linear_model import SGDClassifier
text_clf = Pipeline([('vect', CountVectorizer()),
('tfidf', TfidfTransformer()),
('clf', SGDClassifier(loss='hinge',penalty='l2',
alpha=1e-3, random_state=42,
max_iter=5, tol=None)),])
text_clf.fit(twenty_train.data, twenty_train.target)
predicted = text_clf.predict(docs_test)
print(np.mean(predicted == twenty_test.target))
# KNN KNeighborsClassifier 在测试集上的性能评估
from sklearn.neighbors import KNeighborsClassifier
text_clf = Pipeline([('vect', CountVectorizer()),
('tfidf', TfidfTransformer()),
('clf', KNeighborsClassifier()),])
text_clf.fit(twenty_train.data, twenty_train.target)
predicted = text_clf.predict(docs_test)
print(np.mean(predicted == twenty_test.target))
运行结果: