【问题标题】:Pandas rolling gives NaN熊猫滚动给出 NaN
【发布时间】:2016-11-26 01:53:44
【问题描述】:

我正在看关于窗口函数的教程,但我不太明白为什么下面的代码会产生 NaN。

如果我理解正确,代码会创建一个大小为 2 的滚动窗口。为什么第一行、第四行和第五行都有 NaN?起初,我以为是因为将 NaN 与另一个数字相加会产生 NaN,但后来我不确定为什么第二行不会是 NaN。

dft = pd.DataFrame({'B': [0, 1, 2, np.nan, 4]}, 
                   index=pd.date_range('20130101 09:00:00', periods=5, freq='s'))


In [58]: dft.rolling(2).sum()
Out[58]: 
                       B
2013-01-01 09:00:00  NaN
2013-01-01 09:00:01  1.0
2013-01-01 09:00:02  3.0
2013-01-01 09:00:03  NaN
2013-01-01 09:00:04  NaN

【问题讨论】:

  • 这将允许您从数据框中删除 NaNs,如果这是您想要做的:dft[dft['B'].notnull()].rolling(2).sum()

标签: python pandas


【解决方案1】:

首先要注意的是,默认情况下rolling 会查找要聚合的 n-1 行之前的数据,其中 n 是窗口大小。如果不满足该条件,它将为窗口返回 NaN。这就是第一行发生的事情。第四行和第五行,是因为求和中有一个值是NaN。

如果您想避免返回 NaN,可以将 min_periods=1 传递给将窗口中所需的最小有效观察数减少到 1 而不是 2 的方法:

>>> dft.rolling(2, min_periods=1).sum()
                       B
2013-01-01 09:00:00  0.0
2013-01-01 09:00:01  1.0
2013-01-01 09:00:02  3.0
2013-01-01 09:00:03  2.0
2013-01-01 09:00:04  4.0

【讨论】:

  • 我认为对我来说关键是知道它是 n-1(而不是 n),谢谢!
  • 如果center=True,我猜是(n-1)/2,而不是n-1。但答案当然仍然成立 +1
【解决方案2】:

使用min_periods=1 会导致滚动窗口中的值出现较大差异。删除NaN 值的另一种方法是在滚动窗口上使用fillna

>>> dft.rolling(2).sum().fillna(method='bfill').fillna(method='ffill')
                       B
2013-01-01 09:00:00  1.0
2013-01-01 09:00:01  1.0
2013-01-01 09:00:02  3.0
2013-01-01 09:00:03  3.0
2013-01-01 09:00:04  3.0

滚动窗口大小为 6 的示例说明了该问题:

>>> dft = pd.DataFrame({'B': [10, 1, 10, 1, 10, 1, 10, 1, 10, 1]}, index=pd.date_range('20130101 09:00:00', periods=10, freq='s'))

>>> dft.rolling(6, min_periods=1).sum()
                        B
2013-01-01 09:00:00  10.0
2013-01-01 09:00:01  11.0
2013-01-01 09:00:02  21.0
2013-01-01 09:00:03  22.0
2013-01-01 09:00:04  32.0
2013-01-01 09:00:05  33.0
2013-01-01 09:00:06  33.0
2013-01-01 09:00:07  33.0
2013-01-01 09:00:08  33.0
2013-01-01 09:00:09  33.0

>>> dft.rolling(6).sum().fillna(method='bfill')
                        B
2013-01-01 09:00:00  33.0
2013-01-01 09:00:01  33.0
2013-01-01 09:00:02  33.0
2013-01-01 09:00:03  33.0
2013-01-01 09:00:04  33.0
2013-01-01 09:00:05  33.0
2013-01-01 09:00:06  33.0
2013-01-01 09:00:07  33.0
2013-01-01 09:00:08  33.0
2013-01-01 09:00:09  33.0

虽然使用min_periods=1 会导致前 5 个值低于 33.0,但使用fillna 会在整个窗口中产生预期的 33.0。根据您的用例,您可能希望使用fillna

【讨论】:

    【解决方案3】:

    使用rolling('2d')代替rolling(2)

    dft = pd.DataFrame({'B': [0, 1, 2, np.nan, 4]}, 
                       index=pd.date_range('20130101 09:00:00', periods=5, freq='s'))
    
    
    dft.rolling('2d').sum()
    

    【讨论】:

      【解决方案4】:

      确实添加 NAN 和其他任何东西都会产生 NAN。所以:

      input + rolled = sum
          0      nan   nan
          1        0     1
          2        1     3
        nan        2   nan
          4      nan   nan
      

      第二行没有理由是 NAN,因为它是原始第一个和第二个元素的总和,两者都不是 NAN。

      另一种方法是:

      dft.B + dft.B.shift()
      

      【讨论】:

        猜你喜欢
        • 2017-11-08
        • 1970-01-01
        • 2018-07-05
        • 2018-07-30
        • 1970-01-01
        • 2021-12-15
        • 2014-01-29
        • 1970-01-01
        • 2018-06-26
        相关资源
        最近更新 更多