如何通过词向量技术来计算2个文档的相似度?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何通过词向量技术来计算2个文档的相似度?相关的知识,希望对你有一定的参考价值。

我正好是做记录文档匹配的,提供一个最简单的思路吧,计算两个向量的余弦或者jaccard相似度。即是比较两个向量相同的部分与总数之比,计算两个向量的编辑距离jaro距离或者仿射距离即是一个向量转换为另一个向量所需的最小插入删除更新等编辑操作次数,算出相似度之后,可以直接根据相似度判断是否相似,也可以利用knn分类器等分类方法判断相似与否,用deeplearning的话:短文本:拿word2vec开始,然后上面套CNN(如果n-gram更重要),或者LSTM做短文本的embedding,然后算两个文档在embeddingspace里的相似度。或者拿李航老师的Arc-II直接学word2vec之后的matching。

参考技术A

先不论这样定义的距离是否满足距离的性质(比如对称性),我们考虑这样的情况:文档1中每个词都跟“音乐”密切相关;文档2中只有一个词跟“音乐”密切相关,其余词都跟“音乐”完全无关;文档3中有一个词跟“音乐”密切相关,其他词都跟“音乐”有点关系但关联性不大。我们希望有,但只考虑匹配词对之间的距离和的话无法做到这一点,因为文档1中的所有词在文档2和文档3中都会被匹配到那个跟“音乐”密切相关的词上去,从而可能导致。所以我们希望通过某种约束,使得文档1中的每个词都会以不同权重被“强制性”地匹配到另一个文档的所有词上去。在上面关于“音乐”的例子里,由于文档2或3的所有词都会被匹配到,但文档3的词跟“音乐”更相关,我们便有希望得到。我们先把文档看成词的一个分布(比如使用归一化的词频特征)。首先考虑如何令“文档1中的每个词以不同权重匹配到另一个文档的所有词上”。如下图,很简单,我们允许“部分匹配”就可以了。这里我们把匹配看成是把文档1中的词“移动”到文档2中的词的一个过程,移动代价是两个词向量的Euclidean距离。比如说“Obama”在文档1中的权重(概率)是0.5,如果我把0.4移动到“President”、0.05移动到“greets”……等等,移动代价就是这里应该有个约束:把“Obama”分到文档2中词的权重的和应该等于它在文档1中的权重。

参考技术B

首先,如果不局限于NN的方法,可以用BOW+tf-idf+LSI/LDA的体系搞定,也就是俗称的01或onehotrepresentation。其次,如果楼主指定了必须用流行的NN,俗称word-embedding的方法,当然首推word2vec(虽然不算是DNN)。然后得到了word2vec的词向量后,可以通过简单加权/tag加权/tf-idf加权等方式得到文档向量。这算是一种方法。当然,加权之前一般应该先干掉stopword,词聚类处理一下。还有,doc2vec中的paragraphvector也属于直接得到doc向量的方法。特点就是修改了word2vec中的cbow和skip-gram模型。依据论文《DistributedRepresentationsofSentencesandDocuments》(ICML2014)。还有一种根据句法树加权的方式,是ICML2011提出的,见论文《ParsingNaturalScenesandNaturalLanguagewithRecursiveNeuralNetworks》,后续也有多个改编的版本。当然,得到词向量的方式不局限于word2vec,RNNLM和glove也能得到传说中高质量的词向量。ICML2015的论文《FromWordEmbeddingsToDocumentDistances,Kusner,WashingtonUniversity》新提出一种计算doc相似度的方式,大致思路是将词之间的余弦距离作为grounddistance,词频作为权重,在权重的约束条件下,求WMD的线性规划最优解。最后,kaggle101中的一个word2vec题目的tutorial里作者如是说:他试了一下简单加权和各种加权,不管如何处理,效果还不如01,归其原因作者认为加权的方式丢失了最重要的句子结构信息(也可以说是词序信息),而doc2vec的方法则保存了这种信息。在刚刚结束的ACL2015上,似乎很多人提到了glove的方法,其思想是挖掘词共现信息的内在含义,据说是基于全局统计的方法(LSI为代表)与基于局部预测的方法(word2vec为代表)的折衷,而且输出的词向量在词聚类任务上干掉了word2vec的结果。

针对许多文档计算文本相似度

【中文标题】针对许多文档计算文本相似度【英文标题】:Computing text similarity against many documents 【发布时间】:2020-03-10 12:17:51 【问题描述】:

我正在尝试计算搜索词 A 与其他搜索词集合的文本相似度,例如“如何制作鸡”。为了计算相似度,我使用余弦距离和 TF-IDF 将 A 转换为向量。我想一次比较 A所有 个文档的相似度。

目前,我的方法是迭代地计算 A 与其他所有文档的余弦相似度。我有 100 个要比较的文件。如果是cos_sim(A, X) > 0.8 的结果,那么我会说“酷,这很相似”。

但是,我觉得这可能不是整体相似性的真实表示。有没有办法在运行时为我的 100 个文档预先计算一个向量,并且每次我看到一个新的搜索查询 A 时,我都可以与这个预定义的向量/文档进行比较?

我相信我可以通过简单地将所有文档合并为一个来实现这一点……不过感觉很粗糙。有哪些利弊,以及可能的解决方案?效率加分!

【问题讨论】:

【参考方案1】:

这个问题本质上是传统的搜索问题:您是否尝试过将文档放入Lucene (Java) 或Whoosh (python) 之类的位置?我认为他们有一个余弦相似模型(但即使他们没有,默认值可能会更好)。

所有搜索引擎使用的一般技巧是,文档通常是稀疏的。这意味着要计算相似度(例如,余弦相似度),只关心文档的长度(提前知道)以及它们都包含的术语 ;您可以组织一个像书后索引这样的数据结构,称为inverted index,它可以快速告诉您哪些文档将获得至少非零分。

只有 100 个文档,搜索引擎可能是矫枉过正;您想预先计算 TF-IDF 向量并将它们保存在一个 numpy 矩阵中。然后,您可以使用 numpy 操作一次计算所有文档的点积——它将输出numerators you need 的 1x100 向量。分母可以类似地预先计算。然后numpy.max(numpy.dot(query, docs)/denom) 可能就足够快了。

您应该分析您的代码,但我敢打赌您的矢量提取是缓慢的部分;但是对于所有查询,您应该只需要这样做一次。

如果您有数千或数百万个文档要比较,您可以查看 SciKit learn 的 K-最近邻结构(例如,Ball Tree 或 KDTree,或类似 Facebook's FAISS library 的东西。

【讨论】:

以上是关于如何通过词向量技术来计算2个文档的相似度?的主要内容,如果未能解决你的问题,请参考以下文章

词向量:GloVe

余弦相似度计算

20-余弦相似度及其R实现

针对许多文档计算文本相似度

word2vec词向量训练及中文文本相似度计算

word2vec是如何得到词向量的?