我有一个具有以下结构的字典:
{
1: {"names": ["name1_A", "name1_B", ...]},
2: {"names": ["name2_A", "name2_B", ...]},
...
}
其中name1_A
和name1_B
是同义词/别名/写同名的不同方式,其ID为1. name2_A
和name2_B
是同名的别名,其ID为2,依此类推。
我需要编写一个函数,该函数接受用户输入并返回其别名与用户输入最相似的名称的ID。
我知道理解我的意思并不是很直观,所以这是一个例子。让我们说这是我的字典:
{
1: {"names": ["James", "Jamie"]},
2: {"names": ["Karen", "Karyn"]}
}
用户输入单词Jimmy
。由于与字典Jimmy
的最接近匹配是Jamie
,因此该函数必须返回ID 1。
如果用户输入世界Karena
,由于最接近的匹配是Karen
,因此该函数必须返回ID 2.
我认为获得最接近数学的最佳方法是使用difflib的get_close_matches()
。但是,该函数将可能性列表作为参数,我无法想到在函数中正确使用它的方法。任何帮助将不胜感激。
答案 0 :(得分:4)
如果您对第三方模块感兴趣,那么我喜欢使用这个名为fuzzywuzzy
的小模块,用于Python中的模糊字符串匹配。此模块使用Levenshtein Distance指标计算两个字符串之间的距离。以下是您如何使用它的示例:
>>> from fuzzywuzzy import fuzz
>>> from functools import partial
>>> data_dict = {
... 1: {"names": ["James", "Jamie"]},
... 2: {"names": ["Karen", "Karyn"]}
... }
>>> input_str = 'Karena'
>>> f = partial(fuzz.partial_ratio, input_str)
>>> matches = { k : max(data_dict[k]['names'], key=f) for k in data_dict}
>>> matches
{1: 'James', 2: 'Karen'}
>>> { i : (matches[i], f(matches[i])) for i in matches }
{1: ('James', 40), 2: ('Karen', 100)}
现在,您可以提取Karen
,因为它的分数最高。
为了本演示的目的,我必须两次调用该函数,但您应该只能执行一次,具体取决于您对此示例的扩展方式。
另一点需要注意的是fuzz.partial_ratio
对其匹配更宽松。对于更严格的匹配方案,请考虑使用fuzz.ratio
。
您可以使用模糊字符串匹配here来仔细阅读更多示例。