文本分析:初识Gensim

 


作者:doze_worm
来源:https://www.douban.com/note/620615113/

gensim 起步:
本节介绍理解和使用 gensim 所必须的基础概念和术语,并提供一个简单用例。

核心概念和简单样例:
从高层级来看,gensim 是一个通过衡量词组(或更高级结构,如整句或文档)模式来挖掘文档语义结构的工具。gensim 以“文集”——文本文档的集合——作为输入,并生成一个“向量”来表征该文集的文本内容,从而实现语义挖掘。该向量表示可被用于训练一个“模型”。模型是从数据生成不同特征的算法集,通常是更为语义化的。这三个概念是理解 gensim 是如何工作的关键,因此让我们花些时间来对它们分别解释一下。与此同时,我们会完成一个简单示例来刻画这三个概念。

文集:
文集是一组数字文档集合。该集合是 gensim 的输入,它蕴含着所有文档的结构、主题、等等。文集所蕴含的潜在结构可在稍后用于给训练文集中没出现过的新文档设置标题。因此,我们也将这一集合称为训练文集。无需人工干预(如手工标记文档)——主题分类为无监督学习。

我们使用包含9个字符串的列表作为我们的文集,每个字符串由一个单句组成。
In [1]: raw_corpus = ["Human machine interface for lab abc computer applications",
                         "A survey of user opinion of computer system response time",
                         "The EPS user interface management system",
                         "System and human system engineering testing of EPS",
                         "Relation of user perceived response time to error measurement",
                         "The generation of random binary unordered trees",
                         "The intersection graph of paths in trees",
                         "Graph minors IV Widths of trees and well quasi ordering",
                         "Graph minors A survey"]
这只是一个用于演示的非常小的文集样例。我们也可以把莎士比亚的所有戏剧、维基百科的所有文章、或互联网上某人的所有推特作为一个文集样例。

当我们完成文集收集后,有几个典型的处理步骤我们希望完成。为了让文集简练,把一些常规英语单词(如“the”)及只出现一次的单词移除。为进行此步处理,我们将数据符号化。符号化将文档拆分成单词(此处以空格作为分割符)。

In [2]: # Create a set of frequent words
            stoplist = set('for a of the and to in'.split(' '))
            # Lowercase each document, split it by white space and filter out stopwords
            texts = [word for word in document.lower().split() if word not in stoplist]
                     for document in raw_corpus]

            # Count word frequencies
            from collections import defaultdict
            frequency = defaultdict(int)
            for text in texts:
                for token in text:
                    frequency[token] += 1

            # Only keep words that appear more than once
            processed_corpus = [token for token in text if frequency[token] > 1] for text in texts]
            processed_corpus

Out[2]: ['human', 'interface', 'computer'],
              ['survey', 'user', 'computer', 'system', 'response', 'time'],
              ['eps', 'user', 'interface', 'system'],
              ['system', 'human', 'system', 'eps'],
              ['user', 'response', 'time'],
              ['trees'],
              ['graph', 'trees'],
              ['graph', 'minors', 'trees'],
              ['graph', 'minors', 'survey']

进行操作前,我们希望为文集中的每个单词分配一个唯一的 ID。我们可以使用 gensim.corpora.Dictionary 类来实现。该词典定义了我们的处理器知晓的所有单词词表。

In [3]: from gensim import corpora
             dictionary = corpora.Dictionary(processed_corpus)
             print(dictionary)

Out [3]: Dictionary(12 unique tokens:[u'minors', u'graph', u'system', u'trees', u'eps']...)

由于我们的文集很小,词典中只有12个不同符号。对于大的文集,词典中包含10万量级的符号是很寻常的。

向量:
为了表示我们文集中蕴含的潜在结构,我们需要一种可以进行数学运算的表征文档的方法。一种尝试是把文档表示成一个向量。有很多种不同的文档向量特征生成方法,此处简单以“词袋(BOW)模型”为例。在词袋模型下,我们用文档中出现词典里单词的频率的向量来表示一个文档。举例来说:给定一个词典包含['coffee', 'milk', 'sugar', 'spoon'],由以下字符串 "coffee milk coffee"组成的文档可以表示为向量[2, 1, 0, 0]。向量的每个分量(按顺序)是文档中"coffee", "milk", "sugar" 和 "spoon" 出现的次数。向量的长度是词典中词条的数量。词袋模型的一个主要属性是它完全忽略文档中所涉及的单词出现的顺序,这也是词袋这一名字的由来。

我们处理的文集包含有12个独立单词,也就意味着在词袋模型下,每一个文档将以一个12维数组来表示。我们可以用该词典将符号化的文档转换为12维向量。我们看到这些 ID 对应于:
In [4]: print(dictionary.token2id)

Out [4]: {u'minors': 11, u'graph': 10, u'system': 6, u'trees': 9, u'eps': 8, u'computer': 1, u'survey': 5,
             u'user': 7, u'human': 2, u'time': 4, u'interface': 0, u'response': 3}

例如,我们想将短语“Human computer interaction”(注意,该短语不存在于原始的文集中)向量化,我们可以用 doc2bow 方法创建文档在指定词典下的词袋表征。它将返回一个词频的稀疏表示:
In [5]: new_doc = "Human computer interaction"
             new_vec = dictionary.doc2bow(new_doc.lower().split())
             new_vec
Out[5]: [(1, 1), (2, 1)]

每个元组的第一项对应词典中符号的 ID,第二项对应该符号出现的次数。

注1:原始文集中没有 “interaction“,因此它不包含在向量化结果中。
注2:该向量只包含文档中出现的单词条目,是因为任意给定文档只会包含词典中众多单词中的少数几个,向量化结果中不出现的单词则默认次数为0以节约空间。

我们可以将原始文集转换成一个向量列表:
In [6]: bow_corpus = [dictionary.doc2bow(text) for text in processed_corpus]
             bow_corpus
Out[6]: [(0, 1), (1, 1), (2, 1)],
              [(1, 1), (3, 1), (4, 1), (5, 1), (6, 1), (7, 1)],
              [(0, 1), (6, 1), (7, 1), (8, 1)],
              [(2, 1), (6, 2), (8, 1)],
              [(3, 1), (4, 1), (7, 1)],
              [(9, 1)],
              [(9, 1), (10, 1)],
              [(9, 1), (10, 1), (11, 1)],
              [(5, 1), (10, 1), (11, 1)]

注3:上述结果列表完全保存在内存中。而在大多数应用中,你会希望有种更为规模可控的解决方案。很幸运,gensim 允许你使用任意游标来每次访问一个文档。更多细节请查阅文档。

模型:
现在,我们已经向量化了我们的文集,我们可以开始用模型来对它进行转换。我们使用模型作为一个抽象术语,来描述把一个文档表示转换成另一种文档表示的行为。在 Gensim 中,文档用向量表示,因此模型可以被理解为两个向量空间的转换。这一转换的细节是通过对训练文集的学习得到的。

一个模型的简单样例是 tf-idf。tf-idf 模型将词袋表示向量转换到词频权重向量空间,该向量空间中,以文集中每个单词的希缺性的权重替代单词出现的频率计数。
下面是一个简单用例。首先初始化 tf-idf 模型,以我们的文集对它进行训练,并对字符串”system minors“进行转换:

In [7]: from gensim import models
             # train the model
             tfidf = models.TfidfModel(bow_corpus)
             # transform the "system minors" string
             tfidf[dictionary.doc2bow("system minors".lower().split())]

Out[7]: [(6, 0.5898341626740045), (11, 0.8075244024440723)]

tf-idf 模型返回了一个元组列表,元组的第一项是符号 ID,第二项是 tf-idf 权重。这里我们注意到,”system“(在原始文集中出现4次)的 ID 的权重要比”minors“(只出现了2次)的 ID 的权重要低。

gensim 提供了多种不同模型/转换方法。更多细节参考Transformations and Topics

posted @ 2019-08-05 16:02  -零  阅读(567)  评论(0编辑  收藏  举报