
本文介绍如何将 df1 中以斜杠分隔的姓氏(如 "a/b/c")拆解后,在 df2 中查找这些姓氏共同归属的唯一公司名称,并为每行返回该交集结果。核心在于利用 frozenset 实现无序姓名集合的精确匹配。
本文介绍如何将 df1 中以斜杠分隔的姓氏(如 "a/b/c")拆解后,在 df2 中查找这些姓氏共同归属的唯一公司名称,并为每行返回该交集结果。核心在于利用 frozenset 实现无序姓名集合的精确匹配。
在实际数据处理中,常需根据部分标识(如姓氏)跨表关联并提取“全员一致”的归属信息。本例中,df1['Name'] 存储的是多个姓氏拼接的字符串(如 "A/B/C"),而 df2 包含个体姓氏与所属公司(Last Name → Firm Names)。目标不是任意匹配,而是仅当 df1 中某行所有拆分出的姓氏在 df2 中全部指向同一个公司时,才返回该公司名称——即求多个姓氏对应公司集合的交集,且交集大小为 1。
✅ 推荐方案:使用 frozenset 实现稳健匹配(支持任意顺序)
该方法不依赖姓氏在 df1 和 df2 中的顺序一致性,鲁棒性强:
import pandas as pd
# 构建示例数据
df1 = pd.DataFrame({'Name': ['A/B/C', 'D/E', 'F/G']})
df2 = pd.DataFrame({
'First Name': ['Adam', 'Harry', 'Andrew', 'Mike', 'Sheila', 'Hash', 'Michelle', 'Morty'],
'Last Name': ['A', 'B', 'C', 'A', 'D', 'E', 'F', 'G'],
'Firm Names': ['Firm1','Firm1','Firm1','Firm2','Firm3','Firm3','Firm4','Firm4']
})
# 步骤 1:为 df1 添加姓名集合列(frozenset 保证可哈希且无视顺序)
df1_expanded = df1.assign(
**{
'Last Name': df1['Name'].str.split('/'),
'name_set': df1['Name'].str.split('/').apply(frozenset)
}
)
# 步骤 2:展开姓氏,左连接 df2,按原始行索引 + 公司分组,聚合为 frozenset
df2_matched = (
df1_expanded.explode('Last Name')
.reset_index()
.merge(df2, left_on='Last Name', right_on='Last Name', how='left')
.groupby(['index', 'Firm Names'])
.agg(matched_set=('Last Name', frozenset))
.reset_index(level=1)
)
# 步骤 3:与 df1_expanded 合并,筛选出 matched_set 与原始 name_set 完全相等的记录
result = (
df1_expanded.merge(df2_matched, left_index=True, right_index=True, how='left')
.assign(is_match=lambda x: x['name_set'] == x['matched_set'])
.query('is_match')
[['Name', 'Firm Names']]
.drop_duplicates(subset=['Name'], keep='first')
.reset_index(drop=True)
)
print(result)输出:
Name Firm Names 0 A/B/C Firm1 1 D/E Firm3 2 F/G Firm4
⚠️ 注意事项:
- 若某行拆分后的姓氏(如 "A/B")在 df2 中分别属于 Firm1 和 Firm2,则无交集,该行 Firm Names 将为 NaN;
- frozenset 是关键:它使集合可哈希(用于 groupby)、忽略元素顺序,确保 "A/B" 与 "B/A" 匹配逻辑一致;
- 使用 explode() + merge() + groupby().agg() 组合,清晰表达“每个姓氏查公司 → 按行+公司聚合成集合 → 匹配原始集合”的逻辑链;
- 最终通过 query('is_match') 显式过滤,语义明确,便于调试和扩展(例如改为返回多公司列表或标记匹配状态)。
此方案兼顾可读性、健壮性与工程实用性,适用于真实场景中姓名格式不规范、顺序不可控的数据匹配任务。

















