我有两个数据框:
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
列中的最后一个字符串匹配。
如果有匹配项,我想将 Address
与 Add 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
答案 0 :(得分:2)
您可以利用 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)
那么:
new_df = second_df.loc[second_df["Owner_match_ratio"] > 0.7, :]
答案 1 :(得分:1)
受此 answer 的启发,您可以采用类似的解决方案。
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