如何按ID存储行历史值并在条件触发时更新Load编号与日期?
解决按ID分组的条件触发编号与日期填充问题
我来帮你搞定这个时序数据的分组计算问题~先说说你原来代码里的几个小问题:
- 全局变量
curr_load会在不同ID之间共享状态,导致编号串味(比如ID11的计数会接着ID10的数值继续加) - 手动循环ID的方式不仅效率低,而且代码里没把处理后的
data拼回newdata,等于白忙活 - Load的判断条件写错啦!你代码里判断的是
data['Load'] == 'Load',但实际数据里触发条件是Yes
其实用Pandas的分组和矢量化操作就能完美解决,根本不用递归或者手动循环每个ID,代码简洁还高效。
完整实现代码
import pandas as pd # 先构造你的示例数据(模拟输入) data = pd.DataFrame({ 'Date-Time': ['10/22/2019', '10/23/2019', '10/24/2019', '10/25/2019', '10/26/2019', '10/27/2019', '10/22/2019', '10/23/2019', '10/24/2019', '10/25/2019', '10/26/2019', '10/27/2019'], 'Volume': [3862, 3800, 3700, 5000, 4900, 4800, 3862, 3800, 3700, 5000, 4900, 4800], 'ID': [10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11], 'Load': ['', '', '', 'Yes', '', '', '', '', '', 'Yes', '', ''] }) # 处理Load_number列:按ID分组,每次遇到Load=Yes时递增,后续行沿用 data['Load_number'] = data.groupby('ID')['Load'].apply( lambda x: (x == 'Yes').cumsum() ).reset_index(level=0, drop=True) # 处理LoadDate列:按ID分组,记录最近一次Load=Yes的日期,无则填0 data['LoadDate'] = data.groupby('ID').apply( lambda x: x['Date-Time'].where(x['Load'] == 'Yes').ffill() ).reset_index(level=0, drop=True) # 把开头的NaN替换成0 data['LoadDate'] = data['LoadDate'].fillna(0) # 查看结果 print(data)
代码解释
Load_number 计算逻辑:
- 按
ID分组后,先把Load等于Yes的行标记为1,其他为0 - 用
cumsum()做累计求和,这样每遇到一次Yes,计数就加1,后续行自动继承当前的计数值,完美实现你要的"触发后递增,后续沿用"的效果
- 按
LoadDate 计算逻辑:
- 同样按
ID分组,只保留Load=Yes行的Date-Time,其他行设为NaN - 用
ffill()(向前填充)把NaN替换成最近一次出现的Yes对应的日期 - 最后把分组后开头的NaN(还没出现Yes的行)替换成0,符合你的示例要求
- 同样按
验证结果
运行代码后,输出会和你期望的示例完全一致:
- 每个ID的计数独立,不会互相干扰
- 触发Yes后,后续行的Load_number保持递增后的数值,LoadDate保持触发日期
- 未触发的行Load_number为0,LoadDate为0
内容的提问来源于stack exchange,提问作者Amogh
相关产品推荐
相关产品推荐

