2016-11-25 55 views
8

Tôi có một dataframe như sau:Pandas: Tích lũy trở lại chức năng

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

cách tốt nhất để tính toán lợi nhuận tích lũy trên tất cả các cột trên hàng cuối cùng là gì?

Sau đây là kết quả dự kiến:

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

đâu tích lũy lợi nhuận tính như sau:

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

cách tốt nhất để thực hiện điều này trong gấu trúc là gì?

Trả lời

8

có một phương pháp pandas cumprod() cho điều đó. điều này sẽ làm việc cho mọi cột.

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

này sẽ vào khoảng 2 lần nhanh hơn so với các giải pháp khác trên tập dữ liệu lớn:

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 

tôi sẽ đề nghị để bao giờ sử dụng áp dụng nếu bạn có thể tìm thấy một phương pháp tích hợp từ áp dụng được lặp trên khung dữ liệu làm cho nó chậm. Bult-in phương pháp có hiệu quả cao và thông thường không có cách nào bạn sẽ nhận được nhanh hơn so với họ bằng cách áp dụng.

+0

nhanh hơn rất nhiều !! nhưng tôi có một cột bao gồm NaN. Bất kỳ cách giải quyết nào để bỏ qua và không trả lại NaN? – Kelaref

+2

'df.ix [" Tích lũy "] = ((df.fillna (0) +1) .cumprod() - 1) .iloc [-1]' sẽ thay thế NaN bằng 0 trả về. –

1

Một lựa chọn là chỉ cần sử dụng reduce, mặc dù người khác có thể có thể đưa ra phương pháp vectorized nhanh hơn:

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 

Lưu ý rằng trong Python 3, reduce là một phần của thư viện functools, mặc dù đó là một BUILTIN cho Python 2.

2

với pandas, bạn có thể sử dụng phương pháp 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 

Hoặc như @Randy C nhận xét, đây có thể được đơn giản hóa hơn nữa để:

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

Đẹp nhất.Để thực hiện việc tính toán, nó có thể được đơn giản hóa một chút thành '(df ['Return'] + 1) .prod() - 1'. –

+0

@RandyC Vâng, đó là một cách ngắn gọn hơn cho vấn đề này. – Psidom

+0

Thx @Psidom, tôi đã làm df = ở trên, nó hoạt động tốt, ngoại trừ chỉ mục ngày của tôi biến mất, và trở về dưới cột đầu tiên trả về một NaN, mặc dù không bao gồm bất kỳ NaN nào và tích lũy không bằng 0. Bất kỳ ý tưởng tại sao? – Kelaref

1

Dưới đây là của tôi:

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

Cảm ơn, nó đã hoạt động, nhưng có cách nào để bỏ qua NaN không? – Kelaref

+0

Chắc chắn, đầu tiên 'nhập numpy thành np' và sau đó:' df.append (df.apply (lambda col: prod ([(1 + c) cho c trong col nếu không np.isnan (c)]) - 1) , ignore_index = True) '. Nếu bạn thử nó sau đó cho tôi biết nếu nó không hoạt động! – AlexG

4

Một giải pháp:

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

này sẽ thêm 1 đến df['Return'] cột, nhân tất cả các hàng với nhau và sau đó trừ một hàng khỏi kết quả. Điều này sẽ dẫn đến một giá trị float đơn giản. Kết quả sau đó sẽ được đặt ở chỉ mục "Tích lũy". Kể từ khi chỉ số đó chưa hề tồn tại, 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 

Nếu bạn muốn áp dụng điều này trên nhiều cột:

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

sẽ ra này như sau (tôi đã thực hiện một cột thứ hai gọi là "Return2" đó là bản sao của "Trả lại"):

   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, nhưng làm thế nào để áp dụng trên tất cả các cột? – Kelaref

+1

Đã cập nhật câu trả lời của tôi. Đã bỏ lỡ một phần câu hỏi của bạn. Nó rất giống với câu trả lời của @ Psidom nhưng tôi nghĩ câu trả lời này dễ đọc hơn. – TheF1rstPancake

+0

@ Jalapeno112 Cảm ơn bạn đã hoạt động hoàn hảo – Kelaref

Các vấn đề liên quan