web-dev-qa-db-ja.com

パンダ:累積リターン関数

次のようなデータフレームがあります。

  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 

パンダでこれを実行するための最良の方法は何ですか?

9
Kelaref

そのための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を使用するよりも速くなる方法はありません。

10
Steven G

別の解決策:

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
4
TheF1rstPancake

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

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では、reducefunctoolsライブラリの一部ですが、Python 2の組み込みです。

1
Randy

これが私のものです:

from numpy import prod
df.append(df.apply(lambda col: prod([(1+c) for c in col]) - 1), ignore_index=True)
1
AlexG