如何在指定条件区间内为DataFrame填充cummax与cummin列
问题描述
需要在DataFrame的Condition列中,仅对A与B之间的区间(包含A和B本身)计算并填充滚动累积最大值(cummax)和累积最小值(cummin);不在该区间内的行则留空。
期望输出示例:
| Condition | Value | Cummax | Cummin |
|---|---|---|---|
| A | -1 | -1 | -1 |
| 2 | 2 | -1 | |
| 3 | 3 | -1 | |
| B | 1 | 3 | -1 |
| A | 1 | 1 | 1 |
| 1 | 1 | 1 | |
| -1 | 1 | -1 | |
| B | 1 | 1 | -1 |
| 3 | |||
| A | 2 | 2 | 2 |
| 1 | 2 | 1 | |
| B | -2 | 2 | -2 |
尝试过以下代码,但会计算全局累积最大值,无法满足区间独立计算的需求:
df.loc[(df['Condition'].ffill()=="A")|(df['Condition']=="B"), "Cummax"] = df["Value"].cummax()
解决方案
核心思路是将每个A-B区间拆分为独立分组,在分组内计算累积值,而非全局计算。具体实现代码如下:
import pandas as pd # 示例数据(可替换为你的实际数据) data = { 'Condition': ['A', '', '', 'B', 'A', '', '', 'B', '', 'A', '', 'B'], 'Value': [-1, 2, 3, 1, 1, 1, -1, 1, 3, 2, 1, -2] } df = pd.DataFrame(data) # 1. 为每个以A开头的区间分配唯一分组ID df['group_id'] = df['Condition'].eq('A').cumsum() # 2. 标记每个分组内从A到第一个B的有效行(包含B) def mark_valid_interval(group): first_b_pos = group[group['Condition'] == 'B'].index.min() if pd.notna(first_b_pos): group['is_valid'] = group.index <= first_b_pos else: # 无B的分组直接标记为无效 group['is_valid'] = False return group df = df.groupby('group_id').apply(mark_valid_interval).reset_index(drop=True) # 3. 仅对有效行计算分组内的累积最大/最小值 df['Cummax'] = df.groupby('group_id')['Value'].transform( lambda x: x.cummax() if x.name in df[df['is_valid']]['group_id'].unique() else pd.NA ) df['Cummin'] = df.groupby('group_id')['Value'].transform( lambda x: x.cummin() if x.name in df[df['is_valid']]['group_id'].unique() else pd.NA ) # 4. 清空无效行的累积值 df.loc[~df['is_valid'], ['Cummax', 'Cummin']] = pd.NA # 清理辅助列(可选) df = df.drop(['group_id', 'is_valid'], axis=1) print(df)
代码逻辑说明
- 分组拆分:通过
cumsum()统计Condition为'A'的次数,将每个A开头的区间划分为独立分组,确保累积计算不会跨区间干扰。 - 有效行标记:在每个分组内定位第一个'B'的位置,仅保留从A到该B的行作为计算对象,B之后的行(如示例中第9行)标记为无效。
- 分组内累积计算:针对每个有效分组,单独计算组内的
cummax和cummin,彻底解决全局累积的问题。 - 无效行处理:将无效行的累积值设为空,匹配期望输出格式。
内容的提问来源于stack exchange,提问作者Akav
相关产品推荐
相关产品推荐

