当累积函数返回数据框时,pandas重新采样

时间:2017-09-14 09:04:57

标签: pandas

我想使用pandas的重采样功能,但应用我自己的自定义功能。我面临的问题是自定义函数返回一个pandas Data Frame而不是单个数组。

以下示例说明了我的问题:

>>> import pandas as pd
>>> import numpy as np
>>> def f(data):
...     return ((1+data).cumprod(axis=0)-1)
... 
>>> data = np.random.randn(1000,3)
>>> index = pd.date_range("20170101", periods = 1000, freq="B")
>>> df = pd.DataFrame(data= data, index =index) 

现在假设我想将工作日重新采样到业务结束月份频率:

>>> resampler = df.resample("BM")

如果我现在申请我的函数f我没有得到理想的结果。我想从f获得输出的最后一行。

>>> resampler.apply(f)

这是因为我的函数cumprod中的f返回了一个pandas数据框。我可以写我的f,使它只返回最后一行。但是,我想在其他地方使用此函数来返回整个数据框。这可以通过在函数f中引入类似“last_row”的标志来解决,该标志指向返回完整或仅最后一行。但这个解决方案看起来相当讨厌。

2 个答案:

答案 0 :(得分:2)

只需使用f参数定义您的函数last_row即可。您可以将其默认为False,以便返回整个数据帧。当True返回最后一行时

def f(data, last_row=False):
    df = ((1+data).cumprod(axis=0)-1)
    if last_row:
        return df.iloc[-1]
    return df

获取最后一行

df.resample('BM').apply(f, last_row=True)

                    0           1          2
2017-01-31   0.185662   -0.580058  -1.004879
2017-02-28  -1.004035   -0.999878  17.059846
2017-03-31  -0.995280   -1.000001  -1.000507
2017-04-28  -1.000656 -240.369487  -1.002645
2017-05-31  47.646827  -72.042190  -1.000016
....

按原样返回所有行。

df.resample('BM').apply(f)

答案 1 :(得分:2)

我认为您可以通过以下方式进行重构,对于较大的数据帧,这将更快:

(1+df).resample('BM').prod() - 1


                   0         1         2
2017-01-31 -0.999436 -1.259078 -1.000215
2017-02-28 -1.221404  0.342863  9.841939
2017-03-31 -0.820196 -1.002598 -0.450662
2017-04-28 -1.000299  2.739184 -1.035557
2017-05-31 -0.999986 -0.920445 -2.103289

这给出了与@TedPetrou相同的答案,尽管你无法分辨,因为我们使用了不同的随机种子,但你可以自己轻松测试。虽然实际上,我仍在整理出为什么这会通过prod()而不是cumprod()给出相同的答案。无论如何,你可以看到这是我在这里使用的直觉和逆向工程的混合,并且会在我仔细检查时更新......

对于这个包含1,000行的相对较小的数据帧,这种方式只有大约两倍的速度,但是如果增加行数,你会发现这种方式可以更好地扩展(在10,000行时大约快250倍)。

替代方法:这些方法可以从上面(以及相互之间)给出不同的答案,但我想知道它们是否可能更接近您所寻找的内容?

(1+df).resample('BM').mean().expanding().apply( lambda x: x.prod() - 1)

(1+df).expanding().apply( lambda x: x.prod() - 1).resample('BM').mean()