在 df 列中指定可变窗口大小的 Pandas rolling_max

Nik*_*y G 5 python pandas

我想计算一个 pandas 列的滚动最大值,其中窗口大小不同,并且是当前行索引与满足特定条件的行之间的差异。

所以,作为一个例子,我有:

df = pd.DataFrame({'a': [0,1,0,0,0,1,0,0,0,0,1,0],
                   'b': [5,4,3,6,1,2,3,4,2,1,7,8]})
Run Code Online (Sandbox Code Playgroud)

我想要 df.b 的滚动最大值,因为上一次 df.a == 1。即我想得到这个:

     a   b   rm
 0   0   5   NaN  <- no previous a==1
 1   1   4   4    <- a==1
 2   0   3   4
 3   0   6   6
 4   0   1   6
 5   1   2   2    <- a==1
 6   0   3   3
 7   0   4   4
 8   0   2   4
 9   0   1   4
10   1   7   7    <- a==1
11   0   8   8
Run Code Online (Sandbox Code Playgroud)

我的 df 有一个没有间隙的整数索引,所以我尝试这样做:

df['last_a'] = np.where(df.a == 1, df.index, np.nan)
df['last_a'].fillna(method='ffill', inplace=True)
df['rm'] = pd.rolling_max(df['b'], window = df.index - df['last_a'] + 1)
Run Code Online (Sandbox Code Playgroud)

但我收到一个类型错误:需要一个整数。

这是在相当大的数据帧上运行的长脚本的一部分,所以我需要尽可能最快的解决方案。我已经成功地尝试用循环而不是rolling_max 来做到这一点,但它很慢。能否请你帮忙?

仅供参考。我现在拥有的丑陋而长的循环,无论它有多丑陋,在我的数据帧(测试为 50,000 x 25)上似乎都非常快,如下所示:

df['rm2'] = df.b
df['rm1'] = np.where( (df['a'] == 1) | (df['rm2'].diff() > 0), df['rm2'], np.nan)
df['rm1'].fillna(method = 'ffill', inplace = True)
df['Dif'] = (df['rm1'] - df['rm2']).abs()
while df['Dif'].sum() != 0:
    df['rm2'] = df['rm1']
    df['rm1'] = np.where( (df['a'] == 1) | (df['rm2'].diff() > 0), df['rm2'], np.nan) 
    df['rm1'].fillna(method = 'ffill', inplace = True)
    df['Dif'] = (df['rm1'] - df['rm2']).abs()
Run Code Online (Sandbox Code Playgroud)

Col*_*vel 5

我会创建一个索引和groupby这个索引来使用cummax

import numpy as np

df['index'] = df['a'].cumsum()
df['rm']    = df.groupby('index')['b'].cummax()

df.loc[df['index']==0, 'rm'] = np.nan

In [104]: df
Out[104]:
    a  b  index  rm
0   0  5      0 NaN
1   1  4      1   4
2   0  3      1   4
3   0  6      1   6
4   0  1      1   6
5   1  2      2   2
6   0  3      2   3
7   0  4      2   4
8   0  2      2   4
9   0  1      2   4
10  1  7      3   7
11  0  8      3   8
Run Code Online (Sandbox Code Playgroud)