如何在Python中对Levenshtein距离超过80%的单词进行分组

Posted

技术标签:

【中文标题】如何在Python中对Levenshtein距离超过80%的单词进行分组【英文标题】:How to group words whose Levenshtein distance is more than 80 percent in Python 【发布时间】:2016-05-12 08:02:09 【问题描述】:

假设我有一个列表:-

person_name = ['zakesh', 'oldman LLC', 'bikash', 'goldman LLC', 'zikash','rakesh']

我正在尝试以这样一种方式对列表进行分组,以便两个字符串之间的Levenshtein distance 最大。为了找出两个词之间的比例,我使用了一个python包fuzzywuzzy。

示例:-

>>> from fuzzywuzzy import fuzz
>>> combined_list = ['rakesh', 'zakesh', 'bikash', 'zikash', 'goldman LLC', 'oldman LLC']
>>> fuzz.ratio('goldman LLC', 'oldman LLC')
95
>>> fuzz.ratio('rakesh', 'zakesh')
83
>>> fuzz.ratio('bikash', 'zikash')
83
>>> 

我的最终目标:

我的最终目标是对单词进行分组,使它们之间的 Levenshtein 距离超过 80%?

我的列表应该是这样的:-

person_name = ['bikash', 'zikash', 'rakesh', 'zakesh', 'goldman LLC', 'oldman LLC'] because the distance between `bikash` and `zikash` is very high so they should be together.

代码:

我试图通过排序来实现这一点,但关键功能应该是fuzz.ratio。下面的代码不起作用,但我正在从这个角度解决问题。

from fuzzywuzzy import fuzz
combined_list = ['rakesh', 'zakesh', 'bikash', 'zikash', 'goldman LLC', 'oldman LLC']
combined_list.sort(key=lambda x, y: fuzz.ratio(x, y))
print combined_list

谁能帮我把这些词组合起来,使它们之间的 Levenshtein 距离超过 80%?

【问题讨论】:

“combine”、“similar”、“very high”和“something like this”都没有很好的定义。你必须澄清你的规格。 我很困惑。我看到了一个优化问题,即“将这组单词分成具有最大内部距离的簇”,但您继续谈论“排序”,即“将列表按顺序排列”。我不确定这两者是如何混合的。您是否只希望两个 successive 字符串之间的距离最大? 在 python 2 中,您可以将比较函数 cmp 传递给 sort(和相关函数)。这已从 Python 3 中删除,但一种解决方法:请参阅cmp_to_key。 关于集群问题(如果是的话):听起来像maximum clique。节点是单词,如果这些单词之间的编辑距离 >= 80%,则单词之间有边缘。其余的是 NP 完全的,采用您选择的近似算法,networkx 实现了一些。 @python 对于group by,你需要一个函数来根据单词本身来确定单词的组关联。这里的问题是:是否可以将单词添加到组中取决于 all 组中已经存在的元素。这是一个组合优化问题,据我所知,最大集团符合要求。 【参考方案1】:

这对名称进行分组

from fuzzywuzzy import fuzz

combined_list = ['rakesh', 'zakesh', 'bikash', 'zikash', 'goldman LLC', 'oldman LLC']
combined_list.append('bakesh')
print('input names:', combined_list)

grs = list() # groups of names with distance > 80
for name in combined_list:
    for g in grs:
        if all(fuzz.ratio(name, w) > 80 for w in g):
            g.append(name)
            break
    else:
        grs.append([name, ])

print('output groups:', grs)
outlist = [el for g in grs for el in g]
print('output list:', outlist)

生产

input names: ['rakesh', 'zakesh', 'bikash', 'zikash', 'goldman LLC', 'oldman LLC', 'bakesh']
output groups: [['rakesh', 'zakesh', 'bakesh'], ['bikash', 'zikash'], ['goldman LLC', 'oldman LLC']]
output list: ['rakesh', 'zakesh', 'bakesh', 'bikash', 'zikash', 'goldman LLC', 'oldman LLC']

如您所见,名称分组正确,但顺序可能不是您想要的。

【讨论】:

这不只是一种(贪婪的)方法,而且结果组可能不是最优的吗? @dhke 当然是的。我从来没有说过它是最佳的,也不是唯一的。请务必提供更好/替代的解决方案。 我只是想提一下,但我会尽量给出一个最佳的(最大组数)。尽管如此,您的解决方案当然是正确的并返回有效的集群。 这本质上是使用单个集群进行集群,并逐步添加元素。请注意,它取决于订单;随着我们向集群中添加更多元素(并且它们变得分散),满足“添加”条件all(fuzz.ratio(name, w) > 80 for w in g) 变得更加困难。因此,如果您在运行前将combined_list 洗牌,您可能会得到不同的结果。

以上是关于如何在Python中对Levenshtein距离超过80%的单词进行分组的主要内容,如果未能解决你的问题,请参考以下文章

python-levenshtein

Python:使用 scikit-learn 的 dbscan 进行字符串聚类,使用 Levenshtein 距离作为度量:

如何调整 Levenshtein 距离算法以将匹配限制为单个单词?

odds ratio怎么用python计算

Levenshtein计算相似度距离

Spark Java API 计算 Levenshtein 距离