You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何基于子串合并Pandas DataFrame并区分匹配类型

Pandas子串匹配合并DataFrame解决方案

核心需求回顾

需要合并两个大型DataFrame,仅保留df2的matching列是df1的id列子串的匹配项(反向子串不处理),同时标记精确匹配/子串匹配/无匹配,还要支持单个id对应多个子串的场景。


1. 基础实现(通用场景)

下面的代码直接实现需求,同时添加匹配类型标记,适合中等数据量:

import pandas as pd
import numpy as np

# 初始化示例数据
df1=pd.DataFrame({'id':['abc','adcfek','acefeasdq'],'numbers':[1,2,np.nan],'add_info':[3123,np.nan,312441]})
df2=pd.DataFrame({'matching':['adc','fek','acefeasdq','abcef','acce','dcf'],'needed_info':[1,2,3,4,5,6],'other_info':[22,33,11,44,55,66]})

# 收集所有有效匹配项
matched_records = []
for _, df1_row in df1.iterrows():
    # 筛选df2中matching是当前id子串的行
    valid_matches = df2[df2['matching'].apply(lambda x: x in df1_row['id'])].copy()
    if not valid_matches.empty:
        # 绑定df1当前行的所有字段
        valid_matches = pd.concat([pd.DataFrame([df1_row]*len(valid_matches)), valid_matches], axis=1)
        matched_records.append(valid_matches)

# 合并匹配结果与无匹配行
result = pd.concat(matched_records, ignore_index=True) if matched_records else pd.DataFrame()
no_match_rows = df1[~df1['id'].isin(result['id'])]
result = pd.concat([result, no_match_rows], ignore_index=True)

# 添加匹配类型标记
result['match_type'] = np.where(result['id'] == result['matching'], '精确匹配', '子串匹配')
result['match_type'] = result['match_type'].fillna('无匹配')

# 调整列顺序到期望格式
result = result[['id', 'numbers', 'add_info', 'needed_info', 'other_info', 'match_type']]
print(result)

输出结果

id  numbers  add_info  needed_info  other_info match_type
0     adcfek      2.0       NaN          2.0        33.0     子串匹配
1     adcfek      2.0       NaN          6.0        66.0     子串匹配
2  acefeasdq      NaN  312441.0          3.0        11.0     精确匹配
3        abc      1.0    3123.0          NaN         NaN       无匹配

2. 大数据量优化方案

如果数据量极大,循环遍历效率偏低,可以用笛卡尔积+向量化筛选的方式(注意:内存占用会更高,适合内存充足的场景):

# 生成笛卡尔积,临时用key字段关联
cross_join = df1.assign(temp_key=1).merge(df2.assign(temp_key=1), on='temp_key').drop('temp_key', axis=1)

# 筛选符合子串条件的行
valid_cross = cross_join[cross_join.apply(lambda x: x['matching'] in x['id'], axis=1)]

# 添加匹配标记
valid_cross['match_type'] = np.where(valid_cross['id'] == valid_cross['matching'], '精确匹配', '子串匹配')

# 合并无匹配行
no_match_rows = df1[~df1['id'].isin(valid_cross['id'])].assign(match_type='无匹配')

# 最终结果
result = pd.concat([valid_cross, no_match_rows], ignore_index=True)
result = result[['id', 'numbers', 'add_info', 'needed_info', 'other_info', 'match_type']]

3. 单个id对应多个子串的处理

如果需要把同一个id的多个匹配项聚合(比如合并成列表、取平均值等),可以用分组聚合:

# 基于上面的valid_cross结果进行聚合
aggregated_result = valid_cross.groupby(['id', 'numbers', 'add_info']).agg(
    needed_info=('needed_info', list),  # 把多个值合并成列表
    other_info=('other_info', list),
    match_type=('match_type', lambda x: ','.join(set(x)))  # 去重标记匹配类型
).reset_index()

# 合并无匹配行
final_result = pd.concat([aggregated_result, no_match_rows], ignore_index=True)

聚合后输出

id  numbers  add_info needed_info other_info match_type
0     adcfek      2.0       NaN      [2, 6]     [33,66]     子串匹配
1  acefeasdq      NaN  312441.0         [3]        [11]     精确匹配
2        abc      1.0    3123.0         NaN         NaN       无匹配

关键注意点

  • 严格遵循筛选逻辑:仅df2['matching']是df1['id']的子串时才保留,反向情况(比如df1的abc是df2的abcef的子串)会被自动排除。
  • 精确匹配会被单独标记,方便后续业务区分。
  • 超大数据量场景下,建议用分块处理或Dask并行计算库,避免内存溢出。

内容的提问来源于stack exchange,提问作者Yieh Yan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 02:05:19