如何用Pandas DataFrames实现PySpark的字符串包含左连接?
Pandas实现PySpark的包含式左连接
要在Pandas中实现PySpark df.join(df2, df.name.contains(df2.text), "left") 的功能(左表所有行保留,匹配右表中text被包含在左表name中的所有行),可以根据数据量大小选择不同的方案:
一、小数据量场景(快速实现)
如果两张表的数据量不大,可以直接用逐行匹配后合并的方式:
import pandas as pd # 示例数据 df = pd.DataFrame({'name': ['Alice Smith', 'Bob Johnson', 'Charlie Brown', 'David Lee']}) df2 = pd.DataFrame({'text': ['Smith', 'John', 'Brown', 'Davis'], 'value': [10, 20, 30, 40]}) # 找出当前name对应的所有df2匹配行 def get_matching_rows(name): return df2[df2['text'].apply(lambda x: x in name)] # 生成每个name的匹配结果并合并 matched_rows = df.apply( lambda row: pd.concat([pd.DataFrame([row]*len(get_matching_rows(row['name']))), get_matching_rows(row['name'])], axis=1), axis=1 ) result = pd.concat(matched_rows.tolist(), ignore_index=True) # 补充无匹配的行(右表字段填充NaN) no_match_rows = df[~df['name'].isin(result['name'].unique())] no_match_rows = no_match_rows.join(pd.DataFrame(columns=df2.columns)) result = pd.concat([result, no_match_rows], ignore_index=True)
二、大数据量场景(高效优化)
当表数据量较大时,逐行计算效率极低,推荐使用矢量化字符串操作+正则匹配的方案,避免笛卡尔积和逐行计算:
import pandas as pd import re # 示例数据 df = pd.DataFrame({'name': ['Alice Smith', 'Bob Johnson', 'Charlie Brown', 'David Lee']}) df2 = pd.DataFrame({'text': ['Smith', 'John', 'Brown', 'Davis'], 'value': [10, 20, 30, 40]}) # 1. 构建转义后的正则模式(避免特殊字符干扰匹配) pattern = '|'.join(re.escape(text) for text in df2['text']) # 2. 提取每个name中匹配的所有text,生成列表 df['matched_text'] = df['name'].str.findall(pattern) # 3. 展开匹配列表,实现一对多关联 df_exploded = df.explode('matched_text') # 4. 左连接df2,得到完整结果 result = df_exploded.merge(df2, left_on='matched_text', right_on='text', how='left') # 清理临时列 result = result.drop('matched_text', axis=1)
注意事项
- 如果
df2的text包含正则特殊字符(如.、*、?),必须用re.escape()转义,否则会出现错误匹配。 - 若两张表都是超大规模数据(千万级以上),Pandas的内存可能无法承载,此时可以考虑用Dask DataFrames(兼容Pandas API的分布式框架)来实现类似逻辑。
内容的提问来源于stack exchange,提问作者Miguel
相关产品推荐
相关产品推荐

