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

如何用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个问题:

  1. 变量名错误:使用了未定义的dfcsv,实际应为df1
  2. 正则语法错误:拼接时额外嵌套了大括号,正确写法应为f'({"|".join(df2["To_check"].astype(str))})'
  3. stack()操作破坏了原DataFrame结构,导致匹配逻辑偏离预期

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 15:30:49