如何用另一Pandas DataFrame作为查找表替换DataFrame中的值?
Pandas按匹配规则替换DataFrame值的优化方案
需求说明
需要将df中的每个数值,替换为df2中对应行、对应列名(即df中的数值)的数值,最终得到目标结果。
示例数据
代码创建数据
import numpy as np import pandas as pd dt_index = pd.to_datetime(['2003-05-01', '2003-05-02', '2003-05-03', '2003-05-04']) df = pd.DataFrame({'A':[1,1,3,12], 'B':[12,1,3,3], 'C':[3,12,12,1]}, index = dt_index) df2 = pd.DataFrame({1:[1.4,4.2,1.3,5.6], 12:[2.3,7.3,9.5,0.4], 3:[8.8,0.1,8.7,2.4], 4:[9.6,9.8,5.5,1.8]}, index = dt_index)
数据展示
df内容:
A B C 2003-05-01 1 12 3 2003-05-02 1 1 12 2003-05-03 3 3 12 2003-05-04 12 3 1
df2内容:
1 12 3 4 2003-05-01 1.4 2.3 8.8 9.6 2003-05-02 4.2 7.3 0.1 9.8 2003-05-03 1.3 9.5 8.7 5.5 2003-05-04 5.6 0.4 2.4 1.8
预期输出
expect = pd.DataFrame({'A':[1.4,4.2,8.7,0.4], 'B':[2.3,4.2,8.7,2.4], 'C':[8.8,7.3,9.5,5.6]}, index = dt_index)
expect内容:
A B C 2003-05-01 1.4 2.3 8.8 2003-05-02 4.2 4.2 7.3 2003-05-03 8.7 8.7 9.5 2003-05-04 0.4 2.4 5.6
现有尝试代码
X = df.copy() for i in np.unique(df): X.mask(df == i, df2[i], axis=0, inplace=True)
疑问
现有代码看似可行,但不确定是否存在潜在问题,且当DataFrame规模增大时扩展性如何,希望得到更优、更快的解决方案。
补充说明:df中的值与df、df2的列不保证连续。
优化解决方案
方案1:基于Numpy索引的向量化操作(推荐,高效兼容新版本)
利用Numpy的向量化索引能力,直接定位df2中对应位置的值,完全避免循环,大数据量下性能最优:
# 构建df2列名到索引的映射 col_map = {col: idx for idx, col in enumerate(df2.columns)} # 将df的数值转换为df2对应的列索引 df_col_indices = df.applymap(lambda x: col_map[x]).to_numpy() # 按行、列索引提取df2中的值并重构为DataFrame result = pd.DataFrame( df2.to_numpy()[np.arange(len(df2))[:, None], df_col_indices], index=df.index, columns=df.columns )
方案2:使用melt+merge+pivot(逻辑直观,适合复杂场景)
通过数据重塑的方式实现,逻辑清晰易理解,适合数据量中等或需要调试的场景:
# 将df转为长格式 df_melt = df.reset_index().melt(id_vars='index', var_name='col', value_name='key') # 将df2转为长格式 df2_melt = df2.reset_index().melt(id_vars='index', var_name='key', value_name='value') # 匹配合并数据 merged = df_melt.merge(df2_melt, on=['index', 'key']) # 重塑回宽格式得到结果 result = merged.pivot(index='index', columns='col', values='value').rename_axis(None, axis=1)
方案3:DataFrame.lookup(适用于Pandas < 2.0版本)
lookup方法可直接按行和列的匹配关系提取值,代码简洁,但Pandas 2.0+已标记为弃用:
result = pd.DataFrame( df.lookup(df.index, df.values), index=df.index, columns=df.columns )
现有代码的潜在问题
- 性能瓶颈:循环遍历每个唯一值,每次
mask操作都要遍历整个DataFrame,数据量较大时(如上万行/列)会显著变慢。 - 容错性差:若
df中存在df2没有的列名,代码会直接报错,需额外添加判断逻辑处理此类情况。
内容的提问来源于stack exchange,提问作者handlist
相关产品推荐
相关产品推荐

