我无法理解pandas.rolling.apply
与np.prod
和NaNs的行为。例如
import pandas as pd
import numpy as np
df = pd.DataFrame({'B': [1, 1, 2, np.nan, 4], 'C': [1, 2, 3, 4, 5]}, index=pd.date_range('2013-01-01', '2013-01-05'))
给出这个数据帧:
B C
2013-01-01 1.0 1
2013-01-02 1.0 2
2013-01-03 2.0 3
2013-01-04 NaN 4
2013-01-05 4.0 5
如果我apply
numpynp.prod
函数到raw=False
和min_periods=1
的3天滚动窗口,它按预期工作,忽略nan。
df.rolling('3D', min_periods=1).apply(np.prod, raw=False)
B C
2013-01-01 1.0 1.0
2013-01-02 1.0 2.0
2013-01-03 2.0 6.0
2013-01-04 2.0 24.0
2013-01-05 8.0 60.0
但是对于raw=True
,我在B列中得到nan:
df.rolling('3D', min_periods=1).apply(np.prod, raw=True)
B C
2013-01-01 1.0 1.0
2013-01-02 1.0 2.0
2013-01-03 2.0 6.0
2013-01-04 NaN 24.0
2013-01-05 NaN 60.0
我想使用raw=True
的速度,但我不明白这种行为?有人能解释一下这是怎么回事吗?
这很简单。你可以试试下面的代码
import pandas as pd
import numpy as np
def foo(x):
return np.prod(x, where=~np.isnan(x))
if __name__ == '__main__':
df = pd.DataFrame({'B': [1, 1, 2, np.nan, 4], 'C': [1, 2, 3, 4, 5]},
index=pd.date_range('2013-01-01', '2013-01-05'))
res = df.rolling('3D', min_periods=1).apply(foo, raw=True)
print(res)
B C
2013-01-01 1.0 1.0
2013-01-02 1.0 2.0
2013-01-03 2.0 6.0
2013-01-04 2.0 24.0
2013-01-05 8.0 60.0
感谢@padu和@bui提供的评论/答案,让我找到了我一直在寻找的答案,即解释不同的行为。
正如文档所指出的,当使用raw=False
调用滚动apply
时,每个窗口都被转换为熊猫。在传递给np.prod
之前。使用raw=True
,每个窗口被转换为numpy数组。
np.prod
在Series和narray上的行为不同,忽略了Series中的NaN,这就是为什么我们得到不同的行为:
np.prod(np.array([1, 2, np.nan, 3]))
给出nan
np.prod(pd.Series([1, 2, np.nan, 3]))
给出6.0
我不清楚为什么NaN会被忽略,但正如@bui指出的那样,您可以通过将where
关键字设置为np.prod
来忽略narray情况下的NaN。