Doc2Vec:编码文档和看不见的文档之间的相似性

时间:2018-10-07 21:18:11

标签: python nlp gensim word2vec doc2vec

我有大约60,000个文档样本。我们已经将其中的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 个答案:

答案 0 :(得分:0)

n_similarity看起来像您想要的功能,但似乎只适用于训练集中的样本。

由于只有700个文档需要进行交叉检查,因此使用sklearn不会出现性能问题。只需获取700个文档的向量,然后使用sklearn.metrics.pairwise.cosine_similarity,然后找到最接近的匹配项即可。然后,您可以找到相似度最高的内容(例如,使用`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的方法。

答案 1 :(得分:0)

您的一般做法是合理的。有关设置的一些注意事项:

  • 您必须在epochs=10电话中指定train(),才能真正获得10个培训通行证-在已发表的作品中,最常见的是10个或更多
  • sample控制的下采样有助于加快训练速度,并且通常还可以改善矢量质量,并且对于较大的数据集,该值可以变得更具侵略性(较小)
  • train_lbls在任何最新的Doc2Vec版本中都不是gensim的参数

有几种可能的方法来解释和追求“找到与我们已经手工编码的700个文档最相似的文档”的目标。例如,对于候选文档,应如何定义其与700套相似性-作为与整个摘要的一个摘要“质心”矢量的相似性?还是作为与任何一份文件的相似之处?

您可以通过以下几种方法为集合获取单个汇总向量:

  • 将它们的700个向量平均在一起

  • 将所有单词组合到一个合成复合文档中,并infer_vector()合并到该文档中。 (但请注意:馈送给gensim的优化word2vec / doc2vec例程的文本面临10,000个令牌的内部实现限制-多余的单词将被静默忽略。)

实际上,most_similar()方法可以将多个向量列表作为其“正”目标,并在返回结果之前自动将它们平均在一起。因此,如果说ref_docs列表中有700个文档ID(培训期间使用的标签),则可以尝试...

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中排名靠前的项目将与参考集中的任何项目最相似。 (假设参考集ID也在all_doc_ids中,则第700个结果将再次成为所选文档,所有索引的自相似性均为1.0。)

答案 2 :(得分:0)

我认为您可以使用TaggedDocument做您想做的事情。基本用例是为每个文档添加唯一的标签(文档ID),但是在这里,您将要为手动选择的所有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_similaritymost_similar不适合您想做的事情。

对于Doc2Vec,60,000个文档不是很多,但是也许您会很幸运。