我正在使用Gensim进行一些主题建模,我已经到了使用LSI和tf-idf模型进行相似性查询的地步。我找回了一组ID和相似之处,例如。 (299501, 0.64505910873413086)
。
如何获取与ID相关的文本文档,在本例中为299501?
我查看了语料库,字典,索引和模型的文档,似乎无法找到它。
答案 0 :(得分:3)
可悲的是,据我所知,你必须从分析的最开始知道你想要通过id检索文档。这意味着您需要在ID和原始文档之间创建自己的映射,并确保在整个过程中保留gensim
使用的ID。我认为gensim
不会保留这样的映射。
我肯定是错的,事实上如果有人告诉我有一种更简单的方法,我会喜欢它,但我花了很多时间试图避免在维基百科语料库中重新运行巨大的LSI模型无济于事。最后,我不得不携带一个id列表和相关文档,以便我可以使用gensim
的输出。
答案 1 :(得分:3)
我刚刚经历了同样的过程,并达到了同样的目标,即" sims"有文档ID,但想要我原来的#34;文章代码"。尽管没有完全提供,但整个Gensim库中都有元数据功能,这些示例可以提供帮助。当我记得我必须做的事情时,我会回答这个问题,以防万一这对以前的访问者有任何帮助。
参见gensim.corpora.textcorpus.TextCorpus#get_texts
,它返回文本或简单的单项元数据" linenumber"如果启用了metadata
标志:
def get_texts(self):
"""Iterate over the collection, yielding one document at a time. A document
is a sequence of words (strings) that can be fed into `Dictionary.doc2bow`.
Each document will be fed through `preprocess_text`. That method should be
overridden to provide different preprocessing steps. This method will need
to be overridden if the metadata you'd like to yield differs from the line
number.
Returns:
generator of lists of tokens (strings); each list corresponds to a preprocessed
document from the corpus `input`.
"""
lines = self.getstream()
if self.metadata:
for lineno, line in enumerate(lines):
yield self.preprocess_text(line), (lineno,)
else:
for line in lines:
yield self.preprocess_text(line)
我已经实现了一个自定义的make_corpus.py脚本和一个试用分类器脚本,该脚本使用相似性来查找搜索文档中的相关文档。我为利用该点的元数据所做的更改如下:
在make_corpus脚本中,我将构造函数中的元数据启用到我的TextCorpus子类:
corpus = SysRevArticleCorpus(inp, lemmatize=lemmatize, metadata=True)
我还需要序列化元数据,因为我没有在语料库生成之后立即进行处理(如某些示例所做的那样),因此您还需要在序列化步骤中打开元数据:
MmCorpus.serialize(outp + '_bow.mm', corpus, progress_cnt=10000, metadata=True)
这会使gensim.matutils.MmWriter#write_corpus
使用您的语料库“xxx_bow.mm.metadata.cpickle”
文件保存.mm
个文件。
要在元数据中添加更多项,您需要在TextCorpus子类中实现并覆盖一些内容。我已经基于WikiCorpus示例类创建了一个,因为我有自己的现有语料库来阅读。
构造函数需要接收元数据标志,例如:
def __init__(self, fname, processes=None, lemmatize=utils.has_pattern(),
dictionary=None, metadata=False,
...
self.metadata = metadata
if dictionary is None:
# temporarily disable metadata to make internal dict
metadata_setting = self.metadata
self.metadata = False
self.dictionary = Dictionary(self.get_texts())
self.metadata = metadata_setting
else:
self.dictionary = dictionary
我实际上是从JSON语料库中读书,所以我已经编写了自定义解析器。我的文章有一个"代码"属性是我的规范文档ID。我还想存储"标题",文档正文在"文本"属性。 (这取代了wiki示例中的XML解析)。
def extract_articles(f, filter_namespaces=False):
"""
Extract article from a SYSREV article export JSON = open file-like object `f`.
Return an iterable over (str, str, str) which generates (title, content, pageid) triplets.
"""
elems = (elem for elem in f)
for elem in elems:
yield elem["title"], elem["text"] or "", elem["code"]
这是在被覆盖的get_texts
内调用的(在它提到的父类中,你需要覆盖它以使用自定义元数据)。总结:
def get_texts(self):
...
with open(self.fname) as data_file:
corpusdata = json.load(data_file)
texts = \
((text, self.lemmatize, title, pageid)
for title, text, pageid
in extract_articles(corpusdata['docs'], self.filter_namespaces))
... (skipping pool processing stuff for clarity)
for tokens, title, pageid in pool.imap(process_article, group):
if self.metadata:
yield (tokens, (pageid, title))
else:
yield tokens
因此,这应该让您在corpus.mm文件旁边保存元数据。如果要在以后的脚本中重新阅读它,则需要重新阅读pickle文件 - 似乎没有任何内置方法可以重新读取元数据。幸运的是,它只是一个由Gensim生成的文档ID索引的字典,所以它很容易加载和使用。 (See wiki-sim-search)
e.g。在我的试用版分类器中,我添加了两个内容:metadata = pickle.load()
和metadata[docID]
,以便最终找到原始文章。
# re-load everything...
dictionary = corpora.Dictionary.load_from_text(datapath+'/en_wordids.txt')
corpus = corpora.MmCorpus(datapath +'/xxx_bow.mm')
metadata = pickle.load(open(datapath + 'xxx_bow.mm.metadata.cpickle', 'rb'))
lsiModel = models.LsiModel(corpus, id2word=dictionary, num_topics=4)
index = similarities.MatrixSimilarity(lsiModel[corpus])
# example search
doc = "electronic cognitive simulation"
vec_bow = dictionary.doc2bow(doc.lower().split())
vec_lsi = lsiModel[vec_bow] # convert the query to LSI space
# perform a similarity query against the corpus
sims = index[vec_lsi]
sims = sorted(enumerate(sims), key=lambda item: -item[1])
# Look up the original article metadata for the top hit
(docID, prob) = sims[0]
print(metadata[docID])
# Prints (CODE, TITLE)
('ShiShani2008ProCarNur', 'Jordanian nurses and physicians learning needs for promoting smoking cessation.')
我知道这并没有按照您的要求提供原始文字(我自己也不需要),但您可以非常轻松地将文字添加到&#34 ;元数据" (虽然这相当扩展了元数据的定义,但可能非常大!)。我猜Gensim假设您已经有了一些原始文档的数据库,因此它将超出范围。但是我觉得Gensim生成的ID和原始文档标识符之间需要有一个映射,元数据功能可以很好地完成。