如何基于子串条件高效实现两个手机号DataFrames的左连接合并
基于子串后缀匹配的DataFrame高效左连接实现
需求描述
处理手机号相关的两个DataFrames,需要基于子串匹配条件进行左连接,要求保留所有匹配组合(即一条主表数据对应多条子表匹配项时,需列出全部组合)。原方案通过生成笛卡尔积后过滤子串,数据量大时性能极差,需高效实现方式。
示例数据
PHONES(主表)
| id | phone |
|---|---|
| 1 | +12399998888 |
| 2 | +12377776666 |
| 3 | +1233399998888 |
PHONES_NO_EXT(匹配表)
| id | phone |
|---|---|
| 1 | 99998888 |
| 2 | 99998888 |
| 3 | 77776666 |
期望结果RESULT_NEEDED
| id | phone | phone_no_ext |
|---|---|---|
| 1 | +12399998888 | 99998888 |
| 1 | +12399998888 | 99998888 |
| 2 | +12377776666 | 77776666 |
| 3 | +1233399998888 | 99998888 |
| 3 | +1233399998888 | 99998888 |
注:主表每条数据在匹配表中至少存在一个匹配项,匹配规则为匹配表的phone是主表phone的后缀子串。
高效实现方案
核心思路
将子串匹配转化为等值匹配:由于匹配表的phone是主表phone的后缀,先提取主表phone的对应长度后缀,再通过该后缀列与匹配表的phone列做左连接,直接得到所有匹配组合,完全避免笛卡尔积的生成。
代码实现
import pandas as pd # 1. 构造示例数据(替换为你的实际DataFrame) phones = pd.DataFrame({ 'id': [1, 2, 3], 'phone': ['+12399998888', '+12377776666', '+1233399998888'] }) phones_no_ext = pd.DataFrame({ 'id': [1, 2, 3], 'phone': ['99998888', '99998888', '77776666'] }) # 2. 提取主表手机号的匹配后缀(长度与匹配表手机号一致) # 若匹配表手机号长度不统一,可取最大长度:ext_length = phones_no_ext['phone'].str.len().max() ext_length = len(phones_no_ext['phone'].iloc[0]) phones['phone_suffix'] = phones['phone'].str[-ext_length:] # 3. 基于后缀列做左连接,保留所有匹配组合 merged_result = phones.merge( phones_no_ext, left_on='phone_suffix', right_on='phone', how='left' ) # 4. 整理结果列名与结构 final_result = merged_result.rename( columns={'phone_x': 'phone', 'phone_y': 'phone_no_ext'} )[['id_x', 'phone', 'phone_no_ext']].rename(columns={'id_x': 'id'}) print(final_result)
方案优势
- 性能高效:避免了O(n*m)复杂度的笛卡尔积,转为O(n+m)的等值匹配,pandas内部对该操作有高度优化,数据量越大性能提升越明显。
- 扩展性强:无需修改核心逻辑即可适配更大规模的数据集,若匹配表手机号长度不固定,只需调整后缀长度的计算方式即可。
内容的提问来源于stack exchange,提问作者Kadooken
相关产品推荐
相关产品推荐

