Pandas按serial_number分组,聚合update=False至下一行update=True数据
Pandas 分组聚合:合并False行到下一个True行并计算求和/均值
需求说明
给定包含serial_number(ID列)、update(布尔值列)和多列数值的DataFrame,需对同一serial_number分组内,从连续的update=False行到下一行update=True(包含该行)的数值列分别执行求和或均值计算,最终仅保留update=True的行,其数值替换为聚合结果,非数值列取update=True行的值。
示例输入
| serial_number | model | numerical_mean | numerical_1_sum | numerical_2_sum | update |
|---|---|---|---|---|---|
| a | 2023-01-01 | 5 | 10 | 20 | False |
| a | 2023-01-02 | 10 | 15 | 10 | False |
| a | 2023-01-03 | 15 | 15 | 10 | True |
| b | 2023-01-01 | 10 | 15 | 10 | False |
| b | 2023-01-02 | 15 | 15 | 10 | True |
| b | 2023-01-03 | 15 | 15 | 10 | False |
| b | 2023-01-04 | 15 | 15 | 10 | True |
| b | 2023-01-05 | 15 | 15 | 10 | False |
| c | 2023-01-04 | 15 | 15 | 10 | True |
解决步骤与代码
1. 构造示例数据
import pandas as pd data = { 'serial_number': ['a', 'a', 'a', 'b', 'b', 'b', 'b', 'b', 'c'], 'model': ['2023-01-01', '2023-01-02', '2023-01-03', '2023-01-01', '2023-01-02', '2023-01-03', '2023-01-04', '2023-01-05', '2023-01-04'], 'numerical_mean': [5, 10, 15, 10, 15, 15, 15, 15, 15], 'numerical_1_sum': [10, 15, 15, 15, 15, 15, 15, 15, 15], 'numerical_2_sum': [20, 10, 10, 10, 10, 10, 10, 10, 10], 'update': [False, False, True, False, True, False, True, False, True] } df = pd.DataFrame(data)
2. 标记聚合分组
按serial_number分组,用update列的累计求和生成分组ID,确保每个update=True行和其之前连续的False行归为同一组:
df['group_id'] = df.groupby('serial_number')['update'].cumsum().shift(fill_value=0)
3. 定义聚合规则
根据列名后缀区分求和/均值列,非数值列取组内最后一行(即update=True行)的值:
# 自动识别求和、均值列(可手动指定替换) sum_cols = [col for col in df.columns if '_sum' in col] mean_cols = [col for col in df.columns if '_mean' in col] other_cols = [col for col in df.columns if col not in sum_cols + mean_cols + ['group_id']] # 构建聚合字典 agg_dict = {} for col in sum_cols: agg_dict[col] = 'sum' for col in mean_cols: agg_dict[col] = 'mean' for col in other_cols: agg_dict[col] = 'last'
4. 分组聚合并过滤结果
# 分组聚合 result = df.groupby(['serial_number', 'group_id']).agg(agg_dict).reset_index(drop=True) # 仅保留update=True的行(过滤无对应True行的末尾False行) result = result[result['update']].reset_index(drop=True) # 列名对齐示例输出 result = result.rename(columns={'model': 'date'})
最终输出
运行上述代码后,result即为期望输出:
| serial_number | date | numerical_mean | numerical_1_sum | numerical_2_sum | update |
|---|---|---|---|---|---|
| a | 2023-01-03 | 10.0 | 40 | 40 | True |
| b | 2023-01-02 | 12.5 | 30 | 20 | True |
| b | 2023-01-04 | 15.0 | 30 | 20 | True |
| c | 2023-01-04 | 15.0 | 15 | 10 | True |
补充说明
- 如果列名没有
_sum/_mean的命名规则,可直接手动指定sum_cols和mean_cols列表。 - 分组内末尾的
update=False行(如示例中b的2023-01-05)因无对应True行,会被自动过滤,符合机器学习训练数据的需求。
内容的提问来源于stack exchange,提问作者bktllr
相关产品推荐
相关产品推荐

