【问题标题】:Calculate highest score in fuzzy string matching计算模糊字符串匹配的最高分
【发布时间】:2021-07-06 23:50:09
【问题描述】:

通过使用模糊字符串匹配来寻找两列值之间的最高准确率。

我有 2 个数据帧,我试图在两个数据帧的特定列值之间使用模糊匹配。

假设 df1 有 5 行,df2 有 4 行,我想选择 df1 的每一行的值并匹配 df2 的每一行并找到最高精度。假设 df1 中的 Row1 已经与 df2 中的所有行进行了比较,因此无论 df2 中的哪一行具有最高的准确度,我们都将其视为输出。 df1 中的每一行都需要考虑相同的内容。

输入数据:

数据框1

id_number  company_name        match_acc

IN2231D    AXN pvt Ltd
UK654IN    Aviva Intl Ltd
SL1432H    Ship Incorporations
LK0678G    Oppo Mobiles pvt ltd
NG5678J    Nokia Inc

Dataframe2

identity_no   Pincode   company_name

 IN2231        110030    AXN pvt Ltd
 UK654IN       897653    Aviva Intl Ltd
 SL1432        07658     Ship Incorporations
 LK0678G       120988    Oppo Mobiles Pvt Ltd

希望找到最高准确率百分比并提交 match_acc 列中的值。

我目前使用的代码:

df1 = pd.read_excel(open(r'input.xlsx', 'rb'), sheet_name='sheet1')
df2 = pd.read_excel(open(r'input.xlsx', 'rb'), sheet_name='sheet2')


from fuzzywuzzy import fuzz 
for index, row in df1.iterrows():
   df1['match_acc']= fuzz.partial_ratio(df1['id_number'], df2['identity_no'])

print(df1['match_acc'])

我一直在用Fuzzywuzzy,如果还有其他方法请指教。

任何建议。

【问题讨论】:

标签: python pandas fuzzywuzzy


【解决方案1】:

TL;DR

  1. 交叉-merge df1.id_numberdf2.identity_no
  2. 计算每对的thefuzz.fuzz.ratio 或更快的rapidfuzz.fuzz.ratio
  3. map groupby.max 比率回到 df1
cross = df1[['id_number']].merge(df2[['identity_no']], how='cross')
cross['match_acc'] = cross.apply(lambda x: fuzz.ratio(x.id_number, x.identity_no), axis=1)
df1['match_acc'] = df1.id_number.map(cross.groupby('id_number').match_acc.max())

#   id_number          company_name  match_acc
# 0   IN2231D           AXN pvt Ltd         92
# 1   UK654IN        Aviva Intl Ltd        100
# 2   SL1432H   Ship Incorporations         92
# 3   LK0678G  Oppo Mobiles pvt ltd        100
# 4   NG5678J             Nokia Inc         43

详情

  1. mergecross 方法产生df1.id_numberdf2.identity_no 的笛卡尔积:

    cross = df1[['id_number']].merge(df2[['identity_no']], how='cross')
    
    #    id_number identity_no
    # 0    IN2231D      IN2231
    # 1    IN2231D     UK654IN
    # 2    IN2231D      SL1432
    # ...
    # 17   NG5678J     UK654IN
    # 18   NG5678J      SL1432
    # 19   NG5678J     LK0678G
    

    对于 how='cross' 不可用,因此在临时密钥上使用 how='outer'

    cross = df1[['id_number']].assign(tmp=0).merge(df2[['identity_no']].assign(tmp=0), how='outer', on='tmp').drop(columns='tmp')
    
  2. apply 模糊计算器配对:

    cross['match_acc'] = cross.apply(lambda x: fuzz.ratio(x.id_number, x.identity_no), axis=1)
    
    #    id_number identity_no  match_acc
    # 0    IN2231D      IN2231         92
    # 1    IN2231D     UK654IN         29
    # 2    IN2231D      SL1432         15
    # ...
    # 17   NG5678J     UK654IN         14
    # 18   NG5678J      SL1432          0
    # 19   NG5678J     LK0678G         43
    
  3. 使用groupby.maxid_numbermap 的最高分数转换为df1.match_acc

    df1['match_acc'] = df1.id_number.map(cross.groupby('id_number').match_acc.max())
    
    #   id_number          company_name  match_acc
    # 0   IN2231D           AXN pvt Ltd         92
    # 1   UK654IN        Aviva Intl Ltd        100
    # 2   SL1432H   Ship Incorporations         92
    # 3   LK0678G  Oppo Mobiles pvt ltd        100
    # 4   NG5678J             Nokia Inc         43
    

【讨论】:

  • 没有,明白了,df1 的前 4 行如何以 100% 的准确率作为输出,好像我们可以看到输入数据帧中只有 df1 的 2 行值具有 100% 匹配 - 'UK654IN', 'LK0678G' 与 df2 比较时。
  • 谢谢,在您看来,除了 blur.partial_ratio() 之外还有其他功能。在这种情况下哪个更适合。
  • @NKJ 我更新了答案,将partial_ratio() 更改为ratio(),这将为您提供Levenshtein 分数[92,100,92,100,43]。这应该是您正在寻找的。​​span>
  • @NKJ 不确定,也许你有一个旧的熊猫版本。试试这个:cross = df1[['id_number']].assign(tmp=0).merge(df2[['identity_no']].assign(tmp=0), how='outer', on='tmp').drop(columns='tmp')
  • @NKJ 我会在计算之前从id_number 列中dropna,例如cross = cross.dropna(subset=['id_number'])
【解决方案2】:

您可以使用fuzzywuzzyprocess 函数进行一对多操作。 另外,使用rapidfuzz 代替fuzzywuzzy,它具有相同的功能,但它基于字符串算法执行一些预处理以提供更快的结果。

pip install rapidfuzz

# from fuzzywuzzy import fuzz, process
from rapidfuzz import fuzz, process # --> Use this for drastic exponential execution time improvements

df1 = pd.read_excel(open(r'input.xlsx', 'rb'), sheet_name='sheet1')
df2 = pd.read_excel(open(r'input.xlsx', 'rb'), sheet_name='sheet2')


for index, row in df1.iterrows():
    #extractOne will automatically extract the best one from the list of choices
    # you can provide which fuzzywuzzy scorer to use as well

    df1['match_acc']= process.extractOne(query=row['id_number'], choices=df2['identity_no'].tolist(), scorer=fuzz.partial_ratio)
print(df1['match_acc'])

【讨论】:

  • @shreyansh - 如何通过匹配获得最高精度。 .
  • @NKJ - 正如代码中的注释所述,process.ExtractOne 将在所有choices 中提取一个得分最高(最高准确度)的最佳结果。
  • @shreyansh - 执行时出现错误 TypeError: sentence must be a String
  • @NKJ - 我的错。将df1 更改为row
猜你喜欢
  • 2021-01-31
  • 2011-02-22
  • 2012-02-14
  • 2014-11-02
  • 1970-01-01
  • 2018-05-31
  • 2021-04-19
  • 1970-01-01
  • 2017-08-03
相关资源
最近更新 更多