我想使用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”的标志来解决,该标志指向返回完整或仅最后一行。但这个解决方案看起来相当讨厌。
答案 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()