基于key1包含key2条件的Pandas自定义合并需求(含性能考量)
针对你这种小表匹配大表的子串合并需求,核心思路是减少大表的遍历次数,毕竟200万条数据反复遍历太耗资源。下面给你两种高效的实现方案,从易用到极致效率都有覆盖:
方案一:用Pandas向量化字符串操作(无需额外安装库)
这种方法利用Pandas的str.extractall做批量子串匹配,实现简单且效率足够应付你的数据规模:
import pandas as pd import re # 构造示例数据(实际使用时替换成你的真实数据) df1 = pd.DataFrame({ 'name': ['Bill Gates', 'Steve Jobs', 'Elon Musk'], 'info': ['Microsoft', 'Apple', 'Tesla'] }) df2 = pd.DataFrame({ 'name': ['Bill', 'Kate', 'Steve'], 'info': ['aaa', 'bbb', 'ccc'] }) # 1. 生成匹配df2所有name的正则模式(转义特殊字符避免匹配异常) pattern = '|'.join(re.escape(name) for name in df2['name']) pattern = f'({pattern})' # 用捕获组提取匹配的name # 2. 在df1中提取所有包含的df2的name matches = df1['name'].str.extractall(pattern) matches = matches.reset_index().rename(columns={0: 'df2_name', 'level_0': 'df1_index'}) # 3. 合并df1、df2数据得到结果 df3 = matches.merge(df1, left_on='df1_index', right_index=True) df3 = df3.merge(df2, left_on='df2_name', right_on='name') # 调整列名和顺序(和你的示例输出对齐,实际建议重命名避免列名重复) df3 = df3[['name_x', 'info_x', 'name_y', 'info_y']].rename(columns={ 'name_x': 'name', 'info_x': 'info', 'name_y': 'name', 'info_y': 'info' }) print(df3)
输出结果完全符合你的预期,而且因为只对小表(df1)做了字符串操作,大表(df2)只做了一次模式构建,整体速度非常快。
方案二:用AC自动机实现极致效率(适合超大规模数据)
如果你的df2数据量还会增长,或者追求更快的匹配速度,可以用pyahocorasick库实现多模式子串匹配,这是处理大量子串匹配的工业级方案:
- 先安装库:
pip install pyahocorasick
- 实现代码:
import pandas as pd import ahocorasick # 构造示例数据 df1 = pd.DataFrame({ 'name': ['Bill Gates', 'Steve Jobs', 'Elon Musk'], 'info': ['Microsoft', 'Apple', 'Tesla'] }) df2 = pd.DataFrame({ 'name': ['Bill', 'Kate', 'Steve'], 'info': ['aaa', 'bbb', 'ccc'] }) # 1. 构建AC自动机,把df2的name作为模式存入 automaton = ahocorasick.Automaton() for _, row in df2.iterrows(): automaton.add_word(row['name'], (row['name'], row['info'])) automaton.make_automaton() # 编译自动机 # 2. 遍历小表df1,批量匹配所有符合条件的df2记录 result_rows = [] for _, row_df1 in df1.iterrows(): # 在当前df1的name中查找所有匹配的df2的name for _, (matched_name, matched_info) in automaton.iter(row_df1['name']): result_rows.append({ 'name': row_df1['name'], 'info': row_df1['info'], 'name': matched_name, 'info': matched_info }) # 转成DataFrame得到结果 df3 = pd.DataFrame(result_rows) print(df3)
这种方法的时间复杂度是线性的,匹配速度比正则方法快一个数量级,完全能轻松应对200万条的df2数据。
注意事项
- 若df2的name包含正则特殊字符(如
.,*,+),方案一中的re.escape会自动转义,避免匹配出错; - 示例中结果列名重复,实际使用建议重命名为
df1_name,df1_info,df2_name,df2_info,方便后续数据处理; - 如果df2中存在重复的name,两种方案都会保留所有匹配结果,符合合并逻辑。
内容的提问来源于stack exchange,提问作者Kiki
相关产品推荐
相关产品推荐

