Python pandas: 将函数应用到 dataframe.rolling()

Python pandas: apply a function to dataframe.rolling()

我有这个数据框:

In[1]df = pd.DataFrame([[1,2,3,4,5],[6,7,8,9,10],[11,12,13,14,15],[16,17,18,19,20],[21,22,23,24,25]])
In[2]df
Out[2]: 
    0   1   2   3   4
0   1   2   3   4   5
1   6   7   8   9  10
2  11  12  13  14  15
3  16  17  18  19  20
4  21  22  23  24  25

我需要实现这个:

  1. 对于我的数据框中的每一行,
  2. 如果任意 3 个连续单元格中有 2 个或更多值大于 10,
  3. 那么这 3 个单元格中的最后一个应该标记为 True。

根据上述标准,生成的数据帧 df1 应与其中的 True 或 False 大小相同:

In[3]df1
Out[3]: 
    0   1      2      3      4
0 NaN NaN  False  False  False
1 NaN NaN  False  False  False
2 NaN NaN   True   True   True
3 NaN NaN   True   True   True
4 NaN NaN   True   True   True

我认为带有函数的 dataframe.rolling.apply() 可能是解决方案,但究竟如何呢?

你说得对,使用 rolling() 是正确的方法。但是,您必须记住,因为 rolling() 将 window 末尾的值替换为新值,所以您不能只将 window 标记为 True当条件不适用时也会得到 False

下面是使用示例数据框并执行所需转换的代码:

df = pd.DataFrame([[1,2,3,4,5],[6,7,8,9,10],[11,12,13,14,15],[16,17,18,19,20],[21,22,23,24,25]])

现在,定义一个以window为参数的函数,returns是否满足条件

def fun(x):
    num = 0
    for i in x:
        num += 1 if i > 10 else 0
    return 1 if num >= 2 else -1

我已将阈值硬编码为 10。因此,如果在任何 window 中,大于 10 的值的数量大于或等于 2,那么最后一个值将替换为 1(表示 True),否则它被替换为 -1(表示 False)。

如果您想将阈值参数保留为变量,请查看 this 答案以将它们作为参数传递。

现在在滚动 window 上应用函数,使用 window 大小作为 3,轴 1 另外如果你不想要 NaN 那么你也可以将 min_periods 设置为 1在参数中。

df.rolling(3, axis=1).apply(fun)

产生的输出为

  0   1    2    3    4
0 NaN NaN -1.0 -1.0 -1.0
1 NaN NaN -1.0 -1.0 -1.0
2 NaN NaN  1.0  1.0  1.0
3 NaN NaN  1.0  1.0  1.0
4 NaN NaN  1.0  1.0  1.0

你需要 -

import pandas as pd
import numpy as np
df = pd.DataFrame([[1,2,3,4,5],[6,7,8,9,10],[11,12,13,14,15],[16,17,18,19,20],[21,22,23,24,25]])
df1 = df.apply(lambda x: pd.Series([np.nan, np.nan]+[all(j>10 for j in i) for i in zip(x[0::1], x[1::1], x[2::1])]), axis=1)

print(df1)

输出

0   1      2      3      4
0 NaN NaN  False  False  False
1 NaN NaN  False  False  False
2 NaN NaN   True   True   True
3 NaN NaN   True   True   True
4 NaN NaN   True   True   True

说明

list(zip(x[0::1], x[1::1], x[2::1])

将其分解为每行一次取 3 列 -

0             [(1, 2, 3), (2, 3, 4), (3, 4, 5)]
1            [(6, 7, 8), (7, 8, 9), (8, 9, 10)]
2    [(11, 12, 13), (12, 13, 14), (13, 14, 15)]
3    [(16, 17, 18), (17, 18, 19), (18, 19, 20)]
4    [(21, 22, 23), (22, 23, 24), (23, 24, 25)]

all(j>10 for j in i)

检查元组列表中的每个元素,如果元组中的所有元素都大于 10

,则输出 True

连接 [np.nan, np.nan] 以匹配您的输出。希望对您有所帮助。

在布尔数据框上使用 sum

df.gt(10).rolling(3, axis=1).sum().ge(2)

       0      1      2      3      4
0  False  False  False  False  False
1  False  False  False  False  False
2  False  False   True   True   True
3  False  False   True   True   True
4  False  False   True   True   True

您可以通过屏蔽 where na 来确定请求的确切输出。

df.gt(10).rolling(3, axis=1).sum().pipe(lambda d: d.ge(2).mask(d.isna()))

    0   1      2      3      4
0 NaN NaN  False  False  False
1 NaN NaN  False  False  False
2 NaN NaN   True   True   True
3 NaN NaN   True   True   True
4 NaN NaN   True   True   True