我正在使用Python的gensim库来进行潜在的语义索引。我遵循了网站上的教程,效果很好。现在我正在尝试对它进行一些修改;我希望每次添加文档时都运行lsi模型。
这是我的代码:
stoplist = set('for a of the and to in'.split())
num_factors=3
corpus = []
for i in range(len(urls)):
print "Importing", urls[i]
doc = getwords(urls[i])
cleandoc = [word for word in doc.lower().split() if word not in stoplist]
if i == 0:
dictionary = corpora.Dictionary([cleandoc])
else:
dictionary.addDocuments([cleandoc])
newVec = dictionary.doc2bow(cleandoc)
corpus.append(newVec)
tfidf = models.TfidfModel(corpus)
corpus_tfidf = tfidf[corpus]
lsi = models.LsiModel(corpus_tfidf, numTopics=num_factors, id2word=dictionary)
corpus_lsi = lsi[corpus_tfidf]
geturls是我编写的函数,它以字符串的形式返回网站的内容。同样,如果我等到处理完所有文档后再执行tfidf和lsi,这是有效的,但这不是我想要的。我想在每次迭代中都这样做。不幸的是,我得到了这个错误:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "streamlsa.py", line 51, in <module>
lsi = models.LsiModel(corpus_tfidf, numTopics=num_factors, id2word=dictionary)
File "/Library/Python/2.6/site-packages/gensim-0.7.8-py2.6.egg/gensim/models/lsimodel.py", line 303, in __init__
self.addDocuments(corpus)
File "/Library/Python/2.6/site-packages/gensim-0.7.8-py2.6.egg/gensim/models/lsimodel.py", line 365, in addDocuments
self.printTopics(5) # TODO see if printDebug works and remove one of these..
File "/Library/Python/2.6/site-packages/gensim-0.7.8-py2.6.egg/gensim/models/lsimodel.py", line 441, in printTopics
self.printTopic(i, topN = numWords)))
File "/Library/Python/2.6/site-packages/gensim-0.7.8-py2.6.egg/gensim/models/lsimodel.py", line 433, in printTopic
return ' + '.join(['%.3f*"%s"' % (1.0 * c[val] / norm, self.id2word[val]) for val in most])
File "/Library/Python/2.6/site-packages/gensim-0.7.8-py2.6.egg/gensim/corpora/dictionary.py", line 52, in __getitem__
return self.id2token[tokenid] # will throw for non-existent ids
KeyError: 1248
通常错误会出现在第二个文档上。我想我明白它在告诉我什么(字典索引不好),我只是不明白为什么。我尝试了很多不同的方法,但似乎都不起作用。有人知道发生了什么事吗?
谢谢!
这是gensim中的一个错误,其中反向id->单词映射被缓存,但在addDocuments()
之后缓存没有得到更新。
它在2011年的这次提交中得到了修复:https://github.com/piskvorky/gensim/commit/b88225cfda8570557d3c72b0820fefb48064a049。
好的,所以我找到了一个解决方案,尽管不是最优的。
如果你用corpora.Dictionary
制作一本字典,然后立即用dictionary.addDocuments
添加文档,一切都会很好。
但是,如果您在这两个调用之间使用字典(通过调用dictionary.doc2bow
或将字典附加到具有id2word
的lsi模型),则您的字典将被"冻结",无法更新。您可以调用dictionary.addDocuments
,它会告诉它已更新,甚至会告诉您新字典有多大,例如:
INFO:dictionary:built Dictionary(6627 unique tokens) from 8 documents (total 24054 corpus positions)
但是当你引用任何一个新的指数时,你会得到一个错误。我不确定这是否是一个错误,或者这是否是有意的(无论出于何种原因),但至少gensim报告成功地将文档添加到字典中这一事实肯定是一个缺陷。
首先,我尝试将任何字典调用放在单独的函数中,在这些函数中只应修改字典的本地副本。嗯,它还是坏了。这对我来说很奇怪,我不知道为什么。
我的下一步是尝试使用copy.copy
传递字典的副本。这是可行的,但显然会占用更多的开销。然而,它将允许您维护语料库和词典的工作副本。不过,对我来说,这里最大的缺点是,这个解决方案不允许我使用filterTokens
删除语料库中只出现过一次的单词,因为这需要修改词典。
我的另一个解决方案只是在每次迭代中重建所有内容(语料库、字典、lsi和tfidf模型)。对于我的小样本数据集,这会给我带来更好的结果,但无法在不产生内存问题的情况下扩展到非常大的数据集。不过,就目前而言,这就是我正在做的事情。
如果任何有经验的gensim用户有更好的(更友好的内存)解决方案,这样我就不会遇到更大数据集的问题,请告诉我!
在doc2bow中,您可以设置allow_update=True,它将在每次迭代doc2bow时自动更新您的字典
http://radimrehurek.com/gensim/corpora/dictionary.html