繁体   English   中英

什么是 Python 中的简单模糊字符串匹配算法?

[英]What is a simple fuzzy string matching algorithm in Python?

我试图找到某种好的、模糊的字符串匹配算法。 直接匹配对我不起作用——这不太好,因为除非我的字符串 100% 相似,否则匹配失败。 Levenshtein方法不适用于字符串,因为它适用于字符级别。 我一直在寻找类似词级匹配的东西,例如

字符串 A:快速的棕色狐狸。

字符串B:敏捷的棕色狐狸跳过了懒惰的狗。

这些应该匹配,因为字符串 A 中的所有单词都在字符串 B 中。

现在,这是一个过于简单的例子,但有谁​​知道一个在单词级别上工作的好的模糊字符串匹配算法。

我喜欢德鲁的回答

您可以使用difflib查找最长匹配项:

>>> a = 'The quick brown fox.'
>>> b = 'The quick brown fox jumped over the lazy dog.'
>>> import difflib
>>> s = difflib.SequenceMatcher(None, a, b)
>>> s.find_longest_match(0,len(a),0,len(b))
Match(a=0, b=0, size=19) # returns NamedTuple (new in v2.6)

或者选择一些最小匹配阈值。 例子:

>>> difflib.SequenceMatcher(None, a, b).ratio()
0.61538461538461542

看看 SeatGeek 昨天开源的这个 python 库。 显然,大多数这类问题都非常依赖于上下文,但它可能对您有所帮助。

from fuzzywuzzy import fuzz

s1 = "the quick brown fox"
s2 = "the quick brown fox jumped over the lazy dog"
s3 = "the fast fox jumped over the hard-working dog"

fuzz.partial_ratio(s1, s2)
> 100

fuzz.token_set_ratio(s2, s3)
> 73

SeatGeek 网站

和 Github 仓库

如果您只想测试一个字符串中的所有单词是否与另一个字符串匹配,那就是一个单行:

if not [word for word in b.split(' ') if word not in a.split(' ')]:
    print 'Match!'

如果你想给它们打分而不是二进制测试,为什么不做这样的事情:

((匹配单词的数量) / (较大字符串中的单词数量)) * ((较小字符串中的单词数量) / (较大字符串中的单词数量))

?

如果你愿意,你可以变得更有趣,并对每个字符串进行模糊匹配。

你可以试试这个 python 包,它使用机器学习的模糊名称匹配。

pip install hmni

初始化匹配器对象

import hmni
matcher = hmni.Matcher(model='latin')

单对相似度

matcher.similarity('Alan', 'Al')
# 0.6838303319889133

matcher.similarity('Alan', 'Al', prob=False)
# 1

matcher.similarity('Alan Turing', 'Al Turing', surname_first=False)
# 0.6838303319889133

注意:我还没有构建这个包。 在这里分享它,因为它对我的使用非常有用。 GitHub

您可以修改 Levenshtein 算法来比较单词而不是字符。 这不是一个非常复杂的算法,并且可以在线获得多种语言的源代码。

Levenshtein 通过比较两个字符数组来工作。 没有理由不能对两个字符串数组应用相同的逻辑。

前段时间我用 C# 做了这个,我以前的问题在这里 有您感兴趣的入门算法,您可以轻松地将其转换为 python。

您应该使用编写自己的算法的想法是这样的:

  • 有一个带有原始“标题”的列表(要与之匹配的单词/句子)。
  • 每个标题项都应该在单词/句子上有最低的匹配分数,也忽略标题。
  • 您还应该拥有最终结果的全局最小匹配百分比。
  • 您应该计算每个单词 - 单词 Levenshtein 的距离。
  • 如果单词按相同顺序排列,您应该增加总匹配权重(quick brown vs quick brown,应该比 quick brown vs. brown quick 具有更高的权重。)

您可以从https://github.com/frazenshtein/fastcd/blob/master/search.py尝试 FuzzySearchEngine。

这种模糊搜索仅支持单词搜索,并且该单词具有固定的容许误差(仅对两个相邻字符进行一次替换或换位)。

但是,例如,您可以尝试以下操作:

import search

string = "Chapter I. The quick brown fox jumped over the lazy dog."
substr = "the qiuck broqn fox."

def fuzzy_search_for_sentences(substr, string):  
    start = None
    pos = 0
    for word in substr.split(" "):
        if not word:
            continue
        match = search.FuzzySearchEngine(word).search(string, pos=pos)
        if not match:
            return None
        if start is None:
            start = match.start()
        pos = match.end()
    return start

print(fuzzy_search_for_sentences(substr, string))

11 将被打印

如果您比较单词(由停止字符序列分隔的字符串)而不是单个字母,Levenshtein 应该可以正常工作。

def ld(s1, s2):  # Levenshtein Distance
    len1 = len(s1)+1
    len2 = len(s2)+1
    lt = [[0 for i2 in range(len2)] for i1 in range(len1)]  # lt - levenshtein_table
    lt[0] = list(range(len2))
    i = 0
    for l in lt:
        l[0] = i
        i += 1
    for i1 in range(1, len1):
        for i2 in range(1, len2):
            if s1[i1-1] == s2[i2-1]:
                v = 0
            else:
                v = 1
            lt[i1][i2] = min(lt[i1][i2-1]+1, lt[i1-1][i2]+1, lt[i1-1][i2-1]+v)
    return lt[-1][-1]

str1 = "The quick brown fox"
str2 = "The quick brown fox jumped over the lazy dog"

print("{} words need to be added, deleted or replaced to convert string 1 into string 2".format(ld(str1.split(),str2.split())))

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM