Doc2Vec: Сходство между закодированными документами и невидимыми документами

У меня есть образец ~60000 документов. 700 из них мы закодировали вручную как имеющие определенный тип контента. Теперь мы бы хотели найти "наиболее похожие" документы на 700, которые мы уже написали вручную. Мы используем gensim doc2vec, и я не могу найти лучший способ сделать это.

Вот как выглядит мой код:

cores = multiprocessing.cpu_count()

model = Doc2Vec(dm=0, vector_size=100, negative=5, hs=0, min_count=2, sample=0, 
        epochs=10, workers=cores, dbow_words=1, train_lbls=False)

all_docs = load_all_files() # this function returns a named tuple
random.shuffle(all_docs)
print("Docs loaded!")
model.build_vocab(all_docs)
model.train(all_docs, total_examples=model.corpus_count, epochs=5)

Я не могу понять, как правильно идти вперед. Это то, что может сделать doc2vec? В конце я хотел бы получить ранжированный список из 60 000 документов, где первый является "наиболее похожим" документом.

Спасибо за любую помощь! Я потратил много времени, читая справочные документы Gensim и различные учебные пособия, и не смог понять это.

РЕДАКТИРОВАТЬ: я могу использовать этот код, чтобы получить документы, наиболее похожие на короткое предложение:

token = "words associated with my research questions".split()
new_vector = model.infer_vector(token)
sims = model.docvecs.most_similar([new_vector])
for x in sims:
    print(' '.join(all_docs[x[0]][0]))

Если есть способ изменить это, чтобы вместо этого получить документы, наиболее похожие на 700 закодированных документов, я хотел бы узнать, как это сделать!

3 ответа

Решение

Ваш общий подход разумен. Несколько замечаний о вашей настройке:

  • вам нужно будет указать epochs=10 в вашем train() призыв, чтобы действительно получить 10 учебных пропусков - и 10 или более чаще всего встречается в опубликованных работах
  • sampleуправляемая понижающая дискретизация помогает ускорить обучение и часто улучшает качество вектора, а значение может стать более агрессивным (меньшим) с большими наборами данных
  • train_lbls не является параметром Doc2Vec в любой недавний gensim версия

Существует несколько возможных способов интерпретации и достижения вашей цели "найти" наиболее похожие "документы из 700, которые мы уже написали вручную". Например, для документа-кандидата, как определить его сходство с набором 700 - как сходство с одним итоговым вектором "центроида" для полного набора? Или как его сходство с любым из документов?

Есть несколько способов получить один сводный вектор для набора:

  • в среднем их 700 векторов вместе

  • объединить все их слова в один синтетический составной документ, и infer_vector() на этом документе. (Но обратите внимание: тексты переданы gensimОптимизированные подпрограммы word2vec/doc2vec сталкиваются с внутренним пределом реализации в 10000 токенов - лишние слова молча игнорируются.)

На самом деле, most_similar() Метод может принять список из нескольких векторов в качестве "положительной" цели и автоматически усреднит их вместе перед возвратом результатов. Так что, если, скажем, 700 идентификаторов документов (теги, используемые во время обучения) находятся в списке ref_docsможно попробовать...

sims = model.docvecs.most_similar(positive=ref_docs, topn=0)

... и получить ранжированный список всех других документов в модели, по их сходству со средним числом всех positive Примеры.

Однако альтернативная интерпретация того, что сходство документа с набором ссылок является его наибольшим сходством с каким-либо одним документом внутри набора, может быть лучше для вашей цели. Это может особенно иметь место, если сам набор ссылок варьируется по многим темам и, следовательно, не суммируется одним средним вектором.

Вы должны были бы вычислить эти сходства с вашими собственными циклами. Например, примерно:

sim_to_ref_set = {}
for doc_id in all_doc_ids:
    sim_to_ref_set[doc_id] = max([model.docvecs.similarity(doc_id, ref_id) for ref_id in ref_docs])
sims_ranked = sorted(sim_to_ref_set.items(), key=lambda it:it[1], reverse=True)

Лучшие предметы в sims_ranked будет наиболее похожим на любой элемент в наборе ссылок. (Предполагая, что идентификаторы набора ссылок также находятся в all_doc_ids, первые 700 результатов снова будут выбранными документами, все с самоподобием 1.0.)

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

Поскольку у вас есть только 700 документов для перекрестной проверки, использование sklearn не должно вызывать проблем с производительностью. Просто получите векторы из ваших 700 документов и используйте sklearn.metrics.pairwise.cosine_sdentifity, а затем найдите наиболее близкое соответствие. Затем вы можете найти те, которые имеют наибольшее сходство (например, используя `np.argmax). Некоторый не проверенный код, чтобы проиллюстрировать это:

from sklearn.metrics.pairwise import cosine_similarity

reference_vectors = ... # your vectors to the 700 documents
new_vector = ... # inferred as per your last example
similarity_matrix = cosine_similarity([new_vector], reference_vectors)
most_similar_indices = np.argmax(similarity_matrix, axis=-1)

Это также может быть изменено для реализации такого метода, как n_similarity для ряда невидимых документов.

Я думаю, что вы можете делать то, что вы хотите с TaggedDocument. Основной вариант использования - просто добавить уникальный тег (идентификатор документа) для каждого документа, но здесь вы захотите добавить специальный тег ко всем 700 выбранным вами документам. Называй как хочешь, в этом случае я называю это TARGET, Добавьте этот тег только к своим 700 документам, помеченным вручную, пропустите его для остальных 59 300.

TaggedDocument(words=gensim.utils.simple_preprocess(document),tags=['TARGET',document_id])

Теперь тренируйте свой Doc2Vec.

Далее вы можете использовать model.docvecs.similarity чтобы оценить сходство между вашими немаркированными документами и пользовательским тегом.

model.docvecs.similarity(document_id,'TARGET')

А потом просто сортируй это. n_similarity а также most_similar Я не думаю, что будет подходящим для того, что вы хотите сделать.

60000 документов - это не очень много для Doc2Vec, но, возможно, вам повезет.

Другие вопросы по тегам