2017-09-14 23 views
3

パンダのリサンプリング関数を使用したいが、私自身のカスタム関数を適用したい。私が直面している問題は、カスタム関数が単一の配列ではなくpandasデータフレームを返すことです。累積関数がデータフレームを返すときのパンダ再サンプリング

次の例では、私の問題を示しています

>>> 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 Iドンを適用した場合希望の結果が得られません。私はfから私の出力の最後の行を取得したいと思います。

>>> resampler.apply(f) 

これはパンダのデータフレームを返すf私の機能でcumprod becaumesです。 fと書くと、最後の行だけが返されます。しかし、私はこの機能を他の場所でも使用して、データフレーム全体を返したいと思います。これは、関数fに "last_row"のようなフラグを導入することで解決できます。このフラグは、完全行または最後の行を返すように調整します。しかし、このソリューションはかなり厄介なようです。

+0

本当に必要な機能を最初に適用し、その月の最終営業日を選択すると簡単になると思います。それは実際にリサンプリングを必要とせず、リサンプリングのコンボであり、このトリッキーな累積機能を備えています。 – JohnE

答えて

2

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

thxその瞬間のことですが、醜いIMHOに見えます。それを行うためのもっとpythonicな方法はありませんか? – math

+0

醜い?これはそれを行うための無邪気な方法です。 –

+0

これは間違いなく、ピジョンソニックソリューションです。 ** lambda **: 'resampler.apply(lambda x:f(x).iloc [-1])の他の解法。だから関数f()を変更する必要はありません – qvpham

2

は、私はあなたが大きなデータフレームのためにはるかに高速になり、次のようにリファクタリングできると思います:我々が使用しているため、あなたが言うことができないが、@TedPetrouと同じ答えを与える

(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 

さまざまなランダムな種子が、あなたは簡単にこれを自分でテストすることができます。実際には、私はまだcumprod()ではなく、prod()で同じ答えを返す理由を選んでいます。とにかく、これは直感とリバースエンジニアリングの組み合わせです。私はここで使用しており、物事を二重チェックすると更新されます...

この比較的小さなデータフレームが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

関連する問題