gensim教程翻译学习记录(一)

关键概念(Core Concepts)

该教程介绍了gensim中需要理解和使用的基本概念和术语:Documents、Corpora、Vectors以及Model。

import pprint

genism中的核心概念有:

  1. Document:某个文档。
  2. Corpus:语料库。
  3. Vector:文档便利的数学表示。
  4. Model:将向量从一种表示转换为另一种表示的算法。

让我们更详细地查看每一个概念。

文档(Document)

在Gensim中,一个document是文档序列类型(text sequence type)(通常表示为Python 3中的str)的对象。一个document可以是140 个字符的简短推文、单独段落(即期刊文章摘要)、新闻文章或书籍中的任何东西。

document = "Human machine interface for lab abc computer applications"

语料库(Corpus)

一个语料库(corpus)是Document对象的集合。Corpus在Gensim中有两个作用:

  1. Model训练的输入。在训练中,模型使用对应的训练语料库(training corpus)来查找共同的主题和话题,以及初始化模型的内部参数。
    Genism专注于无人监督的模型,因此不需要人工干预,例如昂贵的注释或手工标记文档。

  2. 组织档。训练后,可以使用主题模型从新文档(培训语料库中未看到的文件)中提取主题。
    这样的语料库可以被相似性查询(Similarity Queries)检索,由语义相似性查询,聚类等。

text_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",
]

注意:上例将整个语料库加载到了内存中。实际上,语料库可能会非常大,因此将其加载到内存是不现实的。Gensim通过一次一个文档的流式传输(streaming)来处理这类语料库。详情参见Corpus Streaming – One Document at a Time

这只是为了说明语料库的极小例子。另一个例子可以是莎士比亚编写的所有剧本列表、是所有维基百科文章的列表或者特定感兴趣的人的所有推文。

在收集语料库后,我们通常要进行一些预处理步骤。我们将保持简单,只需删除一些常用的英语单词(如"the")和语料库中只出现一次的单词。在此过程中,我们将数据进行符号表示。符号化(Tokenization)将文档(documents)分解为单词(words)(在此情况下,将空格作为分界器)。

注意:除了小写化和按空格分界外,有更好的方法执行预处理。高效的预处理不在此教程的范围中:如果您感兴趣,请查看gensim.utils.simple_preprocess()函数。

# 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 text_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]
pprint.pprint(processed_corpus)

结果为:

[['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类。该字典定义了我们处理的所有单词的词汇表。

from gensim import corpora

dictionary = corpora.Dictionary(processed_corpus)
print(dictionary)

结果为

Dictionary(12 unique tokens: ['computer', 'human', 'interface', 'response', 'survey']...)

由于我们的语料库很小,gensim.corpora.Dictionary中仅有12个不同的符号。对大型语料库而言,字典中包含成百上千的符号都是很常见的。

向量(Vector)

为了推理语料库中的潜在结构,我们需要一种可以在数学上操作的方式来表示文档。一种方法是将每个文档表示为一个特征向量。比如,单个特征可以被当作问答对:

  1. 单词“splonge”在文档中出现几次?0次。
  2. 文档包含了几个段落?2个。
  3. 文档使用多少种字体?5种。

问题通常仅被表示其整数id(如1,2和3)。文档的表示则变为一系列对,如(1, 0.0), (2, 2.0), (3, 5.0)。这就是稠密向量(dense vector),因为它包含了以上问题的明确回答。

如果我们提前知道所有问题,我们可能会隐式地遗漏它们,并简单地将文档表示为(0, 2, 5)。这个回答序列就是我们文档的向量(在此情况下是一个3维稠密向量)。出于实用目的,只有答案是(或可以转换为)单个浮点数字的问题才允许在Gensim中使用。

实际上,向量经常包含很多0值。为了节约内存,Gensim忽略掉所有值为0的向量元素。上例因此变为(2, 2.0), (3, 5.0)。这称为稀疏向量或词袋向量。在稀疏表示中,所有缺失向量的值都可明确地解析为0.0。

假设问题是一样的,我们可以相互比较两个不同文档的向量。例如,假设我们有两个向量(0.0, 2.0, 5.0)和(0.1, 1.9, 4.9)。因为这两个向量彼此见非常相似,我们可以得出结论:和向量对应的文档也是相似的。当然,这个结论的正确与否取决于我们最初选择的问题的情况。

另一种将文档表示为向量的方法是词袋模型(bag-of-words model)。在词袋模型下,每个文档被表示为包含字典中每个单词频率数的向量。例如,假设我们有一个包含单词['coffee', 'milk', 'sugar', 'spoon']的字典。一个文档包含字符"coffee milk coffee"将被表示为向量[2, 1, 0, 0],其中向量的实体为“coffee”,“milk”,“sugar”和“spoon”(按照顺序)在文档中的出现次数。向量的长度为字典中实体的数量。词袋模型最主要的性质之一是它完全地忽略了被编码文档中的符号顺序,这也是该模型被称为词袋模型的缘由。

我们处理的语料库包含12个不同的单词,这意味着每个文档将会在词袋模型下被表示为一个12维的向量。我们可以使用字典将符号化的文档转变为12维的向量。我们可以查看这些IDs:

pprint.pprint(dictionary.token2id)

结果为:

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

例如,假设我们想要向量化句子“Human computer interaction”(注意该句子不在原始语料库中)。我们使用字典的doc2bow方法为文档创建词袋表示,其返回一个单词计数的稀疏表示:

new_doc = "Human computer interaction"
new_vec = dictionary.doc2bow(new_doc.lower().split())
print(new_vec)

结果为

[(0, 1), (1, 1)]

每个二元组的第一个元素是字典中对应符号的ID,第二个元素是符号的出现次数。

注意“interaction”没有出现在原始的语料库中,因此其不在向量化中。还要注意,此向量仅包含实际出现在文档中的单词。因为任意给定文档只包含字典中许多单词中的几个单词,因此,为了节省空间,在向量化中未出现的单词隐含地被表示为0。

我们可以将整个原始的语料库转化为向量列:

bow_corpus = [dictionary.doc2bow(text) for text in processed_corpus]
pprint.pprint(bow_corpus)

结果为:

[[(0, 1), (1, 1), (2, 1)],
 [(0, 1), (3, 1), (4, 1), (5, 1), (6, 1), (7, 1)],
 [(2, 1), (5, 1), (7, 1), (8, 1)],
 [(1, 1), (5, 2), (8, 1)],
 [(3, 1), (6, 1), (7, 1)],
 [(9, 1)],
 [(9, 1), (10, 1)],
 [(9, 1), (10, 1), (11, 1)],
 [(4, 1), (10, 1), (11, 1)]]

请注意,虽然此列表完全存在于内存中,但在大多数应用程序中,您将需要一个更可扩展的解决方案。幸运的是,Gensim允许您使用能够一次返回单个文档向量的任意迭代器。有关详细信息,请参阅文档。

重要:一个文档和一个向量的区别在于前者是文本,而后者是该文本的便利的数学表示。有时,人们会交替使用这些术语:例如,给定一些任意的文档D,而不是说“对应文本D的向量”,他们只会说“向量D”或“文档D”。这以模棱两可为代价,实现了简洁。

只要您记得文档存在于文档空间,且向量存在于向量空间,上述的模棱两可是可接受的。

重要:根据如何获得表示,两个不同的文档可能具有相同的向量表示。

模型(Model)

我们已经对我们的语料库进行了向量化,现在可以开始使用模型来转换它。我们使用模型做为抽象术语表示一个文档表示到另一个表示的转换。在gensim中,文档被表示为向量,因此模型可以被认为是两个向量空间之间的转换。当模型读取训练语料库(Corpus)时,其在训练是学习变换的细节。

模型的一个简单例子是tf-idf(term frequency–inverse document frequency)。tf-idf模型将向量从词袋表示转换另一个向量空间,该空间根据语料库中每个单词的相对稀有性对频率计数进行加权。

这里有一个简单的例子。让我们初始化tf-idf模型、在我们的语料库上训练以及转换字符“system minors”:

from gensim import models

# train the model
tfidf = models.TfidfModel(bow_corpus)

# transform the "system minors" string
words = "system minors".lower().split()
print(tfidf[dictionary.doc2bow(words)])

结果为:

[(5, 0.5898341626740045), (11, 0.8075244024440723)]

tfidf模型也返回一个二元组列表,其中第一个元素是符号的ID且第二个元素是tf-idf的权重。值得注意的是,“system”(在原始语料库中出现4次)对应的ID的权重低于“minors”(仅出现两次)对应的ID的权重。

您可以将训练后的模型保存到磁盘,并稍后将其加载回来,也可以在新的训练文档继续训练或者转换新的文档。

gensim提供了大量不同的模型/变换。更多细节,请查阅Topics and Transformations.

一旦你创建了模型,你可以用它做各种很酷的事情。例如,为了通过TfIdf转换整个语料库并将其索引,为相似性查询做好准备:

from gensim import similarities

index = similarities.SparseMatrixSimilarity(tfidf[bow_corpus], num_features=12)

为了查询我们问题文档query_document和语料库中每个文档的相似度:

query_document = 'system engineering'.split()
query_bow = dictionary.doc2bow(query_document)
sims = index[tfidf[query_bow]]
print(list(enumerate(sims)))

结果为:

[(0, 0.0), (1, 0.32448703), (2, 0.41707572), (3, 0.7184812), (4, 0.0), (5, 0.0), (6, 0.0), (7, 0.0), (8, 0.0)]

如何读取这个输出?文档3有0.718=72%的相似度得分,文档2有42%的相似度得分等等。我们可以通过排序将结果变得更可读:

for document_number, score in sorted(enumerate(sims), key=lambda x: x[1], reverse=True):
    print(document_number, score)

结果为:

3 0.7184812
2 0.41707572
1 0.32448703
0 0.0
4 0.0
5 0.0
6 0.0
7 0.0
8 0.0

总结(Summary)

genism中的核心概念有:

  1. Document:某个文档。
  2. Corpus:语料库。
  3. Vector:文档便利的数学表示。
  4. Model:将向量从一种表示转换为另一种表示的算法。

我们看到这些概念在起作用。首先,我们从一系列文档开始。接下来,我们将这些文档转换为向量空间表示。之后,我们创建了一个模型,将我们原来的向量表示转换为 TfIdf。最后,我们使用我们的模型计算某些查询文档与语料库中所有文档之间的相似性。

下一步(What Next?)

Corpora and Vector Spaces需要进一步的学习。

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容