如何比较两个DataFrame的groupby结果值并找出数据集交集?
解决两个姓名DataFrame的交集匹配问题
嘿,我来帮你搞定这个姓名匹配的问题!你的思路完全没问题——按姓氏分组后再做名字匹配确实是高效的方式,下面一步步给你拆解实现方案:
步骤1:拆分姓名为姓氏和名字
首先把两个DataFrame里的姓名按「逗号+空格」拆分,提取出姓氏和独立的名字部分:
import pandas as pd # 初始化你的示例数据 t1 = pd.DataFrame(['Abe, John Doe', 'Smith, Brian', 'Lin, Sam', 'Lin, Greg'], columns=['t1']) t2 = pd.DataFrame(['Abe, John', 'Smith, Brian', 'Lin, Sam', 'Lu, John'], columns=['t2']) # 拆分t1的姓名列,生成姓氏和名字列 t1[['last_name', 'first_name']] = t1['t1'].str.split(', ', expand=True) # 对t2做同样的拆分操作 t2[['last_name', 'first_name']] = t2['t2'].str.split(', ', expand=True)
步骤2:按姓氏分组,整理名字集合
为了快速做匹配检查,我们把每个姓氏对应的所有名字整理成集合(集合的成员检查速度远快于列表):
# t1按姓氏分组,把同姓氏的名字聚合为集合 t1_groups = t1.groupby('last_name')['first_name'].agg(set).reset_index() # t2做同样的分组聚合 t2_groups = t2.groupby('last_name')['first_name'].agg(set).reset_index()
现在两个分组结果的结构是:每行对应一个姓氏,以及该姓氏下的所有名字集合,方便后续对比。
步骤3:找出符合条件的交集
接下来我们把两个分组结果按姓氏合并,然后检查t2的名字是否能在t1对应姓氏的名字集合中找到匹配(比如t2的"John"是否包含在t1的"John Doe"里):
# 按姓氏合并两个分组DataFrame merged = pd.merge(t1_groups, t2_groups, on='last_name', suffixes=('_t1', '_t2')) # 定义匹配函数:检查t2的名字是否是t1中某个名字的子串 def check_name_match(names_t1, names_t2): matched = [] for name_t2 in names_t2: # 判断t2的名字是否出现在t1的任意一个名字中 if any(name_t2 in name_t1 for name_t1 in names_t1): matched.append(name_t2) return matched if matched else None # 应用函数,找出每个姓氏下的匹配名字 merged['matched_names'] = merged.apply(lambda row: check_name_match(row['first_name_t1'], row['first_name_t2']), axis=1) # 过滤出有匹配结果的行,还原成原始姓名格式 result = merged.dropna(subset=['matched_names']).explode('matched_names') result['full_name'] = result['last_name'] + ', ' + result['matched_names'] # 输出最终交集结果 print(result[['full_name']])
运行后会得到你要的交集:
full_name 0 Abe, John 1 Smith, Brian 2 Lin, Sam
关于对比两个DataFrame的groupby结果
如果你需要直接操作两个groupby对象的值,有两种常用方法:
- 转成字典对比:把groupby结果转成「姓氏: 名字集合」的字典,直接按键访问对比,适合快速遍历:
t1_name_dict = t1.groupby('last_name')['first_name'].agg(set).to_dict() t2_name_dict = t2.groupby('last_name')['first_name'].agg(set).to_dict() # 遍历t2的姓氏,检查是否在t1中存在匹配 for last_name, t2_names in t2_name_dict.items(): if last_name in t1_name_dict: t1_names = t1_name_dict[last_name] # 这里可以自定义对比逻辑,比如求完全交集、部分包含等 common = [name for name in t2_names if any(name in t1_name for t1_name in t1_names)] if common: print(f"姓氏 {last_name} 的匹配名字:{common}") - 合并后逐行处理:就像前面步骤3那样,用
pd.merge合并分组结果后,通过apply逐行处理每组数据,这种方式能保留DataFrame结构,方便后续的数据分析和导出。
内容的提问来源于stack exchange,提问作者psak
相关产品推荐
相关产品推荐

