使用多个条件检查一列df到另一列df中的字符串值



我有两个数据帧:

import pandas as pd
first_df = pd.DataFrame({'Full Name': ['Mulligan Nick & Mary', 'Tsang S C', 'Hattie J A C '],
'Address': ['270 Claude Road', '13 Sunnyridge Place', '18A Empire Road']})
second_df = pd.DataFrame({'Owner' : ['David James Mulligan', 'Brenda Joy Mulligan ', 'Helen Kwok Hattie'],
'Add Match': ['19 Dexter Avenue', 'Claude Road ', 'Building NO 512']})

是否只将Full Name列中的第一个字符串与Owner列中的最后一个字符串匹配。

如果有匹配,我想将AddressAdd match进行比较,看看是否有类似的值。如果第一个条件通过,但第二个条件失败,则不会将其添加到新的数据帧中。

使用左联接会导致:

new_df = first_df.merge(second_df, how='left', left_on = ['Full Name', 'Address'], right_on = ['Owner', 'Add Match'])
print(new_df.head())
Full Name              Address Owner Add Match
0  Mulligan Nick & Mary      270 Claude Road   NaN       NaN
1             Tsang S C  13 Sunnyridge Place   NaN       NaN
2         Hattie J A C       18A Empire Road   NaN       NaN

然而,想要的输出看起来更像这样:

new_df
Name                 Address
----                 --------
Brenda Joy Mulligan  Claude Road

您可以利用Python标准库中的difflib模块来查找不同列之间的相似性。例如,您可以定义以下函数:

from difflib import SequenceMatcher
def compare_df(left, right, col: str):
left[f"{col}_match_ratio"] = 0
for value in left[col]:
best_ratio = 0
for other in right[col]:
result = SequenceMatcher(None, str(value), str(other)).ratio()
if result > best_ratio:
best_ratio = result
left.loc[left[col] == value, f"{col}_match_ratio"] = round(best_ratio, 2)

然后:

  • 您只需要确保要比较的列在两个dfs中具有相同的名称
  • 您调用df_compare(first_df,second_df,"所有者"(,它将添加"所有者";所有者匹配比率"列到second_df
  • 最后,根据所需的最小匹配率(例如70%(过滤第二个df,如下所示:new_df = second_df.loc[second_df["Owner_match_ratio"] > 0.7, :]

受此答案的启发,您可以使用类似的解决方案。

TL;DR

first_df[['last_name', 'start_name']] = first_df['Full Name'].str.split(' ', 1, expand=True)
second_df['last_name'] = second_df['Owner'].str.split(' ').str[-1]
df_final = first_df.merge(second_df, how='inner', left_on=['last_name'], right_on=['last_name'])
address_matches = df_final.apply(lambda x: True if difflib.get_close_matches(x['Address'], [x['Add Match']], n=1, cutoff=0.8) else False, axis=1)
df_final = df_final[address_matches].drop(columns=['last_name', 'start_name', 'Full Name', 'Address']).rename(columns={'Owner':'Name', 'Add Match': 'Address'})

循序渐进

最初,提取所需的姓氏关键字。

first_df[['last_name', 'start_name']] = first_df['Full Name'].str.split(' ', 1, expand=True)
second_df['last_name'] = second_df['Owner'].str.split(' ').str[-1]

PS:根据您的指示,我们使用pandas/numpy组合中的内置字符串方法。但如果它更适合你,你也可以对地址部分应用下面显示的相似性方法(例如,difflib.get_close_matches(。

接下来,执行这些数据帧的内部联接,以匹配last_name密钥。

df_temp = first_df.merge(second_df, how='inner', left_on=['last_name'], right_on=['last_name'])

然后应用具有所需相似性的difflib.get_close_matches(我使用cutoff=0.8,因为在该值以上没有返回值(方法来标记哪些行包含匹配项,然后只获得所需的行。

matches_mask = df_final.apply(lambda x: True if difflib.get_close_matches(x['Address'], [x['Add Match']], n=1, cutoff=0.8) else False, axis=1)
df_final = df_final[matches_mask].drop(columns=['last_name', 'start_name'])
Full Name               Address             Owner                   Add Match
Mulligan Nick & Mary    270 Claude Road     Brenda Joy Mulligan     Claude Road

最后,为了与问题末尾发布的结果的格式相匹配,您可以删除或重命名一些列。

df_final.drop(columns=['Full Name', 'Address']).rename(columns={'Owner':'Name', 'Add Match': 'Address'})
Owner                   Add Match
Brenda Joy Mulligan     Claude Road

最新更新