如何用Pandas实现无匹配列的DataFrame非精确比对?
问题描述
现有两个各含5000万行的DataFrame:
- df1:包含
Code(初始类型为int64)、Alias列 - df2:包含
To_check、Id列
二者无匹配列可用于merge,需要实现类似Bash中grep的功能——找出df1中Code转为字符串后,包含df2里To_check任意值的行(匹配值可在开头、中间或末尾)。
之前单个字符串匹配可行,但批量匹配代码返回空结果,相关代码示例:
单个匹配可行代码:
df3=df1[df1['Code'].astype('str').str.contains('701622')]
尝试的批量匹配代码(返回空):
s = dfcsv.set_index('Code').stack() df3 = s.str.extractall(f'({{"|".join(df2["To_Check"])}})')[0].reset_index(name='To_Check')
可行解决方案
方法1:正则表达式批量匹配(推荐)
str.contains()支持传入正则表达式,只需将df2的To_check值拼接为|分隔的正则模式即可,注意提前处理类型和特殊字符:
# 1. 处理To_check:转字符串、去重(减少正则长度提升性能) to_check_vals = df2['To_check'].astype(str).unique() # 2. 若To_check含正则特殊字符(如.、*、?),需先转义 import re to_check_pattern = '|'.join(re.escape(val) for val in to_check_vals) # 3. 执行批量匹配 df3 = df1[df1['Code'].astype(str).str.contains(to_check_pattern, na=False)]
方法2:矢量化广播匹配(适合小体量To_check)
如果df2的To_check数量较少,可利用numpy广播实现逐值匹配:
import numpy as np # 转成字符串数组 code_str = df1['Code'].astype(str).values[:, None] to_check_str = df2['To_check'].astype(str).values # 广播判断每行是否包含任意To_check值 matches = np.char.find(code_str, to_check_str) != -1 matches = matches.any(axis=1) df3 = df1[matches]
注意:该方法在To_check数量大时会占用大量内存,不适合df2也为千万级的场景。
方法3:Dask并行处理(内存友好)
若单机内存无法承载5000万行数据,可使用Dask进行并行处理:
import dask.dataframe as dd # 转为Dask DataFrame拆分分区 ddf1 = dd.from_pandas(df1, npartitions=8) to_check_vals = df2['To_check'].astype(str).unique() to_check_pattern = '|'.join(re.escape(val) for val in to_check_vals) # 并行匹配后计算结果 df3 = ddf1[ddf1['Code'].astype(str).str.contains(to_check_pattern, na=False)].compute()
原代码空结果原因
你之前的代码存在3个问题:
- 变量名错误:使用了未定义的
dfcsv,实际应为df1 - 正则语法错误:拼接时额外嵌套了大括号,正确写法应为
f'({"|".join(df2["To_check"].astype(str))})' stack()操作破坏了原DataFrame结构,导致匹配逻辑偏离预期
内容的提问来源于stack exchange,提问作者Vampire
相关产品推荐
相关产品推荐

