次のようなデータフレームがあります。
Index Return
2008-11-21 0.153419
2008-11-24 0.037421
2008-11-25 0.077500
最後の行のすべての列にわたる累積リターンを計算するための最良の方法は何ですか?
意図した結果は次のとおりです。
Index Return
2008-11-21 0.153419
2008-11-24 0.037421
2008-11-25 0.077500
Cumulative 0.289316
累積リターンが次のように計算される場合:
cumulative = (1 + return1) * (1 + return2) * (1 + return3) - 1
パンダでこれを実行するための最良の方法は何ですか?
そのためのpandas cumprod()
メソッドがあります。これはすべての列で機能します。
df.ix["Cumulative"] = ((df+1).cumprod()-1).iloc[-1]
これは、大規模なデータセットの他のソリューションよりも約2倍高速です。
In[106]: %timeit df.ix["Cumulative"] = ((df+1).cumprod()-1).iloc[-1]
10 loops, best of 3: 18.4 ms per loop
In[107]: %timeit df.ix['Cummulative'] = df.apply(lambda x: (x+1).prod()-1)
10 loops, best of 3: 32.9 ms per loop
In[110]: %timeit df.append(df.iloc[:,1:].apply(lambda col: (col + 1).prod() - 1), ignore_index=True)
10 loops, best of 3: 37.1 ms per loop
In[113]: %timeit df.append(df.apply(lambda col: prod([(1+c) for c in col]) - 1), ignore_index=True)
1 loop, best of 3: 262 ms per loop
Applyがデータフレームをループしているため、組み込みメソッドが見つかった場合は、never applyを使用することをお勧めします。ブルトイン方式は非常に効率的であり、通常、applyを使用するよりも速くなる方法はありません。
別の解決策:
df.ix["Cumulative"] = (df['Return']+1).prod() - 1
これにより、df['Return']
列に1が加算され、すべての行が乗算されてから、結果から1が減算されます。これにより、単純な浮動小数点値になります。結果は、インデックス「累積」に配置されます。そのインデックスはまだ存在しないため、 DataFrameの最後に追加されます :
Return
2008-11-21 0.153419
2008-11-25 0.077500
2008-11-24 0.037421
Cummulative 0.289316
これを複数の列に適用する場合:
df.ix['Cummulative'] = df.apply(lambda x: (x+1).prod()-1)
これにより、次のように出力されます(「Return」のコピーである「Return2」という2番目の列を作成しました)。
Return Return2
2008-11-21 0.153419 0.153419
2008-11-25 0.077500 0.077500
2008-11-24 0.037421 0.037421
Cummulative 0.289316 0.289316
pandas
を使用すると、prod()
メソッドを使用できます。
df.append(df.iloc[:,1:].apply(lambda col: (col + 1).prod() - 1), ignore_index=True)
# Index Return
#0 2008-11-21 0.153419
#1 2008-11-24 0.037421
#2 2008-11-25 0.077500
#3 NaN 0.289316
または、@ Randy Cがコメントしたように、これはさらに単純化して次のようにすることができます。
df.append((df.iloc[:,1:] + 1).prod() - 1, ignore_index=True)
1つのオプションは、reduce
を使用することですが、他のオプションは、より高速なベクトル化されたメソッドを思い付くことができる場合があります。
In [10]: pd.read_clipboard()
Out[10]:
Index Return
0 2008-11-21 0.153419
1 2008-11-24 0.037421
2 2008-11-25 0.077500
In [11]: reduce(lambda x, y: (1+x)*(1+y)-1, _10['Return'])
Out[11]: 0.28931612705992227
Python 3では、reduce
はfunctools
ライブラリの一部ですが、Python 2の組み込みです。
これが私のものです:
from numpy import prod
df.append(df.apply(lambda col: prod([(1+c) for c in col]) - 1), ignore_index=True)