【问题标题】:Fuzzy match for 2 lists with very similar names两个名称非常相似的列表的模糊匹配
【发布时间】:2021-10-23 22:41:43
【问题描述】:

我知道有人以某种方式提出过这个问题,所以很抱歉。我正在尝试将列表 1(sample_name)模糊匹配到列表 2(实际名称)。 Actual_name 的名称比列表 1 的名称多得多,而且我一直在运行模糊匹配,但效果不佳。我尝试了多种模糊匹配方法(部分,set_token),但由于列表 2 中有更多非常相似的名称,所以一直遇到问题。有什么办法可以改善这里的匹配。理想情况下,希望有列表 1,列表 2 中的匹配名称,匹配分数在新数据框中的第 3 列。任何帮助将非常感激。谢谢。

目前为止使用过:

df1=sample_df['sample_name'].to_list()
df2=actual_df['actual_name'].to_list()
response = {}
for name_to_find in df1:
   for name_master in df2:
     if fuzz.partial_ratio(name_to_find,name_master) > 90:
       response[name_to_find] = name_master
       break
for key, value in response.item():
  print('sample name' + key + 'actual_name' + value)


sample_name actual_name
jtsports JT Sports LLC
tombaseball Tom Baseball Inc.
context express Context Express LLC
zb sicily ZB Sicily LLC
lightening express Lightening Express LLC
fire roads Fire Road Express
N/A Earth Treks
N/A TS Sports LLC
N/A MM Baseball Inc.
N/A Contact Express LLC
N/A AB Sicily LLC
N/A Lightening Roads LLC

【问题讨论】:

  • 那么您是否只是想获得sample_name 列与actual_name 列的“匹配分数”?

标签: python fuzzy-search fuzzywuzzy


【解决方案1】:

这不是最有效的方法,正确匹配的数量为 O(n),但您可以计算左右之间的 Levenshtein distance,然后根据最接近的匹配进行匹配. 这就是许多 nieve 拼写检查系统的工作原理。

我建议您对每个正确的名称运行此计算并返回得分最低的匹配项。

调整您发布的代码,我将遵循以下内容。请记住,Levenshtein 距离较低,因此需要进行一些调整。您使用的更高功能似乎更接近,因此以下应该可以使用它。

df1=sample_df['sample_name'].to_list()
df2=actual_df['actual_name'].to_list()
response = {}
for name_to_find in df1:
   highest_so_far = ("", 0)
   for name_master in df2:
     score = fuzz.partial_ratio(name_to_find, name_master)
     if score > highest_so_far[1]:
       highest_so_far = (name_master, score)
   response[name_to_find] = highest_so_far[0]
      
for key, value in response.item():
  print('sample name' + key + 'actual_name' + value)

【讨论】:

  • 我收到一条错误消息,提示highest_so_far 未定义。你知道我如何更改代码吗?谢谢。
  • 是的,很抱歉,到目前为止,if 语句中的最大错字是“h”
【解决方案2】:

不确定这是否是您的预期输出(您可能需要调整阈值),但我认为这就是您想要的?

import pandas as pd
from fuzzywuzzy import process

threshold = 50

list1 = ['jtsports','tombaseball','context express','zb sicily',
         'lightening express','fire roads']
list2 = ['JT Sports LLC','Tom Baseball Inc.','Context Express LLC',
'ZB Sicily LLC','Lightening Express LLC','Fire Road Express',
'Earth Treks','TS Sports LLC','MM Baseball Inc.','Contact Express LLC',
'AB Sicily LLC','Lightening Roads LLC']


response = []
for name_to_find in list1:
    resp_match =  process.extractOne(name_to_find ,list2)
    if resp_match[1] > threshold:
         row = {'sample_name':name_to_find,'actual_name':resp_match[0], 'score':resp_match[1]}
         response.append(row)
         print(row)

results = pd.DataFrame(response)

# If you need all the 'actual_name' tp be in the datframe, continue below
# Otherwise don't include these last 2 lines of code
unmatched = pd.DataFrame([x for x in list2 if x not in list(results['actual_name'])], columns=['actual_name'])
results = results.append(unmatched, sort=False).reset_index(drop=True)

输出:

print(results)
           sample_name             actual_name  score
0             jtsports           JT Sports LLC   79.0
1          tombaseball       Tom Baseball Inc.   81.0
2      context express     Context Express LLC   95.0
3            zb sicily           ZB Sicily LLC   95.0
4   lightening express  Lightening Express LLC   95.0
5           fire roads       Fire Road Express   86.0
6                  NaN             Earth Treks    NaN
7                  NaN           TS Sports LLC    NaN
8                  NaN        MM Baseball Inc.    NaN
9                  NaN     Contact Express LLC    NaN
10                 NaN           AB Sicily LLC    NaN
11                 NaN    Lightening Roads LLC    NaN

【讨论】:

    猜你喜欢
    • 2010-10-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多