匹配两个列表中的字符串

fer*_*n48 2 python string function list

问题是:我想定义一个函数,该函数将使用 fuzzy.ration() 在 2 个列表(大小不同)内比较字符串比率。它应该返回列表 1 中的实体,其中至少有一个与第二个的比率大于 60。

def Matching(list1, list2):
    no_matching = []
    matching = []
    for item1 in list1:    
        for item2 in list2:        
            m_score = fuzz.ratio(item1, item2)
        if m.score < 60:
            no_matching.append(item1)
        if m.score > 60:
            matching.append(item1)
    return(matching, no_matching)
Run Code Online (Sandbox Code Playgroud)

输出不是我的目标。我做错了哪一部分- 为了仅从列表 1 中获取项目(如果列表 2 中至少有一个大于 60 的匹配项)。

例如:

list1 = ["Real Madrid", "Benfica", "Lazio", "FC Milan"]
list2 = ["Madrid", "Barcelona", "Milan"]

for item1 in list1:
    for item2 in list2:
        m_score = fuzz.ratio(item1, item2)
        print(item1, "&", item1, m_score)
Run Code Online (Sandbox Code Playgroud)

输出是:

Real Madrid & Madrid 71 # greater than 60
Real Madrid & Barcelona 20
Real Madrid & Milan 12
Benfica & Madrid 15
Benfica & Barcelona 50
Benfica & Milan 17
Lazio & Madrid 36
Lazio & Barcelona 29
Lazio & Milan 20
FC Milan & Madrid 29
FC Milan & Barcelona 24
FC Milan & Milan 77 # greater than 60
Run Code Online (Sandbox Code Playgroud)

函数输出应该是:

matching = ["Real Madrid", "FC Milan"] # since they have at least one ratio bigger than 60
no_matching = ["Benfica", "Lazio"]
Run Code Online (Sandbox Code Playgroud)

max*_*ann 7

特别是考虑到您对大型列表(10.000 * 1.200)执行此操作的评论,我建议使用RapidFuzz(我是作者)。使用的解决方案RapidFuzz可以通过以下方式实现:

from rapidfuzz import process, fuzz
import numpy as np

list1 = ["Real Madrid", "Benfica", "Lazio", "FC Milan"]
list2 = ["Madrid", "Barcelona", "Milan"]

scores = process.cdist(
    list1, list2, scorer=fuzz.ratio,
    dtype=np.uint8, score_cutoff=60)
# scores is array([[71,  0,  0],
#                  [ 0,  0,  0],
#                  [ 0,  0,  0],
#                  [ 0,  0, 77]], dtype=uint8)

matches = np.any(scores, 1)
# matches is array([ True, False, False,  True])
Run Code Online (Sandbox Code Playgroud)

这仍然处理整个 N*M 矩阵,但它比使用fuzzywuzzy/执行相同操作要快得多thefuzz。当处理非常大的列表时,可以process.cdist通过传递命名参数来启用多线程workers(例如workers=-1,使用所有可用的内核)。如果需要,上面的结果可以转换为示例中显示的列表:

matching = [x for x, is_match in zip(list1, matches) if is_match]
# ['Real Madrid', 'FC Milan']
not_matching = [x for x, is_match in zip(list1, matches) if not is_match]
# ['Benfica', 'Lazio']
Run Code Online (Sandbox Code Playgroud)

我使用两个大列表 (10.000 * 1.200)在i7-8550U上对该解决方案进行了基准测试:

print(timeit(
"""
scores = process.cdist(
    list1, list2, scorer=fuzz.ratio,
    dtype=np.uint8, score_cutoff=60)

matches = np.any(scores, 1)

matching = [x for x, is_match in zip(list1, matches) if is_match]
not_matching = [x for x, is_match in zip(list1, matches) if not is_match]
""",
setup="""
from rapidfuzz import process, fuzz
import numpy as np

list1 = ["Real Madrid", "Benfica", "Lazio", "FC Milan"] * 2500
list2 = ["Madrid", "Barcelona", "Milan"] * 400
""", number=1
))
Run Code Online (Sandbox Code Playgroud)

耗时 0.33 秒。使用workers=-1将运行时间减少到 0.08 秒。