
本文介绍一种高效、可靠的方法:通过正则提取子字符串构建临时键,再执行左连接,从而将 name 列(如 "dale")与包含该名称的 id 字符串(如 "dale-999999")精准关联。
在实际数据处理中,常遇到「一端为完整标识符、另一端仅为其中一部分」的关联需求——例如 a["Name"] 是人名("Dale"),而 b["ID"] 是带后缀的复合 ID("Dale-999999")。此时无法直接使用等值连接(merge),需借助字符串匹配逻辑构建映射关系。
核心思路是:先从 b["ID"] 中提取出与 a["Name"] 完全一致的子串,生成临时键 _name;再以此键与 a["Name"] 执行左连接(how='left')。这既满足“每个 b["ID"] 最多匹配一个 a["Name"]”的约束,也支持“一个 a["Name"] 对应多个 b["ID"]”的业务场景(如 "Bill" 匹配 "Bill-000" 和 "Bill-001")。
具体实现如下:
import pandas as pd
a = pd.DataFrame({"Name": ["Boomhaur", "Dale", "Bill", "Hank"]})
b = pd.DataFrame({"ID": ["Boomhaur-2345", "Dale-999999", "Bill-000", "Bill-001", "Peggy-420"]})
# 构建正则模式:\b(Boomhaur|Dale|Bill|Hank)\b → 确保精确单词匹配,避免 "Bill" 匹配 "Billy"
pat = r'\b(' + '|'.join(a['Name'].str.replace(r'[^\w\s]', r'\\', regex=True)) + r')\b'
b['_name'] = b["ID"].str.extract(pat)
# 执行左连接:以 a["Name"] 为左键,b["_name"] 为右键
result = a.merge(b, how='left', left_on='Name', right_on='_name')
# 清理临时列(可选)
result = result.drop(columns=['_name']).reset_index(drop=True)
print(result)输出结果为:
Name ID 0 Boomhaur Boomhaur-2345 1 Dale Dale-999999 2 Bill Bill-000 3 Bill Bill-001 4 Hank NaN
⚠️ 注意事项:
- 正则中的 \b(词边界)至关重要,可防止误匹配(如 "Bill" 不会错误匹配 "Billy" 或 "ABill");
- 若 a["Name"] 中含正则元字符(如 +, *, (),务必用 str.replace(..., regex=True) 转义,否则引发 re.error;
- str.extract() 返回首个匹配项,符合“每个 ID 至多匹配一个 Name”的前提;
- 若需保留 b 中未匹配的行,应改用 how='right' 或外连接,但本例明确要求以 a 为主表,故使用 how='left'。
该方法简洁、可读性强,且完全基于 Pandas 原生向量化操作,无需循环或 apply,性能优异,适用于中大型数据集。










