基于范围的DataFrame左连接实现问询(无需显式指定列)
方法一:使用merge_asof(推荐,适合大数据量)
因为你的df1中的区间是连续且不重叠的,而且df2['x']是有序的,merge_asof是高效又简洁的选择,完全不需要显式列出所有非范围列:
import pandas as pd import numpy as np # 初始化数据 df1 = pd.DataFrame({ 'col1': ['A', 'B', 'C', 'D','E'], 'col2': ['alpha', 'beta', 'gamma', 'delta','epsilon'], 'min': [0, 15, 20, 90, 100], 'max': [15, 20, 90, 100, 200] }) df2 = pd.DataFrame({'x': np.linspace(0,199, 6)}) # merge_asof要求两个DataFrame按匹配键排序 df1_sorted = df1.sort_values('min') df2_sorted = df2.sort_values('x') # 匹配逻辑:找到小于等于当前x的最大min值对应的行 merged = pd.merge_asof(df2_sorted, df1_sorted, left_on='x', right_on='min', direction='backward') # 过滤掉x超出对应区间max的情况(你的数据区间连续,这一步可省略,但更严谨) final_result = merged[merged['x'] <= merged['max']] # 保留需要的列(如果要保留所有非范围列,直接去掉这一步即可) final_result = final_result[['x', 'col1', 'col2']].reset_index(drop=True) print(final_result)
输出结果和你期望的完全一致:
x col1 col2 0 0.0 A alpha 1 39.8 C gamma 2 79.6 C gamma 3 119.4 E epsilon 4 159.2 E epsilon 5 199.0 E epsilon
方法二:使用IntervalIndex(直观易懂)
这个方法通过把df1的min和max转换成区间索引,直接匹配x所在的区间,同样不需要手动列所有非范围列:
import pandas as pd import numpy as np # 初始化数据 df1 = pd.DataFrame({ 'col1': ['A', 'B', 'C', 'D','E'], 'col2': ['alpha', 'beta', 'gamma', 'delta','epsilon'], 'min': [0, 15, 20, 90, 100], 'max': [15, 20, 90, 100, 200] }) df2 = pd.DataFrame({'x': np.linspace(0,199, 6)}) # 创建左闭右开的区间索引(对应逻辑:min <= x < max) df1['interval'] = pd.IntervalIndex.from_arrays(df1['min'], df1['max'], closed='left') # 将区间设为索引,方便快速匹配 df1_interval = df1.set_index('interval') # 对每个x找到对应的区间行,合并到df2 matches = df2['x'].apply(lambda x: df1_interval.loc[x]) final_result = pd.concat([df2, matches.drop(columns=['min', 'max', 'interval'])], axis=1) print(final_result)
为什么这两个方法都不用显式写非范围列?
merge_asof会自动把df1的所有列合并过来,你只需要最后筛选保留需要的列(或者直接保留全部);IntervalIndex方式中,df1_interval.loc[x]会返回对应区间的整行数据,你只需要排除min、max、interval这些范围相关列即可,其他列自动保留。
内容的提问来源于stack exchange,提问作者user32882
相关产品推荐
相关产品推荐

