本文主要翻译自:https://radimrehurek.com/gensim/tut2.html
这个教程会向大家展示如何将代表文档的向量转换成另一种向量,做这件事的目的主要有两个:
发现语料中的隐藏结构,比如词与词之间的联系,然后用一种全新的方式、一种更能表现语义的方式(semantic way)来描述文档。
使文档的表示更加紧凑,这样可以提高效率和功效,因为新的表达方式消耗更少的资源,并且去除了噪音。
在之前的gensim基础使用中,我们介绍了如何将语料提取特征后转换为向量(基于词袋模型),上一章中的结果:
# 清洗后的语料库,只有九句话,代表九个文档
[['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
{'computer': 0,
'eps': 8,
'graph': 10,
'human': 1,
'interface': 2,
'minors': 11,
'response': 3,
'survey': 4,
'system': 5,
'time': 6,
'trees': 9,
'user': 7}
# 根据词典基于词袋模型,训练上面语料的结果,(0,1.0)的意思是id为0的单词,即“computer”在第一篇文章中出现了1次。其它类似。
[[(0, 1.0), (1, 1.0), (2, 1.0)],
[(0, 1.0), (3, 1.0), (4, 1.0), (5, 1.0), (6, 1.0), (7, 1.0)],
[(2, 1.0), (5, 1.0), (7, 1.0), (8, 1.0)],
[(1, 1.0), (5, 2.0), (8, 1.0)],
[(3, 1.0), (6, 1.0), (7, 1.0)],
[(9, 1.0)],
[(9, 1.0), (10, 1.0)],
[(9, 1.0), (10, 1.0), (11, 1.0)],
[(4, 1.0), (10, 1.0), (11, 1.0)]]
###二、加载上一章中结果(保存的字典和语料向量)
from gensim import corpora, models, similarities
import os
if(os.path.exists('./gensim_out/deerwester.dict')):
dictionary = corpora.Dictionary.load('./gensim_out/deerwester.dict')
corpus = corpora.MmCorpus('./gensim_out/deerwester.mm')
print("使用之前已经存储的字典和语料向量")
else:
print("请先通过上一章生成deerwester.dict和deerwester.mm")
#pprint(dictionary.tokenz`2id)
#pprint(corpus)
转换模型是标准的python对象,通常需要传入一个语料库进行初始化。
我们使用教程1中的旧语料库来初始化(训练)转换模型。也就是上面加载的corpus, 不同的转换模型一般需要不同的初始化参数; 在TfIdf的情况下,“训练”仅包括通过提供的语料库一次并计算其所有词频和逆文档频率。 训练其他模型,例如潜在语义分析或潜在狄利克雷分析,涉及更多,因此也会消耗更多时间。
tfidf = models.TfidfModel(corpus) #初始化一个模型
doc_bow = [(0, 1), (1, 1)]
print(tfidf[doc_bow])#输出:[(0, 0.70710678), (1, 0.70710678)]
上面已经创建了tfidf模型,我们应该将其作为一个只读对象来看待,用它可以将旧的向量表示(上一节中的词袋模型)转换为新的向量表示(比如tf-idf权重)
假设新文本为:“Human computer interaction”
doc_bow是新文本经过上一章的清洗、分词、基于词袋模型转换后的结果,(0, 1)表示id为0,即“computer”。1表示“computer”在新文本中出现了1次;(1, 1)表示id为1,即“human”也出现了1次。
tfidf模型将新文本从词袋向量模型([(0, 1), (1, 1)])转换为了词频-逆文档频率权重向量([(0, 0.70710678), (1, 0.70710678)]),即“computer”的权重为0 0.70710678,“human”的权重为0.70710678
调用model_name[corpus]仅在旧的语料库文档流周围创建一个包装器 ,实际转换在文档迭代期间即时完成。 我们无法在调用corpus_transformed = model [corpus]时转换整个语料库,因为这意味着将结果存储在内存中,这与gensim的内存独立的目标相矛盾。 如果您将多次迭代转换的corpus_transformed,并且转换成本很高,请先将生成的语料库序列化到磁盘然后再使用它。
#用tfidf转换语料库corpus
corpus_tfidf = tfidf[corpus]
#initialize an LSI transformation(初始化LSI模型)
lsi = models.LsiModel(corpus_tfidf, id2word=dictionary, num_topics=2)
#create a double wrapper over the original corpus: bow->tfidf->fold-in-lsicorpus_lsi = lsi[corpus_tfidf]
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"
根据上面结果可以看出“trees”, “graph” and “minors都是相关联的词汇,并且对第一个主题的贡献度最高,第二个主题,更多的是关注其他的词汇
for doc in corpus_lsi:
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"
lsi.save('./gensim_out/model.lsi') #保存 same for tfidf, lda, ...
lsi = models.LsiModel.load('/tmp/model.lsi') #加载
1.Term Frequency * Inverse Document Frequency, Tf-Idf
model = models.TfidfModel(corpus, normalize=True)
2.Latent Semantic Indexing, LSI (or sometimes LSA)
model = models.LsiModel(tfidf_corpus, id2word=dictionary, num_topics=300)
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]
...
3.Random Projections, RP
model = models.RpModel(tfidf_corpus, num_topics=500)
4.Latent Dirichlet Allocation, LDA
model = models.LdaModel(corpus, id2word=dictionary, num_topics=100)
5.Hierarchical Dirichlet Process, HDP
model = models.HdpModel(corpus, id2word=dictionary)