【问题标题】:Checking condition in negative rolling window within GroupBy in Pandas在 Pandas 的 GroupBy 中检查负滚动窗口中的条件
【发布时间】:2019-03-11 21:49:31
【问题描述】:

以下是我的数据框的样子。 Expected_Output 列是我想要的/目标列。

   Group  Value  Expected_Output
0      1      2                1
1      1      3                1
2      1      6                1
3      1     11                0
4      1      7                0
5      2      3                1
6      2     13                1
7      2     14                0

对于给定的Group,对于给定的行,我正在查看下一个 5 行并检查是否有Value > 10。如果为真,那么我想在Expected_Output 中返回 1,否则返回 0。

例如,在Group 1 中,从第一行开始,11(大于 10)的Value 出现在 3 行内,并且确实落在满足条件的“下 5 行窗口”内因此在Expected_Output 中返回 1。与Group 2 中的第 6 行类似,Value 为 14(大于 10)出现在 1 行内,并且确实落在满足条件的“下 5 行窗口”内,因此在 @ 中返回 1 987654331@.

我试过df.groupby('Group')['Value'].rolling(-5).max() > 10 无济于事。

【问题讨论】:

    标签: python pandas numpy pandas-groupby


    【解决方案1】:

    pd.Series.rolling 默认向后看。要向前看,您可以反转数据帧,然后反转 GroupBy 结果。您需要包含shift,因为您正在寻找下一个 5 个值。

    def roller(x):
        return x.rolling(window=5, min_periods=1)['Value'].max().shift().gt(10).astype(int)
    
    df['Result'] = df.iloc[::-1].groupby('Group', sort=False).apply(roller).iloc[::-1].values
    
    print(df)
    
       Group  Value  Result
    0      1      2       1
    1      1      3       1
    2      1      6       1
    3      1     11       0
    4      1      7       0
    5      2      3       1
    6      2     13       1
    7      2     14       0
    

    【讨论】:

      【解决方案2】:

      您可以尝试对数据框进行分组并利用数据框索引来获取下一个可能的 5 个值并检查任何大于 10 的值

      df['Expected_Output'] =df.groupby(['Group'])['Value'].transform(lambda y:list(map(lambda x: 1 if any(y.loc[set(np.arange(x+1,x+6)).intersection(y.index)] >10) else 0,y.index)))
      

      输出:

          Group   Value   Expected_Output
      0   1   2   1
      1   1   3   1
      2   1   6   1
      3   1   11  0
      4   1   7   0
      5   2   3   1
      6   2   13  1
      7   2   14  0
      

      【讨论】:

      • 您应该尝试将 Pandas / NumPy 方法与 Pandas 对象一起使用。 any/set/三元语句将bool转换为int;所有这些都可以正常工作,但在矢量化解决方案可用时并不理想。
      • 感谢@jpp 的建议,我会合并它:-)
      【解决方案3】:

      有一种方法可以在没有任何额外技巧的情况下做到这一点,但它需要您有一个排序维度。与大多数时间序列数据一样,您应该可以使用时间变量。那么解决方法就很简单了:

      1. 倒序排列
      2. 使用标准的.rolling(window) 功能
      3. (可选)再次排序

      示例:睡眠研究

      from pydataset import data
      sleep_study = data('sleepstudy')
      print(sleep_study.head(5))
      
         Reaction  Days  Subject
      1  249.5600     0      308
      2  258.7047     1      308
      3  250.8006     2      308
      4  321.4398     3      308
      5  356.8519     4      308
      

      1) 向后排序

      sleep_study.sort_values(by=['Subject', 'Days'], ascending=False, inplace=True)
      

      2) 使用.rolling(window)

      assert sleep_study.index.is_unique
      sleep_study['max_react_next_3_days'] = sleep_study\
          .groupby(['Subject'], as_index=False)['Reaction']\
          .rolling(window=3, min_periods=1, closed='left').max()['Reaction']
      sleep_study['expected_output'] = sleep_study['max_react_next_3_days'] > 400
      

      解释:

      • 我们想提前 3 天看,因此window=3
      • 但是,研究只剩下 2 或 1 天也可以,所以min_periods=1 -- 这取决于您的假设/喜好
      • 我们要使用下一个 3 天,而不是当天,所以我们使用closed='left' 排除它,这意味着rolling 需要一个半开间隔,即开在“右”,“左”闭。
      • 警告:您的数据集必须具有唯一索引才能使此代码正常工作,否则会出现静默错误

      3) 再次排序,这样就没有惊喜了

      sleep_study.sort_values(by=['Subject', 'Days'], ascending=True, inplace=True)
      

      结果:

      print(sleep_study.head(20))
      
          Reaction  Days  Subject  max_react_next_3_days  expected_output
      1   249.5600     0      308               321.4398            False
      2   258.7047     1      308               356.8519            False
      3   250.8006     2      308               414.6901             True
      4   321.4398     3      308               414.6901             True
      5   356.8519     4      308               414.6901             True
      6   414.6901     5      308               430.5853             True
      7   382.2038     6      308               466.3535             True
      8   290.1486     7      308               466.3535             True
      9   430.5853     8      308               466.3535             True
      10  466.3535     9      308                    NaN            False
      11  222.7339     0      309               205.2658            False
      12  205.2658     1      309               207.7161            False
      13  202.9778     2      309               215.9618            False
      14  204.7070     3      309               215.9618            False
      15  207.7161     4      309               217.7272            False
      16  215.9618     5      309               224.2957            False
      17  213.6303     6      309               237.3142            False
      18  217.7272     7      309               237.3142            False
      19  224.2957     8      309               237.3142            False
      20  237.3142     9      309                    NaN            False
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-02-25
        • 2021-06-22
        • 2021-12-17
        • 2017-07-12
        • 1970-01-01
        • 2018-01-28
        • 2020-03-06
        相关资源
        最近更新 更多