【问题标题】:Python pandas: apply a function to dataframe.rolling()Python pandas:将函数应用于 dataframe.rolling()
【发布时间】:2018-09-25 01:43:34
【问题描述】:

我有这个数据框:

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
  • df1.iloc[0,1] 是 NaN,因为在该单元格中,只给出了两个数字,但至少需要 3 个数字才能进行测试。
  • df1.iloc[1,3] 为 False,因为 [7,8,9] 中没有一个大于 10
  • df1.iloc[3,4] 为 True,因为 [18,19,20] 中的 2 或更多大于 10

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

【问题讨论】:

标签: python pandas rolling-computation


【解决方案1】:

您说得对,使用rolling() 是正确的选择。但是,您必须记住,因为rolling() 将窗口末尾的值替换为新值,所以您不能只用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]])

现在,定义一个以窗口为参数并返回是否满足条件的函数

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

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

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

现在在滚动窗口上应用该函数,使用窗口大小为 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

【讨论】:

  • 感谢您的解释,如果我需要 threadhold(0 in your if i > 0) 和大于 1(1 in your if num > 1) 都作为函数的参数,如何重写“df.rolling(3,axis=1,min_periods=1).apply(fun)”? .apply 中的函数需要的不仅仅是 self 作为参数?
【解决方案2】:

在布尔数据帧上使用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

【讨论】:

    【解决方案3】:

    你需要 -

    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] 以匹配您的输出。希望对您有所帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-04-10
      • 1970-01-01
      • 2020-12-09
      • 2021-12-04
      • 2012-08-24
      相关资源
      最近更新 更多