【问题标题】:Function that returns affinity between texts?返回文本之间的亲和力的函数?
【发布时间】:2011-06-14 20:56:02
【问题描述】:

考虑一下我有一个

string1 = "hello hi goodmorning evening [...]"

我还有一些次要关键字

compare1 = "hello evening"
compare2 = "hello hi"

我需要一个函数来返回文本和关键字之间的亲和力。示例:

function(string1,compare1);  // returns: 4
function(string1,compare2);  // returns: 5 (more relevant)

请注意 5 和 4 只是示例。

你可以说 - 编写一个计算出现次数的函数 - 但对于这个例子,这不起作用,因为两者都有 2 次出现,但 compare1 不太相关,因为在 string1 中没有完全找到“hello night”(两个词 hello和晚上比你好嗨更遥远)

是否有任何已知的算法可以做到这一点?

添加1:

在这种情况下,像编辑距离这样的算法将不起作用。 因为 string1 是一个完整的文本(如 300-400 个字),比较字符串最多 4-5 个字。

【问题讨论】:

  • 您是在寻找简单的字符串编辑距离比较还是完全语义等价?例如cat 更类似于 cart 还是 feline?
  • 两者都不是..我需要一些类似计算出现次数+根据单词距离给予权重的东西(正如我之前解释的那样:string1 是一篇有 300-400 字的文章,比较字符串只有 3- 4 个字)
  • 您的关键字总是成对出现吗?更重要的是,有更多匹配的词或更好的接近度?
  • 1.不总是成对的,比较字符串最多可以是 5-6 个单词 2. 50%-50%

标签: algorithm text full-text-search relevance


【解决方案1】:

一种动态规划算法

您正在寻找的似乎与Smith–Waterman algorithm 所做的非常相似。

来自维基百科:

该算法由 Temple F. Smith 和 Michael S. Waterman 于 1981 年首次提出。与 Needleman-Wunsch 算法一样,它是一个变体,Smith-Waterman 是 dynamic programming algorithm。因此,它具有理想的特性,即可以保证找到相对于所使用的评分系统(包括替换矩阵和间隙评分方案)的最佳局部对齐。

让我们看一个实际示例,以便您评估它的实用性。

假设我们有一个文本:

text = "We the people of the United States, in order to form a more 
perfect union, establish justice, insure domestic tranquility, 
provide for the common defense, 

  promote the general welfare, 

  and secure the blessings of liberty to ourselves and our posterity, 
do ordain and establish this Constitution for the United States of 
America.";  

我隔离了我们要匹配的片段,只是为了便于阅读。

我们会将相似度(或相似度)与字符串列表进行比较:

list = {
   "the general welfare",
   "my personal welfare",
   "general utopian welfare",
   "the general",
   "promote welfare",
   "stackoverflow rulez"
   };  

我已经实现了算法,所以我将计算相似度并将结果归一化:

sw = SmithWatermanSimilarity[ text, #] & /@ list;
swN = (sw - Min[sw])/(Max[sw] - Min[sw])  

然后我们绘制结果:

我认为这与您的预期结果非常相似。

HTH!

一些实现(带源代码)

【讨论】:

  • 这可能是解决方案!但是为什么你的函数被称为“SmithWatermanSimilarity”而不仅仅是“SmithWaterman”:我的意思是你有一些定制吗?无论如何,您对此有伪代码描述吗?所以我可以翻译成我的语言(php)
  • @yes123 在我的回答末尾有一些链接(您可能会发现很多),包括三个实现和两个“教育”资源。我不能提供我的,因为它不是开源的。
  • 嗯,好的。也许我会尝试 cuda 或 java 实现,看看它是否符合我的需求(比如你的解决方案)。如果我要翻译成php,我会在这里发布一个链接,谢谢
  • 我正在测试一些 java 实现。这些实现似乎考虑了字符而不是词条。这对我来说是个大问题
  • @yes123 它也适用于文字,试试吧。它旨在匹配类似于单词的 DNA 序列
【解决方案2】:

看看如何从您的输入数据中创建 N-gram,然后在 N-gram 上进行匹配。我有一个解决方案,我将每个 n-gram 视为向量空间中的一个维度(在我的情况下变成 4000 个维度的空间),然后亲和力是两个向量之间角度的余弦(这里涉及点积)。

困难的部分是想出一个以您想要的方式定义亲和力的指标。

另一种方法是查看滑动窗口并根据窗口中的 compare_x 数据中的单词数进行评分。最后的分数就是总和。

【讨论】:

  • 嗯,即使它很有趣我不认为你可以使用这个滑动窗口,因为你不能选择 alyawys 工作的 windows 大小。我在想更像这样的事情:首先只计算出现次数,然后根据找到的键之间有多少字符来删除一些点。但我不敢相信这项工作还没有已知的算法......它在搜索相关的东西中非常重要。 Regsrding 使用 ngrams 的其他解决方案我不知道如何制作它
  • 没有明确的解决方案,因为不同的目的需要不同的指标。
  • 你为什么这么说?我很确定其他人已经为此编写了算法(我认为这不会太难)我在这里找到了该问题的一些数学解决方案:domino.mpi-inf.mpg.de/intranet/ag5/ag5publ.nsf/… 在第 31 页有一个解决方案“对于 a 的每个术语 t查询 q= {t1, . . . , tn},我们计算一个累加器 acc,其中包含 t 在当前元素 e 内的邻近分数:"
【解决方案3】:

py-editdist 将为您提供两个字符串之间的Levenshtein edit distance,这是一个可能有用的指标。​​

见:http://www.mindrot.org/projects/py-editdist/

该页面的代码示例:

import editdist

# Calculate the edit distance between two strings
d = editdist.distance("abc", "bcdef")

相关:https://stackoverflow.com/questions/682367/good-python-modules-for-fuzzy-string-comparison

【讨论】:

    【解决方案4】:

    我认为这里有一个很好且完整的答案 http://answers.google.com/answers/threadview?id=337832

    对不起,谷歌的答案!

    【讨论】:

    • 该页面上的一半链接不起作用。而另一半根本不谈论接近度
    • 如果你的意思是接近,就像意思一样,
    【解决方案5】:

    在这里,您可以找到用于计算字符串之间距离的指标列表,以及可以执行此操作的开源 Java 库。 http://en.wikipedia.org/wiki/String_metric 特别是,看看 Smith-Waterman 算法,记住他们所谓的“字母”可以由我们所谓的字符串组成:所以,给定字母

    {A = "hello", B = "hi",C = "goodmorning",D = "evening"}
    

    并调用 d 距离,您的函数会尝试计算

    d(ABCD,AB) vs d(ABCD,AC)
    

    【讨论】:

    • HM,我读过 Smith–Waterman 在角色方面的作品很棒。我需要这个算法来处理文本 =/
    • 如前所述,将每个单词都视为一个常量字符,你应该完成
    • 嗯,所以我应该根据我的文本和比较字符串构建我的 Alphabet 并将它们提供给算法?我不确定它是否可以工作,因为算法支持像“插入”/“删除”这样适用于字符的东西
    【解决方案6】:

    嗯,你可以统计比较文本的出现次数,即:

    "a-b-c" -> "a" , "b" , "c" , "a-b" , b-c" , "a-b-c" (如果你想要的话,可能是 "a-c")

    然后计算每一个的出现次数,并将它们相加,可能权重为(字符串长度)/(整个字符串的长度)。

    那么您只需要一种方法来生成这些片段,并检查所有这些片段。

    【讨论】:

      【解决方案7】:

      虽然现在的 Levenshtein distance 可能不适合您的目的,但对其进行修改可能会:尝试通过分别存储插入、删除和替换来实现它。

      距离将是以下各项的总和:

      • 所有替换项
      • 每组连续插入/删除中的空格数减一:
        • (在您的情况下:“hi goodmorning”仅计为两次编辑,而“[...]”计为一次。)

      当然,您必须对此进行测试,但如果效果不佳,请尝试简单地使用连续插入/删除的总和(因此,“嗨,早上好”只有 1 次编辑)。

      编辑

      PS:这假设 Levenshtein 的工作方式发生了相对重大的变化,您首先要“对齐”您的数据(找出有显着(两个以上字符)重叠的位置并插入“空”字符,这将算作插入)。

      此外,这只是一个未经测试的想法,因此欢迎任何改进想法。

      【讨论】:

        猜你喜欢
        • 2013-08-19
        • 2010-11-05
        • 2015-10-16
        • 1970-01-01
        • 2017-01-10
        • 2016-05-31
        • 1970-01-01
        • 1970-01-01
        • 2021-08-21
        相关资源
        最近更新 更多