如何在两个DataFrame间按Range列映射值并执行除法运算
高效实现DataFrame元素按区间匹配的除法运算
问题概述
现有两个Pandas DataFrame:df和df2,二者列名基本一致(df2多一列Range存储数值区间)。需要对df中的每个元素,根据其值所在的df2区间,找到df2对应列的元素,执行df元素 / df2对应元素的运算,要求高效实现,避免逐元素循环。
原始数据定义
import pandas as pd # 定义df d = {'Col1': [10,67], 'Col2': [30,10],'Col3': [70,40]} df = pd.DataFrame(data=d) # 定义df2 df2 = pd.DataFrame( data=[[25,36,47,(0,20)], [70,85,95,(20,40)], [12,35,49,(40,60)], [50,49,21,(60,80)], [60,75,38,(80,100)]], columns=["Col1","Col2","Col3","Range"] )
解决方案一:按列批量处理(简洁高效)
这种方法通过pd.cut快速匹配区间索引,直接对整列进行运算,仅需遍历列(列数通常远少于行数),效率很高。
result_df = df.copy() # 提取区间的上下限,生成用于cut的bins bins = [interval[0] for interval in df2['Range']] + [df2['Range'].iloc[-1][1]] for col in df.columns: # 为df当前列的每个值匹配对应的区间索引 interval_indices = pd.cut( df[col], bins=bins, labels=False, include_lowest=True # 确保最小值落在第一个区间内 ) # 提取df2对应列的匹配值,执行除法运算 result_df[col] = df[col] / df2[col].iloc[interval_indices].values
运行后result_df的输出:
Col1 Col2 Col3 0 0.400 0.352941 3.333333 1 1.340 0.277778 0.816327
解决方案二:长格式合并(适合超大数据集)
如果数据集行数极多,可通过merge_asof实现基于排序的高效合并,时间复杂度为O(n log n),避免列循环。
- 预处理
df2,拆分区间为上下限:
df2[['lower', 'upper']] = pd.DataFrame(df2['Range'].tolist(), index=df2.index)
- 将
df转为长格式,方便按值和列名匹配:
df_melt = df.reset_index().melt(id_vars='index', var_name='column', value_name='df_value')
- 对
df2和df_melt排序,满足merge_asof的要求:
df2_sorted = df2.sort_values('lower') df_melt_sorted = df_melt.sort_values('df_value')
- 按列分组匹配区间,计算除法后转回原格式:
# 将df2的列也转为长格式,方便匹配 df2_melt = df2_sorted.melt( id_vars=['lower', 'upper'], var_name='column', value_name='df2_value' ) # 用merge_asof按列匹配区间 merged = pd.merge_asof( df_melt_sorted, df2_melt, by='column', left_on='df_value', right_on='lower', direction='backward' ) # 过滤出值在区间内的行(确保df_value < upper) merged = merged[merged['df_value'] < merged['upper']] # 计算除法并转回原DataFrame结构 merged['result'] = merged['df_value'] / merged['df2_value'] result_df = merged.pivot(index='index', columns='column', values='result').rename_axis(None, axis=1)
关键说明
- 两种方法均避免了逐元素循环,适合大规模数据处理;
- 区间匹配默认采用左闭右开规则(如
(0,20)包含0但不包含20),若需调整可修改pd.cut的right参数或merge_asof的过滤条件; merge_asof方法更适合列数多、行数极大的场景,按列处理的方法则更简洁易读。
内容的提问来源于stack exchange,提问作者Martin Yordanov Georgiev
相关产品推荐
相关产品推荐

