Получить строчную версию документа по ID в Gensim

Я использую Gensim для моделирования некоторых тем, и я дошел до того, что делаю похожие запросы с использованием моделей LSI и tf-idf. Я возвращаю набор идентификаторов и сходств, например. (299501, 0.64505910873413086) .

Как получить текстовый документ, связанный с идентификатором, в данном случае 299501?

Я просмотрел документы для корпуса, словаря, индекса и модели и не могу найти его.

К сожалению, насколько я могу судить, вам нужно начинать с самого начала анализа, зная, что вы захотите получить документы с помощью идентификаторов. Это означает, что вам необходимо создать собственное сопоставление между идентификаторами и исходными документами и убедиться, что использование ids gensim сохраняется на протяжении всего процесса. Как и я, я не думаю, что gensim сохраняет такое отображение.

Я определенно ошибаюсь, и на самом деле мне бы это понравилось, если бы кто-то сказал мне, что есть более простой способ, но я потратил много часов, пытаясь избежать повторного запуска гигантской модели LSI на корпусе википедии безрезультатно. В конце концов мне пришлось переносить список идентификаторов и связанных документов, чтобы я мог использовать gensim .

Я только что прошел один и тот же процесс и достиг той же точки, что и «симы» с идентификатором документа, но хочу получить свой оригинальный «код статьи». Хотя это не предусмотрено полностью, в библиотеке 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” с вашими файлами corpus .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, поэтому я уже написал собственный парсер. Мои статьи имеют свойство «code», которое является моим каноническим идентификатором документа. Я также хочу сохранить «title», а тело документа находится в «текстовом» свойстве. (Это заменяет синтаксический анализ 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 из переопределенных 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, поэтому его легко загружать и использовать. ( См. Wiki-sim-search )

например, в моем metadata = pickle.load() классификаторе, я добавил две вещи: 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.') 

Я знаю, что это не дает исходный текст, как вы просили (мне он не нужен сам), но вы могли бы легко добавить текст в «метаданные» (хотя это довольно растягивает определение метаданных и может быть очень большим !). Я предполагаю, что Генсим предполагает, что у вас уже будет база данных ваших исходных документов, и поэтому она будет недоступна. Однако я чувствую, что должно быть сопоставление между идентификаторами, генерируемыми Gensim, и оригинальными идентификаторами документа, которые функция метаданных выполняет достаточно хорошо.