Pandas GroupBy按id分组每N行统计值变化计算每分钟变化率
Pandas实现分机器统计每分钟value变化率方案
核心逻辑拆解
整个实现分4步完成,完全匹配需求的中间计算逻辑:
- 按机器id分组,标记每条记录相对同组上一条记录的value是否发生变化,单台机器的首条作业无前置参考,不计入变化
- 按机器id分组,为组内每条作业分配窗口编号:每3条连续作业划分为1个窗口(对应60秒时长),窗口编号从0开始递增
- 按「机器id+窗口编号」分组,统计每个窗口内的value变化总次数,得到需求指定的中间结果表
- 按机器id分组,用单台机器的总变化次数除以对应窗口总数,得到每分钟的平均变化率
完整可运行代码
import pandas as pd def calc_change_rate(df): # 1. 标记分组内相邻记录的value变化 df['is_change'] = df.groupby('id')['value'].diff().ne(0).astype(int) # 2. 分组内分配窗口编号,每3条作业一个窗口 df['window_id'] = df.groupby('id').cumcount() // 3 # 3. 统计每个窗口的变化次数,得到中间结果 window_stats = df.groupby(['id', 'window_id'], as_index=False)['is_change'].sum() window_stats = window_stats.rename(columns={'is_change': 'changes'}) # 4. 计算单台机器的每分钟平均变化率 id_total = window_stats.groupby('id').agg( total_changes=('changes', 'sum'), window_cnt=('window_id', 'nunique') ) id_total['rate'] = id_total['total_changes'] / id_total['window_cnt'] final_result = id_total[['rate']].reset_index() return window_stats, final_result
结果验证
第一个基础示例验证
# 构造第一个示例数据 df1 = pd.DataFrame({ "id": [1,1,1,1,2,2,2,2,2,3,3,3,3], "job": [1,2,3,4,1,2,3,4,5,1,2,3,4], "value": [42,42,42,45,38,38,40,40,42,44,44,43,43] }) window_df1, res1 = calc_change_rate(df1) print("=== 中间窗口统计结果 ===") print(window_df1) print("\n=== 最终变化率结果 ===") print(res1)
运行输出和需求给出的预期完全一致:
=== 中间窗口统计结果 === id window_id changes 0 1 0 0 1 1 1 1 2 2 0 1 3 2 1 1 4 3 0 1 5 3 1 0 === 最终变化率结果 === id rate 0 1 0.5 1 2 1.0 2 3 0.5
第二个补充测试用例验证
# 构造补充测试数据 df2 = pd.DataFrame({ "id": [1,1,1,1,1,1,2,2,2,3,3,3,3], "job": [1,2,3,4,5,6,1,2,3,1,2,3,4], "value": [0,1,2,3,4,5,0,0,0,0,1,1,2] }) window_df2, res2 = calc_change_rate(df2) print(res2)
运行输出完全匹配预期:
id rate 0 1 2.5 1 2 0.0 2 3 1.0
关键避坑点
- 计算value变化必须在
id分组内调用diff(),禁止直接对全表做shift/diff,否则会把不同机器的首尾作业误判为值变化 - 窗口编号必须使用分组内累计序号
groupby('id').cumcount() // 3生成,禁止直接用全局索引整除3,否则会把不同机器的作业错误划分到同一窗口 - 跨窗口相邻作业(上一窗口最后一条、下一窗口第一条)的值变化,会计入后一窗口的统计,和需求给出的中间结果逻辑完全对齐
内容的提问来源于stack exchange,提问作者thenewjames
相关产品推荐
相关产品推荐

