如何在Pandas中实现跨DataFrame区间匹配并计算对应值?
DataFrame区间匹配并添加计算列解决方案
问题场景
现有两个DataFrame:
import pandas as pd data = {'A': [0,11,21,31,41,51,61], 'B': [10,20,30,40,50,60,70]} data2 = {'Point': [11.5, 18.3, 31.3, 41.2, 51.5, 66.6, 34.7, 12.1, 14.4, 56.8, 54.3]} df = pd.DataFrame(data) df2 = pd.DataFrame(data2)
需求:判断df2['Point']的每个值是否落在df中A与B组成的区间(如[0,10]、[11,20]等)内,若匹配成功,将对应行的A+B值作为新列sum_AB添加到df2中。
解决方案
方法1:使用merge_asof(高效推荐,适合大数据集)
merge_asof是Pandas专门用于有序键值匹配的工具,能高效处理区间匹配场景:
# 提前计算A+B的结果列 df['sum_AB'] = df['A'] + df['B'] # 确保df按A排序(merge_asof要求左表按键有序) df = df.sort_values('A').reset_index(drop=True) # 对df2按Point排序(merge_asof要求右表按键有序) df2_sorted = df2.sort_values('Point').reset_index(drop=True) # 匹配小于等于Point的最大A值,再过滤Point不超过对应B的行 result = pd.merge_asof(df2_sorted, df, left_on='Point', right_on='A', direction='backward') result = result[result['Point'] <= result['B']] # 合并回原df2,保留原始行顺序 final_df = df2.merge(result[['Point', 'sum_AB']], on='Point', how='left')
方法2:pd.cut+映射(简洁直观)
针对你之前用pd.cut仅得到区间的问题,只需添加一步映射即可获取目标值:
# 构造与df区间完全对应的IntervalIndex(闭区间) intervals = pd.IntervalIndex.from_arrays(df['A'], df['B'], closed='both') # 为每个Point匹配对应的区间 df2['interval'] = pd.cut(df2['Point'], bins=intervals) # 建立区间到sum_AB的映射关系 interval_to_sum = pd.Series(df['A'] + df['B'], index=intervals) # 映射得到sum_AB列 df2['sum_AB'] = df2['interval'].map(interval_to_sum) # 清理临时列 df2.drop('interval', axis=1, inplace=True)
方法3:apply逐行匹配(适合小数据集)
若数据量较小,可直接用apply逐行查找匹配区间:
def get_sum_ab(point): # 筛选出包含当前Point的区间行 match_row = df[(df['A'] <= point) & (df['B'] >= point)] return match_row['A'].iloc[0] + match_row['B'].iloc[0] if not match_row.empty else None df2['sum_AB'] = df2['Point'].apply(get_sum_ab)
结果示例
处理后df2的sum_AB列结果如下:
| Point | sum_AB |
|---|---|
| 11.5 | 31 |
| 18.3 | 31 |
| 31.3 | 71 |
| 41.2 | 91 |
| 51.5 | 111 |
| 66.6 | NaN |
| 34.7 | 71 |
| 12.1 | 31 |
| 14.4 | 31 |
| 56.8 | 111 |
| 54.3 | 111 |
内容的提问来源于stack exchange,提问作者zeroz
相关产品推荐
相关产品推荐

