为了我自己学习方便,翻译了gensim的官方教程。如有错误,请指正。原文地址
如果想要开启日志,别忘记设置:
- 1
- 2
转换接口
在之前的教程《语料库与向量空间》中,我们创建了一个用向量流表示文档的语料库。为了继续征程,让我们启动gensim并使用该语料库。
- 1
- 2
- 3
- 4
- 5
在本次教程中,我将会向你展示如何将文档从一种向量表示方式转换到另一种。这个处理是为了两个目的:
- 将语料库中隐藏的结构发掘出来,发现词语之间的关系,并且利用这些结构、关系使用一种新的、更有语义价值的(这是我们最希望的)方式描述其中的文档。
- 使得表示方式更加简洁。这样不仅能提高效率(新的表示方法一般消耗较少的资源)还能提高效果(忽略了边际数据趋势、降低了噪音)。
创建一个转换
转换(transformations)是标准的Python类,通常通过训练语料库的方式初始化
- 1
我们使用了前一个教程中用过的语料库来初始化(训练)这个转换模型。不同的转换可能需要不同的初始化参数;在Tfidf案例中,“训练”仅仅是遍历提供的语料库然后计算所有属性的文档频率(译者注:在多少文档中过)。训练其他模型,例如潜在语义分析或隐含狄利克雷分配,更加复杂,因此耗时也多。
作者注:转换常常是在两个特定的向量空间之间进行。训练与后续的转换必须使用相同的向量空间(=有相同的属性,且编号相同)。如若不然,例如使用不同的预处理方法处理字符串、使用不同的属性编号、需要Tfidf向量的时候却输入了词袋向量,将会导致转换过程中属性匹配错误,进而使输出结果无意义并可能引发异常。
转换向量
从现在开始,tfidf将被视为只读的对象,可以用它来转换将任何采用旧表示方法的向量(词袋整数计数)转换为新的表示方法(Tfidf 实数权重):
- 1
- 2
- 3
或者对整个语料库实施转换:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
在这个特殊的情况中,被转换的语料库与用来训练的语料库相同,但是这仅仅是偶然。一旦转换模型被初始化了,它可以用来转换任何向量(当然最好使用与训练语料库相同的向量空间 | 注:即语言环境),即使它们并没有在训练语料库中出现。这是通过潜在语义分析的调入(folding in)、隐含狄利克雷分配的主题推断(topic inference)等得到的。
调用model[corpus]只能在旧的corpus文档流的基础上创建一个包装-真正的转化是在迭代文档时即时计算的。我们可以通过调用corpus_transformed = model[corpus]一次转化整个语料库,因为这样意味着我们要将结果存入内存中,这与gensim内存无关的设计理念不太符合。如果你还要多次迭代转化后的corpus_transformed,负担将会十分巨大。你可以先将结果序列化并存储到硬盘上再做需要的操作。
转换也可以被序列化,还可以一个(转换)叠另一个,像一串链条一样:
- 1
- 2
这里我们利用潜在语义索引(LSI) 将Tf-Idf语料转化为一个潜在2-D空间(2-D是因为我们设置了num_topics=2)。现在你可能想知道:2潜在维度意味着什么?让我们利用models.LsiModel.print_topics()
来检查一下这个过程到底产生了什么变化吧:
- 1
- 2
- 3
(这些主题将会记录在日志中,想要了解如何激活日志,请看开头的注解)
根据LSI来看,“tree”、“graph”、“minors”都是相关的词语(而且在第一主题的方向上贡献最多),而第二主题实际上与所有的词语都有关系。如我们所料,前五个文档与第二个主题的关联更强,而其他四个文档与第一个主题关联最强:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
模型的持久可以借助save()
和load()
函数完成:
- 1
- 2
下一个问题可能就该是:这些文档之间确切的相似度是多少呢?能否将相似性形式化,以便给定一个文档,我们能够根据其他文档与该文档的相似度排序呢?敬请阅读下个教程——《相似度查询》。
可用的转换
Gensim实现了几种常见的向量空间模型算法:
词频-逆文档频(Term Frequency * Inverse Document Frequency, Tf-Idf)
需要一个词袋形式(整数值)的训练语料库来实现初始化。转换过程中,他将会接收一个向量同时返回一个相同维度的向量,在语料库中非常稀有的属性的权重将会提高。因此,他会将整数型的向量转化为实数型的向量,同时让维度不变。而且。你可以选择是否将返回结果标准化至单位长度(欧几里得范数)。
- 1
潜在语义索引(Latent Semantic Indexing,LSI,or sometimes LSA)
将文档从词袋或TfIdf权重空间(更好)转化为一个低维的潜在空间。对于我们上面用到的玩具级的语料库,我们使用了2潜在维度,但是在真正的语料库上,推荐200-500的目标维度为“金标准”。[1]
- 1
LSI训练的独特之处是我们能在任何继续“训练”,仅需提供更多的训练文本。这是通过对底层模型进行增量更新,这个过程被称为“在线训练”。正因为它的这个特性,输入文档流可以是无限大——我们能在以只读的方式使用计算好的模型的同时,还能在新文档到达时一直“喂食”给LSI“消化”!
- 1
- 2
- 3
- 4
- 5
- 6
有关在无限大的流中,如何让LSI逐渐“忘记”旧的观测结果,详情请看gensim.models.lsimodel的帮助文档。如果你不怕麻烦,有几个参数可以控制LSI算法的影响速度、内存占用和数值精度等。
gensim使用一个新颖的在线增量流分布式训练算法(还挺拗口的…),我曾将该方法发表在[5]中。gensim内部执行了一个来自Halko等[4]的随机多通道算法(stochastic multi-pass algorithm)来加速核心(in-core)部分的计算。参考《在英文维基百科上的实验》教程了解如何通过计算机集群分布式计算来提高速度。
随机映射(Random Projections,RP)
目的在于减小空维度。这是一个非常高效(对CPU和内存都很友好)方法,通过抛出一点点随机性,来近似得到两个文档之间的Tfidf距离。推荐目标维度也是成百上千,具体数值要视你的数据集大小而定。
- 1
隐含狄利克雷分配(Latent Dirichlet Allocation, LDA)
也是将词袋计数转化为一个低维主题空间的转换。LDA是LSA(也叫多项式PCA)的概率扩展,因此LDA的主题可以被解释为词语的概率分布。这些分布式从训练语料库中自动推断的,就像LSA一样。相应地,文档可以被解释为这些主题的一个(软)混合(又是就像LSA一样)。
- 1
gensim使用一个基于[2]的快速的在线LDA参数估计实现,修改并使其可以在计算机集群上以分布式模式运行。
分层狄利克雷过程(Hierarchical Dirichlet Process,HDP)
是一个无参数贝叶斯方法(注意:这里没有num_topics参数):
- 1
gensim使用一种基于[3]的快速在线来实现。该算法是新加入gensim的,并且还是一种粗糙的学术边缘产品——小心使用。
增加新的VSM转化(例如新的权重方案)相当平常;参见API参考或者直接参考我们的源代码以获取信息与帮助。
值得一提的是,这些模型增量模型,无需一次将所有的训练语料库全部放到内存中。在关心内存的同时,我还在不断改进分布式计算,来提高CPU效率。如果你自觉能够贡献一份力量(测试、提供用例或代码),请让我知道。
下一个教程,我们将会讲《相似度查询》。