2016-11-25 23 views
8

Mam dataframe takie jak:Pandy: Zbiorcza funkcja powrotu

Index  Return 
2008-11-21 0.153419 
2008-11-24 0.037421 
2008-11-25 0.077500 

Jaki jest najlepszy sposób, aby obliczyć łączny zysk na wszystkich kolumnach w ostatnim rzędzie?

Poniżej zamierzony rezultat:

Index  Return 
2008-11-21 0.153419 
2008-11-24 0.037421 
2008-11-25 0.077500 
Cumulative 0.289316 

Jeżeli łączny zwrot oblicza się następująco:

cumulative = (1 + return1) * (1 + return2) * (1 + return3) - 1 

Jaki jest najlepszy sposób, aby wykonać to w pand?

Odpowiedz

8

jest pandy cumprod() sposób na to. to zadziała dla każdej kolumny.

df.ix["Cumulative"] = ((df+1).cumprod()-1).iloc[-1] 

byłoby to około 2 razy szybsze niż w przypadku innych rozwiązań na dużym zbiorze:

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 

Proponuję nigdy stosowania zastosowania, jeżeli można znaleźć wbudowaną metodę, ponieważ stosuje się zapętlenie nad ramką danych, co sprawia, że ​​jest wolna. Metoda Bult-in jest bardzo wydajna i zwykle nie ma mowy, aby uzyskać szybszy efekt niż przy zastosowaniu.

+0

, który był niesamowicie szybszy! ale mam jedną kolumnę, która zawiera NaN. Każde obejście, aby je pominąć i nie zwrócić NaN? – Kelaref

+2

'df.ix [" Cumulative "] = ((df.fillna (0) +1) .cumprod() - 1) .iloc [-1]' zastąpił NaN z powrotem 0. –

1

Jedną z opcji jest po prostu użyć reduce, choć inni mogą być w stanie wymyślić szybszych metod vectorized:

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 

pamiętać, że w Pythonie 3 reduce jest częścią biblioteki functools, choć jest to wbudowane dla Pythona 2.

2

z pandas, można użyć metody 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 

albo jako @Randy C powiedział, można jeszcze bardziej uprościć do:

df.append((df.iloc[:,1:] + 1).prod() - 1, ignore_index=True) 
+1

Niezły.Aby wykonać obliczenia, można je nieco uprościć do '(df ['Return'] + 1) .prod() - 1'. –

+0

@RandyC Tak, to jest bardziej zwięzły sposób na ten problem. – Psidom

+0

Thx @Psidom, zrobiłem df = powyższe, działa wspaniale, z wyjątkiem tego, że mój indeks daty zniknął, a powrót do CUM w pierwszej kolumnie zwraca NaN, pomimo że nie zawiera żadnych NaN, a skumulowany nie jest równy zeru. Jakieś pomysły, dlaczego? – Kelaref

1

Oto kopalni:

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

Dzięki, zadziałało, ale czy istnieje sposób na pominięcie NaNs? – Kelaref

+0

Oczywiście, najpierw 'import numpy jako np', a następnie:' df.append (df.apply (lambda col: prod ([(1 + c) dla cw col, jeśli nie np.isnan (c)]) - 1) , ignore_index = True) '. Jeśli wypróbujesz to daj mi znać, jeśli to nie działa! – AlexG

4

Innym rozwiązaniem:

df.ix["Cumulative"] = (df['Return']+1).prod() - 1 

Doda 1 do df['Return'] kolumna, pomnóż wszystkie wiersze razem, a następnie odejmij jeden od wyniku. Spowoduje to powstanie prostej wartości zmiennoprzecinkowej. Wynik zostanie następnie umieszczony na indeksie "Łączny". Ponieważ wskaźnik ten jeszcze nie istnieje, it will be appended to the end of the DataFrame:

   Return 
2008-11-21 0.153419 
2008-11-25 0.077500 
2008-11-24 0.037421 
Cummulative 0.289316 

Jeśli chcesz zastosować to w wielu kolumnach:

df.ix['Cummulative'] = df.apply(lambda x: (x+1).prod()-1) 

To byłoby wyjście następujące (Zrobiłem drugą kolumnę o nazwie „return2” że jest kopią „Return”):

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

Thx @ Jalepeno112, ale jak zastosować we wszystkich kolumnach? – Kelaref

+1

Zaktualizowałem moją odpowiedź. Przegapiłeś tę część twojego pytania. Jest bardzo podobny do odpowiedzi @ Psidoma, ale myślę, że ta jest bardziej czytelna. – TheF1rstPancake

+0

@ Jalapeno112 Dziękujemy, że działało idealnie – Kelaref