【问题标题】:Fuzzy String Comparison模糊字符串比较
【发布时间】:2012-04-30 11:37:20
【问题描述】:

我正在努力完成的是一个程序,它读取一个文件,并根据原始句子比较每个句子。与原文完全匹配的句子将获得 1 分,完全相反的句子将获得 0 分。所有其他模糊句子将获得介于 1 和 0 之间的评分。

我不确定使用哪个操作可以让我在 Python 3 中完成此操作。

我已经包含了示例文本,其中文本 1 是原始文本,其他前面的字符串是比较。

文本:示例

文字 1:那是一个黑暗而暴风雨的夜晚。我一个人坐在红色的椅子上。我不是一个人,因为我养了三只猫。

文本 20:那是一个阴暗而暴风雨的夜晚。我一个人坐在深红色的椅子上。我并不完全孤单,因为我有三只猫科动物 // 应该得分高点,但不是 1

文本 21:那是一个阴暗而暴风雨的夜晚。我一个人坐在深红色的大教堂上。我并不完全孤单,因为我有三只猫科动物 // 得分应该低于文本 20

文本 22:我一个人坐在深红色的大教堂上。我并不完全孤单,因为我有三只猫科动物。这是一个阴暗而暴风雨的夜晚。 // 得分应该低于文本 21 但不是 0

文本 24:那是一个黑暗而暴风雨的夜晚。我并不孤单。我没有坐在红色的椅子上。我养了三只猫。 // 应该得 0 分!

【问题讨论】:

  • 似乎您想计算 Levenshtein distance(或其他一些 edit distance 指标)。如果您现在是最大距离,您只需将分数缩放到[0,1] 的范围内。
  • 感谢您的帮助@Felix Kling,difflib 可能是要走的路。
  • @FelixKling 太糟糕了,它被删除了......
  • 为什么字符串 1 和 24 应该为零?他们的第一句话完全相同。 1 中的第 2 句与 24 中的第 2+3 句几乎相同(唯一的区别是“不是”,还有一个额外的“我不是”)。从数字上讲,它们非常相似。从语义上讲,它们是不同的,但如果您要求计算机理解句子的含义,那么您可能要求的太多了。

标签: python nlp fuzzy-comparison


【解决方案1】:

有一个名为fuzzywuzzy 的包。通过 pip 安装:

pip install fuzzywuzzy

简单用法:

>>> from fuzzywuzzy import fuzz
>>> fuzz.ratio("this is a test", "this is a test!")
    96

该软件包建立在difflib 之上。你问为什么不直接使用它?除了更简单一点之外,它还有许多不同的匹配方法(如令牌顺序不敏感、部分字符串匹配),使其在实践中更加强大。 process.extract 函数特别有用:从一组中找到最匹配的字符串和比率。从他们的自述文件中:

部分比率

>>> fuzz.partial_ratio("this is a test", "this is a test!")
    100

令牌排序率

>>> fuzz.ratio("fuzzy wuzzy was a bear", "wuzzy fuzzy was a bear")
    90
>>> fuzz.token_sort_ratio("fuzzy wuzzy was a bear", "wuzzy fuzzy was a bear")
    100

代币组合比例

>>> fuzz.token_sort_ratio("fuzzy was a bear", "fuzzy fuzzy was a bear")
    84
>>> fuzz.token_set_ratio("fuzzy was a bear", "fuzzy fuzzy was a bear")
    100

过程

>>> choices = ["Atlanta Falcons", "New York Jets", "New York Giants", "Dallas Cowboys"]
>>> process.extract("new york jets", choices, limit=2)
    [('New York Jets', 100), ('New York Giants', 78)]
>>> process.extractOne("cowboys", choices)
    ("Dallas Cowboys", 90)

【讨论】:

  • 试试fuzzywuzzy。发现如果将“纽约巨人队”更改为“纽约巨人队达拉斯牛仔队”,则 process.extract(“new york jets”,choices,limit=2) 产生 [('New York Jets', 100), ( “纽约巨人队达拉斯牛仔队”,86)]。你知道为什么第二次模糊匹配的匹配率会上升吗?这没有多大意义。
  • 得到警告,“lib/python2.7/site-packages/fuzzywuzzy/fuzz.py:35: UserWarning: 使用慢的纯python SequenceMatcher。安装python-Levenshtein来删除这个警告warnings.warn('Using slow pure-python SequenceMatcher.Install python-Levenshtein to remove this warning')"
  • @user2738183 pip install python-Levenshtein FuzzyWuzzy 使用 difflib,它是标准库的一部分。但是,为了获得更好的性能,您可以安装 python-Levenshtein 模块以进行上述序列匹配。 pypi.org/project/python-Levenshtein
【解决方案2】:

标准库中有一个模块(称为difflib)可以比较字符串并根据它们的相似性返回一个分数。 SequenceMatcher 类应该做你想做的事。

Python 提示的小例子:

>>> from difflib import SequenceMatcher as SM
>>> s1 = ' It was a dark and stormy night. I was all alone sitting on a red chair. I was not completely alone as I had three cats.'
>>> s2 = ' It was a murky and stormy night. I was all alone sitting on a crimson chair. I was not completely alone as I had three felines.'
>>> SM(None, s1, s2).ratio()
0.9112903225806451

【讨论】:

  • 谢谢@mac。这正是我正在寻找的。我只是在想办法让程序判断一个句子是否与原文相反。 python 是否有一个库可以帮助我解决这个问题的语法情况?
  • @user1365664 - 这听起来是一个非常困难的问题,但 Python 中有关自然语言的任何问题的规范答案是 NLTK,nltk.org
  • @user1365664:我怀疑这样的事情是否存在,除非您在这种情况下指定“相反”的含义。 abzy 的反义词吗?还是abba 的反义词?等
  • @user1365664:在这种情况下,您可能想看看 NLP 和 情感分析
  • @user1365664 如果您满意,请不要忘记接受这个答案。
【解决方案3】:

fuzzyset 在索引和搜索方面都比fuzzywuzzy (difflib) 快得多。

from fuzzyset import FuzzySet
corpus = """It was a murky and stormy night. I was all alone sitting on a crimson chair. I was not completely alone as I had three felines
    It was a murky and tempestuous night. I was all alone sitting on a crimson cathedra. I was not completely alone as I had three felines
    I was all alone sitting on a crimson cathedra. I was not completely alone as I had three felines. It was a murky and tempestuous night.
    It was a dark and stormy night. I was not alone. I was not sitting on a red chair. I had three cats."""
corpus = [line.lstrip() for line in corpus.split("\n")]
fs = FuzzySet(corpus)
query = "It was a dark and stormy night. I was all alone sitting on a red chair. I was not completely alone as I had three cats."
fs.get(query)
# [(0.873015873015873, 'It was a murky and stormy night. I was all alone sitting on a crimson chair. I was not completely alone as I had three felines')]

警告:注意不要在您的模糊集中混用 unicodebytes

【讨论】:

  • 如何只提取文本
  • @JafferWilson 与从任何 python 元组列表中提取第一行、最后一个“列”的方式相同:fs.get(query)[0][-1]
  • Thankx.. :) 我一定会用这个。
【解决方案4】:

这项任务被称为Paraphrase Identification,这是自然语言处理研究的一个活跃领域。我已经链接了几篇最先进的论文,其中很多你可以在 GitHub 上找到开源代码。

请注意,所有回答的问题都假设两个句子之间存在一些字符串/表面相似性,而实际上两个字符串相似性很小的句子在语义上可能是相似的。

如果您对这种相似性感兴趣,可以使用Skip-Thoughts。 根据 GitHub 指南安装软件并转到自述文件中的释义检测部分:

import skipthoughts
model = skipthoughts.load_model()
vectors = skipthoughts.encode(model, X_sentences)

这会将您的句子 (X_sentences) 转换为向量。稍后您可以通过以下方式找到两个向量的相似性:

similarity = 1 - scipy.spatial.distance.cosine(vectors[0], vectors[1])

我们假设 vector[0] 和 vector1 是 X_sentences[0]、X_sentences1 的对应向量,您想找到它们的分数。

还有其他模型可以将句子转换为向量,您可以找到here

将句子转换为向量后,相似度只需找出这些向量之间的余弦相似度即可。

2020 年更新 谷歌发布了一个名为BERT的新模型,它基于一个名为Tensorflow的深度学习框架。还有一个很多人觉得更容易使用的实现,称为Transformers。这些程序所做的是,它们接受两个短语或句子,并且能够训练它们说出这两个短语/句子是否相同。要训​​练它们,您需要一些标签为 1 或 0 的句子(如果它们具有相同的含义或不同)。您使用您的训练数据(已经标记的数据)训练这些模型,然后您将能够使用经过训练的模型来预测一对新的短语/句子。您可以在相应的 github 页面或许多其他地方(例如 this)找到如何训练(他们称之为微调)这些模型。

还有一些可用英文标记的训练数据,称为 MRPC(微软释义识别语料库)。请注意,BERT 也存在多语言或特定语言版本,因此该模型也可以在其他语言中扩展(例如训练)。

【讨论】:

    【解决方案5】:

    还有这个由 MIT 许可的快速准确的模糊比较库: https://github.com/maxbachmann/RapidFuzz

    【讨论】:

      猜你喜欢
      • 2012-04-27
      • 2023-02-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-15
      • 2021-03-18
      相关资源
      最近更新 更多