# 主题和转换
别忘了设置
```py
>>> import logging
>>> logging.basicConfig(format='%(asctime)s : %(levelname)s : %(message)s', level=logging.INFO)
```
如果你想看到记录事件。
## [转换接口](https://radimrehurek.com/gensim/tut2.html#transformation-interface "永久链接到这个标题")
在上一篇关于[Corpora和Vector Spaces的](https://radimrehurek.com/gensim/tut1.html)教程中,我们创建了一个文档语料库,表示为向量流。要继续,让我们启动gensim并使用该语料库:
```py
>>> from gensim import corpora, models, similarities
>>> if (os.path.exists("/tmp/deerwester.dict")):
>>> dictionary = corpora.Dictionary.load('/tmp/deerwester.dict')
>>> corpus = corpora.MmCorpus('/tmp/deerwester.mm')
>>> print("Used files generated from first tutorial")
>>> else:
>>> print("Please run first tutorial to generate data set")
```
MmCorpus(9个文件,12个特征,28个非零项)
在本教程中,我将展示如何将文档从一个矢量表示转换为另一个矢量表示。这个过程有两个目标:
1. 为了在语料库中显示隐藏的结构,发现单词之间的关系并使用它们以新的(希望)更加语义的方式描述文档。
2. 使文档表示更紧凑。这既提高了效率(新表示消耗更少的资源)和功效(边际数据趋势被忽略,降噪)。
### [创建转换](https://radimrehurek.com/gensim/tut2.html#creating-a-transformation "永久链接到这个标题")
转换是标准的Python对象,通常通过*训练语料库进行*初始化:
```py
>>> tfidf = models.TfidfModel(corpus) # step 1 -- initialize a model
```
我们使用教程1中的旧语料库初始化(训练)转换模型。不同的转换可能需要不同的初始化参数; 在TfIdf的情况下,“训练”仅包括通过提供的语料库一次并计算其所有特征的文档频率。训练其他模型,例如潜在语义分析或潜在Dirichlet分配,涉及更多,因此需要更多时间。
注意
转换总是在两个特定的向量空间之间转换。必须使用相同的向量空间(=同一组特征id)进行训练以及后续的向量转换。无法使用相同的输入要素空间,例如应用不同的字符串预处理,使用不同的特征ID,或使用预期为TfIdf向量的词袋输入向量,将导致转换调用期间的特征不匹配,从而导致垃圾中的任何一个输出和/或运行时异常。
### [变换向量](https://radimrehurek.com/gensim/tut2.html#transforming-vectors "永久链接到这个标题")
从现在开始,`tfidf` 被视为一个只读对象,可用于将任何向量从旧表示(bag-of-words整数计数)转换为新表示(TfIdf实值权重):
```py
>>> doc_bow = [(0, 1), (1, 1)]
>>> print(tfidf[doc_bow]) # step 2 -- use the model to transform vectors
[(0, 0.70710678), (1, 0.70710678)]
```
或者将转换应用于整个语料库:
```py
>>> corpus_tfidf = tfidf[corpus]
>>> for doc in corpus_tfidf:
... print(doc)
[(0, 0.57735026918962573), (1, 0.57735026918962573), (2, 0.57735026918962573)]
[(0, 0.44424552527467476), (3, 0.44424552527467476), (4, 0.44424552527467476), (5, 0.32448702061385548), (6, 0.44424552527467476), (7, 0.32448702061385548)]
[(2, 0.5710059809418182), (5, 0.41707573620227772), (7, 0.41707573620227772), (8, 0.5710059809418182)]
[(1, 0.49182558987264147), (5, 0.71848116070837686), (8, 0.49182558987264147)]
[(3, 0.62825804686700459), (6, 0.62825804686700459), (7, 0.45889394536615247)]
[(9, 1.0)]
[(9, 0.70710678118654746), (10, 0.70710678118654746)]
[(9, 0.50804290089167492), (10, 0.50804290089167492), (11, 0.69554641952003704)]
[(4, 0.62825804686700459), (10, 0.45889394536615247), (11, 0.62825804686700459)]
```
在这种特殊情况下,我们正在改变我们用于训练的同一语料库,但这只是偶然的。一旦初始化了转换模型,它就可以用在任何向量上(当然它们来自相同的向量空间),即使它们根本没有用在训练语料库中。这是通过LSA的折叠过程,LDA的主题推断等来实现的。
> 注意
调用`model[corpus]`仅在旧`corpus` 文档流周围创建一个包装器- 实际转换在文档迭代期间即时完成。我们无法在调用 `corpus_transformed = model[corpus]` 时转换整个语料库,因为这意味着将结果存储在主存中,这与gensim的内存独立目标相矛盾。如果您将多次迭代转换,并且转换成本[很高,请先将生成的语料库序列化为磁盘](https://radimrehurek.com/gensim/tut1.html#corpus-formats)并继续使用它。
转换也可以序列化,一个在另一个之上,在一个链中:
```py
>>> lsi = models.LsiModel(corpus_tfidf, id2word=dictionary, num_topics=2) # initialize an LSI transformation
>>> corpus_lsi = lsi[corpus_tfidf] # create a double wrapper over the original corpus: bow->tfidf->fold-in-lsi
```
在这里,我们通过[潜在语义索引](https://en.wikipedia.org/wiki/Latent_semantic_indexing)将我们的Tf-Idf语料库 转换为潜在的2-D空间(因为我们设置了2-D `num_topics=2`)。现在你可能想知道:这两个潜在的维度代表什么?让我们检查一下`models.LsiModel.print_topics()`:
```py
>>> lsi.print_topics(2)
topic #0(1.594): -0.703*"trees" + -0.538*"graph" + -0.402*"minors" + -0.187*"survey" + -0.061*"system" + -0.060*"response" + -0.060*"time" + -0.058*"user" + -0.049*"computer" + -0.035*"interface"
topic #1(1.476): -0.460*"system" + -0.373*"user" + -0.332*"eps" + -0.328*"interface" + -0.320*"response" + -0.320*"time" + -0.293*"computer" + -0.280*"human" + -0.171*"survey" + 0.161*"trees"
```
(主题打印到日志 - 请参阅本页顶部有关激活日志记录的说明)
根据LSI的说法,“树”,“图”和“未成年人”都是相关词(并且对第一个主题的方向贡献最大),而第二个主题实际上与所有其他词有关。正如所料,前五个文件与第二个主题的关联性更强,而剩下的四个文件与第一个主题相关:
```py
>>> for doc in corpus_lsi: # both bow->tfidf and tfidf->lsi transformations are actually executed here, on the fly
... print(doc)
[(0, -0.066), (1, 0.520)] # "Human machine interface for lab abc computer applications"
[(0, -0.197), (1, 0.761)] # "A survey of user opinion of computer system response time"
[(0, -0.090), (1, 0.724)] # "The EPS user interface management system"
[(0, -0.076), (1, 0.632)] # "System and human system engineering testing of EPS"
[(0, -0.102), (1, 0.574)] # "Relation of user perceived response time to error measurement"
[(0, -0.703), (1, -0.161)] # "The generation of random binary unordered trees"
[(0, -0.877), (1, -0.168)] # "The intersection graph of paths in trees"
[(0, -0.910), (1, -0.141)] # "Graph minors IV Widths of trees and well quasi ordering"
[(0, -0.617), (1, 0.054)] # "Graph minors A survey"
```
使用`save()`和`load()`函数实现模型持久性:
```py
>>> lsi.save('/tmp/model.lsi') # same for tfidf, lda, ...
>>> lsi = models.LsiModel.load('/tmp/model.lsi')
```
接下来的问题可能是:这些文件之间的相似程度如何?有没有办法形式化相似性,以便对于给定的输入文档,我们可以根据它们的相似性订购一些其他文档?[下一个教程](https://radimrehurek.com/gensim/tut3.html)将介绍相似性查询。
## [可用的转换](https://radimrehurek.com/gensim/tut2.html#available-transformations "永久链接到这个标题")
gensim实现了几种流行的矢量空间模型算法:
* [术语频率*反向文档频率,Tf-Idf](https://en.wikipedia.org/wiki/Tf%E2%80%93idf) 期望初始化期间的词袋(整数值)训练语料库。在变换期间,它将采用向量并返回具有相同维度的另一个向量,除了在训练语料库中罕见的特征将增加其值。因此,它将整数值向量转换为实值向量,同时保持维度的数量不变。它还可以任选地将得到的矢量归一化为(欧几里得)单位长度。
`>>> model = models.TfidfModel(corpus, normalize=True)`
* [潜在语义索引,LSI(或有时LSA)](https://en.wikipedia.org/wiki/Latent_semantic_indexing) 将文档从单词袋或(优选地)TfIdf加权空间转换为较低维度的潜在空间。对于上面的玩具语料库,我们只使用了2个潜在维度,但在实际语料库中,建议将200-500的目标维度作为“黄金标准” [[1]](https://radimrehurek.com/gensim/tut2.html#id6)。
`>>> model = models.LsiModel(tfidf_corpus, id2word=dictionary, num_topics=300)`
LSI培训的独特之处在于我们可以随时继续“培训”,只需提供更多培训文件即可。这是通过在称为在线培训的过程中对底层模型的增量更新来完成的。由于这个特性,输入文档流甚至可能是无限的 - 只需在LSI新文档到达时继续提供它们,同时使用计算的转换模型作为只读!
```py
>>> model.add_documents(another_tfidf_corpus) # now LSI has been trained on tfidf_corpus + another_tfidf_corpus
>>> lsi_vec = model[tfidf_vec] # convert some new document into the LSI space, without affecting the model
>>> ...
>>> model.add_documents(more_documents) # tfidf_corpus + another_tfidf_corpus + more_documents
>>> lsi_vec = model[tfidf_vec]
>>> ...
```
有关[`gensim.models.lsimodel`](https://radimrehurek.com/gensim/models/lsimodel.html#module-gensim.models.lsimodel "gensim.models.lsimodel:潜在语义索引")如何使LSI逐渐“忘记”无限流中的旧观察的详细信息,请参阅文档。如果你想变脏,还有一些你可以调整的参数会影响速度与内存占用量和LSI算法的数值精度。
gensim使用了一种新颖的在线增量流分布式训练算法(相当满口!),我在[[5]中](https://radimrehurek.com/gensim/tut2.html#id10)发表过。gensim还执行Halko等人的随机多遍算法。[[4]](https://radimrehurek.com/gensim/tut2.html#id9)内部,加速核心部分的计算。另请参阅[英语维基百科上的实验,](https://radimrehurek.com/gensim/wiki.html)以便通过在计算机集群中分配计算来进一步提高速度。
* [随机投影,RP](http://www.cis.hut.fi/ella/publications/randproj_kdd.pdf)旨在减少向量空间维度。这是一种非常有效的(内存和CPU友好的)方法,通过投入一点随机性来近似文档之间的TfIdf距离。建议的目标维度再次为数百/数千,具体取决于您的数据集。
`>>> model = models.RpModel(tfidf_corpus, num_topics=500)`
* [Latent Dirichlet Allocation,LDA](https://en.wikipedia.org/wiki/Latent_Dirichlet_allocation) 是另一种从词袋计数转变为低维度主题空间的转变。LDA是LSA(也称为多项PCA)的概率扩展,因此LDA的主题可以解释为对单词的概率分布。与LSA一样,这些分布也是从训练语料库中自动推断出来的。文档又被解释为这些主题的(软)混合(再次,就像LSA一样)。
`>>> model = models.LdaModel(corpus, id2word=dictionary, num_topics=100)`
gensim使用基于[[2]](https://radimrehurek.com/gensim/tut2.html#id7)的在线LDA参数估计的快速实现,修改为在计算机集群上以[分布式模式](https://radimrehurek.com/gensim/distributed.html)运行。
* [分层Dirichlet过程,HDP](http://jmlr.csail.mit.edu/proceedings/papers/v15/wang11a/wang11a.pdf) 是一种非参数贝叶斯方法(请注意缺少的请求主题数):
`>>> model = models.HdpModel(corpus, id2word=dictionary)`
gensim使用基于[[3]](https://radimrehurek.com/gensim/tut2.html#id8)的快速在线实现。HDP模型是gensim的新成员,并且在学术方面仍然很粗糙 - 谨慎使用。
添加新的VSM转换(例如不同的加权方案)相当简单; 有关更多信息和示例,请参阅[API参考](https://radimrehurek.com/gensim/apiref.html)或直接参阅[Python代码](https://github.com/piskvorky/gensim/blob/develop/gensim/models/tfidfmodel.py)。
值得重申的是,这些都是独特的**增量**实现,不需要整个训练语料库一次性存在于主存储器中。有了内存,我现在正在改进[分布式计算](https://radimrehurek.com/gensim/distributed.html),以提高CPU效率。如果您认为自己可以做出贡献(通过测试,提供用例或代码),请[告诉我们](mailto:radimrehurek%40seznam.cz)。
继续阅读下一个关于[相似性查询的](https://radimrehurek.com/gensim/tut3.html)教程。
---
[[1]](https://radimrehurek.com/gensim/tut2.html#id1) 布拉德福德。2008.对大规模潜在语义索引应用程序所需维度的实证研究。
[[2]](https://radimrehurek.com/gensim/tut2.html#id4) 霍夫曼,布莱,巴赫。2010.潜在Dirichlet分配的在线学习。
[[3]](https://radimrehurek.com/gensim/tut2.html#id5) 王,佩斯利,布莱。2011.层级Dirichlet过程的在线变分推理。
[[4]](https://radimrehurek.com/gensim/tut2.html#id3) Halko,Martinsson,Tropp。2009.找到随机性的结构。
[[5]](https://radimrehurek.com/gensim/tut2.html#id2) Řehůřek。2011.潜在语义分析的子空间跟踪。