如何在Pandas DataFrame中提取所有区间并计算重叠段N列总和
解决方法
方法一:基础实现(适合小数据量)
1. 提取所有时间临界点
把原始数据里的Start和End值全部收集起来,去重后排序,这些点就是拆分区间的边界:
import pandas as pd # 构造原始数据 df = pd.DataFrame({ 'Id': [1,2,3,4], 'Start': [0,0,10,15], 'End': [10,10,20,25], 'N': [10,10,5,10] }) # 提取并排序所有时间点 time_points = sorted(set(df['Start'].tolist() + df['End'].tolist()))
2. 生成拆分后的区间
用相邻的时间点组成新的区间:
intervals = pd.DataFrame({ 'Start': time_points[:-1], 'End': time_points[1:] })
3. 计算每个区间的N值总和
对每个拆分后的区间,筛选出所有和它重叠的原始行,把这些行的N加起来:
def get_overlap_sum(row): # 判断原始行与当前区间是否重叠:原始Start < 当前End,且原始End > 当前Start overlap_mask = (df['Start'] < row['End']) & (df['End'] > row['Start']) return df.loc[overlap_mask, 'N'].sum() intervals['Sum'] = intervals.apply(get_overlap_sum, axis=1)
运行后intervals就是目标结果,和示例输出完全一致。
方法二:向量化实现(适合大数据量)
如果数据量很大,apply循环效率低,用事件累积的思路优化:
1. 生成事件数据
把每个原始区间的Start标记为“+N”事件,End标记为“-N”事件:
# 生成Start事件(加N) start_events = df[['Start', 'N']].rename(columns={'Start': 'Time', 'N': 'Delta'}) # 生成End事件(减N) end_events = df[['End', 'N']].rename(columns={'End': 'Time', 'N': 'Delta'}) end_events['Delta'] = -end_events['Delta'] # 合并所有事件 events = pd.concat([start_events, end_events]).sort_values('Time').reset_index(drop=True)
2. 计算累积和
按时间排序后,计算Delta的累积和,这个累积和就是对应时间段的N值总和:
events['CumSum'] = events['Delta'].cumsum()
3. 生成最终区间
用相邻时间点组成区间,对应的累积和就是该区间的总和:
result = pd.DataFrame({ 'Start': events['Time'][:-1], 'End': events['Time'][1:], 'Sum': events['CumSum'][:-1] }) # 去重(处理同一时间点的多个事件) result = result.drop_duplicates(subset=['Start', 'End']).reset_index(drop=True)
这种方法全程用向量化操作,速度比循环快很多,适合处理十万级以上的数据。
内容的提问来源于stack exchange,提问作者G. Bittencourt
相关产品推荐
相关产品推荐

