Pandas多条件滚动计数需求:基于奶牛泌乳期及DIM间隔的累计计数调整
解决Pandas多条件滚动计数问题(按奶牛泌乳期重置+时间间隔判断)
没问题,我来帮你实现这个带时间间隔条件的滚动计数需求!我们可以通过分组计算差值、标记递增条件,再累计求和的方式,完美得到你想要的Adjusted列。
完整实现代码
import pandas as pd # 初始化你的原始数据 l1 =["1", "1", "1", "2", "2", "2", "2", "2"] l2 =[1, 2, 2, 2, 2, 2, 2, 3] l3 =[45, 25, 28, 70, 95, 98, 120, 80] cowmast = pd.DataFrame(list(zip(l1, l2, l3)), columns=['Cow', 'Lact', 'DIM']) # --- 生成你原有的xmast和Lxmast列(如果需要保留)--- def rolling_count(val): if val == rolling_count.previous: rolling_count.count +=1 else: rolling_count.previous = val rolling_count.count = 1 return rolling_count.count rolling_count.count = 0 rolling_count.previous = None cowmast['xmast'] = cowmast['Cow'].apply(rolling_count) def count_consecutive_items_n_cols(df, col_name_list, output_col): cum_sum_list = [ (df[col_name] != df[col_name].shift(1)).cumsum().tolist() for col_name in col_name_list ] df[output_col] = df.groupby( ["_".join(map(str, x)) for x in zip(*cum_sum_list)] ).cumcount() + 1 return df count_consecutive_items_n_cols(cowmast, ['Cow', 'Lact'], 'Lxmast') # --- 核心:生成Adjusted列 --- # 1. 按Cow和Lact分组,计算组内相邻行的DIM差值 cowmast['dim_diff'] = cowmast.groupby(['Cow', 'Lact'])['DIM'].diff() # 2. 标记需要递增计数的情况:组内第一行(diff为NaN) 或 DIM差值超过7天 cowmast['incr_flag'] = (cowmast['dim_diff'].isna()) | (cowmast['dim_diff'] > 7) # 3. 按Cow和Lact分组,对标记列做累计求和,得到最终的Adjusted计数 cowmast['Adjusted'] = cowmast.groupby(['Cow', 'Lact'])['incr_flag'].cumsum().astype(int) # 查看最终结果 print(cowmast[['Cow', 'Lact', 'DIM', 'xmast', 'Lxmast', 'Adjusted']])
代码逻辑解释
计算组内DIM差值:
使用groupby(['Cow', 'Lact'])['DIM'].diff(),确保我们只计算同一奶牛同一泌乳期内的相邻天数差,每个组的第一行会得到NaN(因为没有上一行数据)。标记递增条件:
我们只在两种情况下让计数递增:- 该行是当前
Cow-Lact组的第一行(对应dim_diff为NaN) - 相邻两天的差值超过7天(
dim_diff >7)
用布尔值生成incr_flag列,满足条件为True(等价于1),否则为False(等价于0)。
- 该行是当前
累计求和生成计数:
在每个Cow-Lact组内对incr_flag做累计求和,这样每次满足条件时计数就加1,不满足时保持不变,同时实现了按组重置计数的需求。
最终输出结果
运行代码后,你会得到和预期完全一致的表格:
| Cow | Lact | DIM | xmast | Lxmast | Adjusted | |
|---|---|---|---|---|---|---|
| 0 | 1 | 1 | 45 | 1 | 1 | 1 |
| 1 | 1 | 2 | 25 | 2 | 1 | 1 |
| 2 | 1 | 2 | 28 | 3 | 2 | 1 |
| 3 | 2 | 2 | 70 | 1 | 1 | 1 |
| 4 | 2 | 2 | 95 | 2 | 2 | 2 |
| 5 | 2 | 2 | 98 | 3 | 3 | 2 |
| 6 | 2 | 2 | 120 | 4 | 4 | 3 |
| 7 | 2 | 3 | 80 | 5 | 1 | 1 |
内容的提问来源于stack exchange,提问作者JohnH
相关产品推荐
相关产品推荐

