基于Pandas实现可变长度子数组列求和并扩展结果列
解决Pandas中按标记分段求和并提取起止时间的问题
问题场景
我正在尝试对DataFrame中的数据进行求和与整理,现有简化后的数据结构如下:
| latitude | longitude | time | t2m | av | kont |
|---|---|---|---|---|---|
| ... | 46.5 | 1998-01-12 07:00:00 | 0.284698 | ... | 0.001613 |
| 18.0 | ... | 1998-01-24 08:00:00 | -1.304504 | ... | 0.001418 FROMHERE |
| 18.0 | ... | 1998-01-24 09:00:00 | -1.113770 | ... | 0.002679 |
| 18.0 | ... | 1998-01-24 17:00:00 | 0.345001 | ... | 0.004633 FROMHERE |
| 18.0 | ... | 1998-01-24 18:00:00 | -0.122498 | ... | 0.004400 |
| 18.0 | ... | 1998-01-24 19:00:00 | 0.041565 | ... | 0.002184 |
| 18.0 | ... | 1998-01-24 20:00:00 | 0.100861 | ... | 0.002220 |
| 18.0 | ... | 1998-01-24 21:00:00 | 0.120636 | ... | 0.003083 |
| 18.0 | ... | 1998-01-24 22:00:00 | -0.615662 | ... | 0.004330 |
| 18.0 | ... | 1998-01-24 23:00:00 | -0.686798 | ... | 0.002404 |
| 18.0 | ... | 1998-01-25 00:00:00 | -0.743134 | ... | 0.000953 |
| 18.0 | ... | 1998-01-29 02:00:00 | -4.786346 | ... | 0.002984 FROMHERE |
我的目标是对**FROMHERE标记之间**的av列数据求和,并添加time列中的起止日期(d1、d2),期望输出如下:
| latitude | longitude | t2m | ... | kont | sum | d1 | d2 |
|---|---|---|---|---|---|---|---|
| ... | 46.5 | 0.284698 | ... | 0.001613 | ... | 1998-01-12 07:00:00 | 1998-01-24 08:00:00 |
| 18.0 | ... | -1.304504 | ... | FROMHERE | 0.004097 | 1998-01-24 08:00:00 | 1998-01-24 09:00:00 |
| 18.0 | ... | 0.345001 | ... | FROMHERE | 0.024207 | 1998-01-24 17:00:00 | 1998-01-25 00:00:00 |
| 18.0 | ... | -4.786346 | ... | FROMHERE | xxxxxx | 1998-01-29 02:00:00 | ... |
我已尝试通过df.loc创建kont列来实现子数组求和,但陷入瓶颈。由于数据量庞大,希望采用Pandas原生向量化计算的解决方案,恳请提供帮助与思路。
解决方案(纯向量化,无循环)
这是典型的按标记分段聚合问题,完全可以用Pandas的分组聚合能力高效解决,全程避免循环,适配大数据量场景:
步骤1:提取标记并生成分组ID
首先我们需要把FROMHERE标记提取出来,然后用它生成唯一的分组ID,每个分组对应两个标记之间的区间:
# 1. 提取FROMHERE标记(假设标记在kont列末尾) df['is_from_here'] = df['kont'].str.endswith('FROMHERE', na=False) # 清理kont列的标记文本,还原原始数值 df['kont'] = df['kont'].str.replace(' FROMHERE', '', regex=False) # 2. 生成分组ID:每次遇到FROMHERE就开启新分组 # 注意:第一个分组是从数据开头到第一个FROMHERE之前的部分 df['group_id'] = df['is_from_here'].cumsum()
步骤2:分组聚合计算核心指标
用groupby结合agg一次性计算每个分组的av求和、起止时间,全程向量化:
# 对每个分组聚合:sum_av是av列求和,d1是分组最早时间,d2是分组最晚时间 group_stats = df.groupby('group_id').agg( sum_av=('av', 'sum'), d1=('time', 'first'), d2=('time', 'last') ).reset_index()
步骤3:合并结果并整理格式
把聚合结果对应到每个FROMHERE行,同时处理开头的无标记分组:
# 1. 处理所有FROMHERE标记行,关联分组统计结果 result = df[df['is_from_here']].merge(group_stats, on='group_id', how='left') # 把kont列替换为FROMHERE标记 result['kont'] = 'FROMHERE' # 2. 处理开头的无标记分组(从数据起始到第一个FROMHERE) first_group = df[df['group_id'] == 0] if not first_group.empty: first_summary = pd.DataFrame({ 'latitude': [first_group['latitude'].iloc[0]], 'longitude': [first_group['longitude'].iloc[0]], 't2m': [first_group['t2m'].iloc[0]], 'kont': [first_group['kont'].iloc[0]], 'sum': [first_group['av'].sum()], 'd1': [first_group['time'].iloc[0]], 'd2': [first_group['time'].iloc[-1]] }) # 合并到最终结果 result = pd.concat([first_summary, result], ignore_index=True) # 3. 处理最后一个分组的d2(如果没有后续数据,设为缺失值) last_row_idx = result.index[-1] if result.loc[last_row_idx, 'd1'] == result.loc[last_row_idx, 'd2']: result.loc[last_row_idx, 'd2'] = pd.NA # 调整列顺序匹配期望输出 result = result[['latitude', 'longitude', 't2m', 'kont', 'sum', 'd1', 'd2']]
关键优势说明
- 纯向量化:全程使用Pandas原生分组聚合函数,没有逐行循环,处理百万级数据也能保持高效。
- 边界全覆盖:自动处理开头无标记分组、末尾未闭合分组的特殊情况,确保结果完整。
- 可扩展性:如果需要添加其他聚合指标(比如t2m的平均值),直接在
agg里新增字段即可。
内容的提问来源于stack exchange,提问作者user2727167
相关产品推荐
相关产品推荐

