2017-09-14 122 views
3

我想使用熊貓的重採樣函數,但應用我自己的自定義函數。我面臨的問題是自定義函數返回一個熊貓數據框而不是單個數組。當累計函數返回數據幀時,熊貓重採樣

下面的例子說明我的問題:

>>> 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) 

這是becaumes在我的函數f返回大熊貓數據幀的cumprod。我可以寫我的f,它只返回最後一行。但是,我想在其他地方使用這個函數來返回整個數據框。這可以通過在函數f中引入一個像「last_row」這樣的標誌來解決,該標誌可以返回完整的或最後一行。但這個解決方案看起來很討厭。

+0

我認爲這可以簡化,如果你真正想要的是首先應用該功能,然後選擇該月的最後一個營業日。這實際上不需要重新採樣,它是一個累積函數的重採樣組合,這使得我現在所做的這個棘手的 – JohnE

回答

2

只需使用last_row參數定義您的函數f即可。您可以將其默認爲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) 
+0

thx,但它看起來相當醜陋恕我直言。有沒有更pythonic的方式來做到這一點? – math

+0

醜陋?這是做pythonic的方式。 –

+0

這絕對是一個pythonic解決方案。使用** lambda **:'resampler.apply(lambda x:f(x).iloc [-1])的其他解決方案'。所以你不需要改變函數'f()' – qvpham

2

我想你可以通過以下方式,這將是更快較大dataframes重構:

(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() 
+0

你可以直接使用.prod()作爲方法(我認爲可能不會實現) – Jeff

+0

@jeff啊,是的,謝謝!據此編輯。 – JohnE