模糊字符串比较


70

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

我不确定要使用哪种操作在Python 3中完成此操作。

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

文字:样本

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

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

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

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

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


4
似乎您要计算Levenshtein距离(或其他一些编辑距离度量标准)。如果现在是最大距离,则只需将分数缩放到范围[0,1]
Felix Kling

感谢您的帮助@Felix Kling difflib可能是您要走的路。
jacksonstephenc 2012年

@FelixKling太糟糕了,它删除了....
弗兰克Dernoncourt

为什么字符串1和24取零?他们的第一句话完全一样。1中的第二个句子与24中的2 + 3句子几乎相同(不同之处仅在于“ not”,还有一个额外的“ I was not”)。在数字上它们非常相似。从语义上来说,它们是不同的,但是如果您要求计算机理解句子的含义,那么您可能要求太多。
naught101 '18

Answers:


107

有一个名为的软件包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)

尝试模糊。发现是否将“ New York Giants”更改为“ New York Giants Dallas Cowboys”,process.extract(“纽约喷气机”,choices,limit = 2)会产生[('New York Jets',100),( '纽约巨人达拉斯牛仔',86)]。您知道第二个模糊匹配的匹配率为什么会上升吗?这没有多大意义。
ToonZ

得到警告,“ lib / python2.7 / site-packages / fuzzywuzzy / fuzz.py:35:UserWarning:使用慢速纯Python SequenceMatcher。安装python-Levenshtein删除此警告warnings.warn('使用慢速纯Python SequenceMatcher 。安装python-Levenshtein删除此警告')

@ user2738183 pip install python-Levenshtein FuzzyWuzzy使用difflib,它是标准库的一部分。为了获得更好的性能,您可以安装python-Levenshtein模块以进行上述序列匹配。pypi.org/project/python-Levenshtein
Alexander

85

标准库中有一个模块(称为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

HTH!


1
谢谢@mac。这正是我想要的。我只是在想办法让程序判断句子是否与原句相反。python是否有一个可以帮助我解决语法问题的库?
jacksonstephenc 2012年

@ user1365664-这听起来像是一个非常棘手的问题,但是有关Python中自然语言的所有问题的规范答案都是NLTK,nltk.org
AKX 2012年

@ user1365664:我怀疑这样的事情是否存在,除非您在这种情况下指定“相反”的含义。是ab相反的zy吗?还是ab相反ba?等
Felix Kling 2012年

1
@ user1365664:在这种情况下,您可能想看看NLP和情感分析
Felix Kling

5
@ user1365664如果您满意,请不要忘记接受此答案。
漂流者

16

fuzzyset索引和搜索的速度都比fuzzywuzzydifflib)快得多。

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')]

警告:要小心,不要混用unicode,并bytes在你的fuzzyset。


1
如何仅提取文本
Jaffer Wilson

@JafferWilson就像从任何python元组列表中提取第一行,最后一个“列”一样:fs.get(query)[0][-1]
滚刀

1
谢谢.. :)我一定会用的。
贾弗·威尔逊

5

该任务称为复述识别,这是自然语言处理研究的活跃领域。我已经链接了一些最新的论文,您可以在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]和vector 1是X_sentences [0]和X_sentences 1的对应向量,您想找到它们的分数。

还有其他将句子转换为向量的模型,您可以在此处找到。

将句子转换为向量后,相似度只是找到这些向量之间的余弦相似度的问题。

2020年更新谷歌基于深度学习框架Tensorflow发布了 这种称为BERT的新模型。还有许多人发现更易于使用的实现称为“变形金刚”。这些程序的作用是接受两个短语或句子,并且能够训练他们说出这两个短语/句子是否相同。要训​​练它们,您需要多个带有标签1或0的句子(无论它们的含义是否相同)。您可以使用训练数据(已经标记的数据)训练这些模型,然后就可以使用训练后的模型对新的一对短语/句子进行预测。您可以在相应的github页面或诸如this的许多其他地方找到如何训练(称为微调)这些模型的方法。

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.