文本相似度算法

Posted

技术标签:

【中文标题】文本相似度算法【英文标题】:Text similarity Algorithms 【发布时间】:2011-08-13 05:45:33 【问题描述】:

我正在做一个 Java 项目,我必须在其中制作一个文本相似性程序。我希望它获取 2 个文本文档,然后将它们相互比较并获得相似度。它们之间有多么相似。

我稍后会放置一个已经存在的数据库,该数据库可以找到单词的同义词并查看文本以查看文本文档作者是否只是将单词更改为其他同义词而文本完全相同.向上或向下移动 paragrafs 也是如此。 是的,因为它是一个抄袭程序......

我想听听你们会推荐什么样的算法。

通过查看这里和其他地方,我发现了 Levenstein 和 Cosine 的相似性。他们两个似乎都被提及很多。汉明距离是我老师告诉我的另一个距离。

我有一些与这些相关的问题,因为我并没有真正了解***。有人可以向我解释这些事情吗?

Levenstein:这个算法由sub改变,添加和删除单词,看看它与文本文档中的另一个单词有多接近。但是如何在整个文本文件中使用它呢?我可以看到它如何用于一个单词,但不能用于一个句子或从一个到另一个的整个文本文档。

余弦:通过测量两个向量之间夹角的余弦来衡量两个向量之间的相似性。我在这里不明白两个文本如何成为 2 个向量以及其中的单词/句子呢?

Hamming:这个距离似乎比 Levenstein 更好,但它只是在相等的弦上。当 2 个文档甚至其中的句子不是两个长度相等的字符串时,为什么它很重要?

***应该有意义,但事实并非如此。如果这些问题听起来太愚蠢,我很抱歉,但它让我感到沮丧,我认为这里有人非常有能力解释它,所以即使是这个领域的新手也能理解。

感谢您的宝贵时间。

【问题讨论】:

看看:en.wikipedia.org/wiki/Diff#Algorithm 肯定会帮助你,但是,不是从头开始。不如你先来看看我们可以从哪里开始。这就是家庭作业/学校项目的工作方式。 Err..对不起,我没有得到你。我想我确实开始了为什么我要问我不理解的问题。哦,我还没有做程序,我在理解事物的部分。我喜欢在使用它之前得到它。 【参考方案1】:

Levenstein:理论上你可以将它用于整个文本文件,但它确实不太适合这项任务。它确实适用于单个单词或(最多)一个短语。

余弦:首先计算每个文档中的唯一单词。完成后,previous question 的答案将涵盖计算。

我从来没有为此目的使用过汉明距离,所以我不能说太多。

我会将 TFIDF(词频 * 倒排文档频率)添加到列表中。它与余弦距离非常相似,但 1) 往往在较短的文档上做得更好,并且 2) 在考虑整个语料库中哪些词非常常见而不仅仅是那些恰好常见的词方面做得更好到两个特定的文档。

最后一点:任何要产生有用的结果,您几乎需要在尝试计算相似度之前筛选掉停用词(尽管 TFIDF 似乎比其他人做得更好如果你跳过这个)。至少根据我的经验,词干(删除后缀)也非常有帮助。完成后,我使用了 Porter 的词干算法。

出于您的目的,您可能想要使用我称之为倒置词库的东西,它可以让您查找一个词,并为每个词替换一个规范词来表示该含义。我在一个项目上试过这个,并没有发现它像预期的那样有用,但听起来对你的项目来说它可能会更有用。

【讨论】:

谢谢。自从我浏览了大多数与相似性相关的主题以来,我确实看到了余弦实现。这是从我迷路的文本部分中理解向量;独特的词,嗯...关于倒叙词库,我将使用这个名为 wordnet 的词汇数据库:wordnet.princeton.edu 这是他们一直在做的一个庞大的项目。不过那是很久以后的事了。现在,在我开始使用它们之前,它已经了解了算法:D 啊,不要介意矢量交易。我刚刚找到了这个很好的例子,可以按照我的喜好向我解释它。如果有人也想读的话,这里就是:***.com/questions/1746501/… 这很好除了,因为 TFIDF 并不是计算相似度的真正解决方案。其目的是确定一个术语对整个文档的重要性。因此,它可用于计算余弦相似度(如您链接到的答案所示)。【参考方案2】:

考虑一下 wikipedia 上关于 Levenshtein 距离的示例:

For example, the Levenshtein distance between "kitten" and "sitting" is 3, since the following three edits change one into the other, and there is no way to do it with fewer than three edits:

   1. kitten → sitten (substitution of 's' for 'k')
   2. sitten → sittin (substitution of 'i' for 'e')
   3. sittin → sitting (insertion of 'g' at the end).

现在,将“kitten”替换为“第一篇论文中的文字”,将“sitting”替换为“第二篇论文中的文字”。

Paper[] papers = getPapers();
for(int i = 0; i < papers.length - 1; i++) 
    for(int j = i + 1; j < papers.length; j++) 
        Paper first = papers[i];
        Paper second = papers[j];
        int dist = compareSimilarities(first.text,second.text);
        System.out.println(first.name + "'s paper compares to " + second.name + "'s paper with a similarity score of " + dist);
    

比较这些结果并确定距离得分最低的孩子。

在您的compareSimilarities 方法中,您可以使用任何或所有比较算法。您可以在公式中加入的另一个是“最长公共子字符串”(这是发现抄袭的好方法。)

【讨论】:

我明白了。所以我们将所有单词保存在一个数组中,然后根据我们比较的算法?所以它可以像示例中一样:Now, replace "kitten" with "text from first paper", and "sitting" with "text from second paper". 这里它可以获取单词 text 然后将它与句子的每个单词进行比较,看看它们有多相似,直到它跳到另一个单词并做完全相同的事情直到最后一个字,然后吐出分数? 我会尝试将论文的文本视为一个巨大的单词。 嗯...所以“texfromthefirstpaper”和“textfromthesecondpaper”,然后比较它们。虽然如果我取第二个大词并写下“thesecondpaperstext”,那会不会给出完全不同的结果,因为它似乎是按字符串比较的? O.o 那么我是否正确,虽然第一个会给出更相似的结果,但第二个根本不会?【参考方案3】:

信息检索中比较两个文档相似度的基本思想是提取一些指纹,并根据指纹判断它们是否共享一些信息。

只是一些提示,Winnowing: Local Algorithms for Document Fingerprinting 可能是您解决问题的一个选择和一个很好的起点。

【讨论】:

谢谢,我明天早餐后去看看。^^ 我读过。我不能说这就是我想要的。虽然头疼;p

以上是关于文本相似度算法的主要内容,如果未能解决你的问题,请参考以下文章

文本相似度算法

文本相似度-bm25算法原理及实现

文本相似度计算(一):距离方法

基于Gensim的文本相似度计算

文本相似度算法

文本挖掘之 文本相似度判定