关闭

Sklearn用户手册(三): 文本数据的处理

标签: sklearn文本处理
412人阅读 评论(1) 收藏 举报
分类:

本次内容:用一堆的法子去处理二十个不同主题下的文档。(数据集:newsgroup posts)

前文为关于安装的balabala,反正我直接下了个anaconda套装。

加载数据集

数据集名称为“Twenty Newsgroups”,关于该数据集的描述:

20 Newsgroups数据集包含了近20000篇新闻文稿,被分成20个不同的主题,最早由Ken Lang为他自己的论文所收集,如今经常被拿来测试机器学习模型,如文本分类或聚类

该数据集可手动下载,然后用sklearn.datasets.load_files函数导入,不过这里我们直接加载它

from sklearn.datasets import fetch_20newsgroups

为了加快训练速度,第一个例子中,只取其中四个主题的文档

categories = ['alt.atheism', 'soc.religion.christian', 'comp.graphics', 'sci.med']
#取训练集,并随机排序,另。。时间稍长
twenty_train = fetch_20newsgroups(subset='train', categories=categories, shuffle=True, random_state=42)

之所以要重新排序,是方便你希望拿一个小样本出来快速验证一下自己的模型时,不至于从头一取大部分都是同一类里的。
返回值是一个类似于字典的objects

print twenty_train.target_names
print len(twenty_train.data),len(twenty_train.filenames)
#还可以看看第一个,全部打印就算了。。
print "\n".join(twenty_train.data[0].split("\n")[:3])
#看看第一条数据的类别
print twenty_train.target_names[twenty_train.target[0]]

提取特征

要让电脑可以去处理文本,那就得把每个文本表示成一个可计算可比较可量化的东西,也就是数值类型的特征向量。对哪一类的数据都是如此。

词袋模型

这应该是最基本的一种方式了,
初始化一个m*n维的X矩阵,就是模型输入值。m为文档的数量,n为下文中词典的长度。
1. 统计任一文档中出现的词,组合成一个词典b,其实就是这所有文档的词汇量汇总了,并且为每个词编号。
2. 对每个文档,查看词典b中的第j个词在文档中是否出现,出现了,则把出现的次数记录在X[i, j]中

由此带来的一个问题是,这个矩阵往往会非常大,如果是20000篇文档中有10000个不同的词,则所占空间为20000*10000*4bytes为8GB RAM。这个一般个人电脑玩不转的。

但是所幸这个矩阵里有很多零值,因为单就一篇文档而言,词汇量还是很有限的。于是大家们就引入了稀疏矩阵的存储方式来解决这个问题。关于此处可见scipy.sparse.

最简单的一个例子:

import numpy as np
from scipy.sparse import csr_matrix
# row记录行号,col记录列号,data为值。如都看数组的第一个元素,0行1列的值为1,以此类推
row = np.array([0, 1, 1, 2, 3, 3])
col = np.array([1, 0, 2, 3, 0, 1])
data = np.array([1, 2, 1, 1, 2, 3])
X = csr_matrix((data, (row, col)), shape=(4, 4))
print X

标记文本

首先,sklearn中有CountVectorizer函数可以直接得到上述文档的稀疏模型

from sklearn.feature_extraction.text import CountVectorizer
count_vect = CountVectorizer()
X_train_counts = count_vect.fit_transform(twenty_train.data)
#看algorithm里词汇表的长度
print count_vect.vocabulary_.get(u'algorithm')

根据词典库以及文档中词语的分布我们可以判断矩阵X的哪个位置是有值的了,不过值取多少却要视情形而定。

  1. 二值特征,即只关心有还是没有,非0即1。听着不太合理,但事实说,有时候效果还不错。
  2. 出现了几次值为几。这就牵涉到了一个问题,如果某一文档本身较长,那它啥词都会显的更多,因此改用词出现的频率,就是出现的次数除以文档总词数啦。也就是常称的tf(term frequencies).

但这也不算完,所谓能体现主题的关键词。那当然是露面次数较少的。这样的词信息量才大。什么时候都说好其实就相当于什么都没说。照如此想,似乎又跟熵的理念比较接近。好吧,回到正题,因此针对这种情况,我们还可以给tf加个权重,即总文档数量与该词出现的文档数量之比。也就是常说的idf(inverse document frequency),当然这个idf的算法又有很多改进,比如取对数约束一下,或者分母加1防止为0的情形,或者光滑一下等等。但是本质上意思还是这么个意思

from sklearn.feature_extraction.text import TfidfTransformer
tf_transformer = TfidfTransformer(use_idf=False)
X_train_tf = tf_transformer.fit_transform(X_train_counts)
#use_idf默认为True
tfidf_transformer = TfidfTransformer()
X_train_tfidf = tfidf_transformer.fit_transform(X_train_counts)

上分类器

有了特征以后,就可以用模型对数据进行分类了,这里选用的是简单高效好用的朴素贝叶斯方法

from sklearn.naive_bayes import MultinominalNB
clf = MultinomialNB().fit(X_train_tfidf, twenty_train.target)

接下来要对测试文档用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])

#利用数据集中提供的测试集来看看准确率
twenty_test = fetch_20newsgroups(subset='test', categories=categories, shuffle=True, random_state=42)
docs_test = twenty_test.data
X_test = count_vect.transform(docs_test)
X_test_tfidf = tfidf_transformer.transform(X_test)
predicted = clf.predict(X_test_tfidf)
accuracy = np.mean(predicted == twenty_test.target)
print accuracy

当然也是可以用前一节说的Gridsearch来帮助选取参数。不过都是纯代码的东西,不想翻了,另外,困了zzz。。

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:3879次
    • 积分:108
    • 等级:
    • 排名:千里之外
    • 原创:1篇
    • 转载:0篇
    • 译文:6篇
    • 评论:1条
    文章分类
    文章存档
    最新评论