如何用Pandas实现DataFrame按里程区间关联并分组聚合?
刚好做过类似的里程区间匹配+聚合场景,用Pandas完全可以实现这种SQL风格的关联分组逻辑,我给你一步步拆解:
1. 先模拟示例数据(方便你对照测试)
先造两个符合你描述的DataFrame,实际使用时替换成你的真实数据即可:
import pandas as pd import numpy as np # DataFrame1:5米间隔的里程区间数据 df_section = pd.DataFrame({ 'Section': ['A', 'A', 'B', 'B'], 'chainage_from': [0, 5, 0, 5], 'chainage_to': [5, 10, 5, 10], 'Frame': ['F1', 'F2', 'F3', 'F4'] }) # DataFrame2:1米间隔的测点数据 df_points = pd.DataFrame({ 'Section': ['A']*10 + ['B']*10, 'Chainage': list(range(0,10)) + list(range(0,10)), 'Col1': np.random.randint(1,10,20), 'Col2': np.random.randint(1,20,20), 'Col3': np.random.rand(20), 'Col4': np.random.rand(20), 'Col5': np.random.rand(20), 'Col6': np.random.rand(20), 'Col7': np.random.rand(20), 'Col8': np.random.rand(20) })
2. 核心:按Section关联+里程区间匹配
这里推荐用pd.merge_asof,它专门处理有序键的区间匹配,比循环/apply高效N倍,尤其适合大数据量。不过要先满足两个前提:
- 两个DataFrame都要按
Section和里程列排序 - 确保区间是连续不重叠的(你的数据是5米间隔,应该没问题)
代码实现:
# 先对两个表按Section+里程列排序(merge_asof要求右侧表的匹配键是有序的) df_section_sorted = df_section.sort_values(['Section', 'chainage_from']) df_points_sorted = df_points.sort_values(['Section', 'Chainage']) # 执行区间匹配:同Section下,把测点的Chainage匹配到对应的里程区间 merged = pd.merge_asof( df_points_sorted, df_section_sorted, left_on='Chainage', right_on='chainage_from', by='Section', # 按Section分组匹配,避免跨Section错误匹配 direction='backward' # 找到<=当前Chainage的最大chainage_from,也就是对应的区间 ) # 过滤掉Chainage超出区间上限的行(防止极端情况的错误匹配) merged = merged[merged['Chainage'] < merged['chainage_to']]
如果你的数据量极小,也可以用简单的apply方式(但效率低,不推荐大数据):
def map_to_frame(row): # 找到同Section下符合里程区间的Frame match = df_section[ (df_section['Section'] == row['Section']) & (df_section['chainage_from'] <= row['Chainage']) & (df_section['chainage_to'] > row['Chainage']) ] return match['Frame'].iloc[0] if not match.empty else None df_points['Frame'] = df_points.apply(map_to_frame, axis=1) merged = df_points.dropna(subset=['Frame'])
3. 按Frame分组聚合
最后一步就是按Frame分组,给不同列指定对应的聚合规则,和SQL的GROUP BY+聚合函数完全对应:
# 定义聚合规则字典:键是列名,值是对应的聚合方法 aggregation_rules = { 'Col1': 'sum', # 列1求和 'Col2': 'max', # 列2取最大值 'Col3': 'mean', # 列3求平均 'Col4': 'mean', 'Col5': 'mean', 'Col6': 'mean', 'Col7': 'mean', 'Col8': 'mean' } # 分组聚合,最后用reset_index把Frame从索引变回列 final_result = merged.groupby('Frame').agg(aggregation_rules).reset_index()
这样得到的final_result就是你要的目标输出啦!
几个关键注意事项
- 确保里程列(chainage_from/chainage_to/Chainage)的数据类型一致,比如都是int或float,避免匹配错误
- 如果你的Section是多维度分组(比如加个Line列),可以把
by参数改成列表:by=['Line', 'Section'] - 提前检查df_section的区间,确保每个Section下的区间是连续且不重叠的,否则会出现匹配混乱
内容的提问来源于stack exchange,提问作者user55641
相关产品推荐
相关产品推荐

