2012-12-27 112 views
29

我試圖乘以一個熊貓Dataframe(orders_df)中的兩個現有列 - 價格(股票收盤價)和金額(股票數量)並將計算添加到名爲「值」的新列。出於某種原因,當我運行這段代碼時,'Value'列下的所有行都是正數,而一些行應該是負數。在DataFrame的Action列下面,有七行'Sell'字符串和七個'Buy'字符串。我想在熊貓DataFrame中乘以兩列,並將結果添加到新列

for i in orders_df.Action: 
if i == 'Sell': 
    orders_df['Value'] = orders_df.Prices*orders_df.Amount 
elif i == 'Buy': 
    orders_df['Value'] = -orders_df.Prices*orders_df.Amount) 

請讓我知道我做錯了什麼!

回答

12

如果我們願意犧牲海登的解決方案的簡潔,一個也可以做這樣的事情:

In [22]: orders_df['C'] = orders_df.Action.apply(
       lambda x: (1 if x == 'Sell' else -1)) 

In [23]: orders_df # New column C represents the sign of the transaction 
Out[23]: 
    Prices Amount Action C 
0  3  57 Sell 1 
1  89  42 Sell 1 
2  45  70 Buy -1 
3  6  43 Sell 1 
4  60  47 Sell 1 
5  19  16 Buy -1 
6  56  89 Sell 1 
7  3  28 Buy -1 
8  56  69 Sell 1 
9  90  49 Buy -1 

現在我們已經消除了對if聲明的必要性。使用DataFrame.apply(),我們也取消了for循環。正如海登指出的那樣,向量化操作總是更快。

In [24]: orders_df['Value'] = orders_df.Prices * orders_df.Amount * orders_df.C 

In [25]: orders_df # The resulting dataframe 
Out[25]: 
    Prices Amount Action C Value 
0  3  57 Sell 1 171 
1  89  42 Sell 1 3738 
2  45  70 Buy -1 -3150 
3  6  43 Sell 1 258 
4  60  47 Sell 1 2820 
5  19  16 Buy -1 -304 
6  56  89 Sell 1 4984 
7  3  28 Buy -1 -84 
8  56  69 Sell 1 3864 
9  90  49 Buy -1 -4410 

該解決方案需要兩行代碼,而不是一行,但更容易閱讀。我懷疑計算成本也是相似的。

17

您可以使用數據框apply方法:

order_df['Value'] = order_df.apply(lambda row: (row['Prices']*row['Amount'] 
               if row['Action']=='Sell' 
               else -row['Prices']*row['Amount']), 
            axis=1) 

它通常是更快地使用這些方法,而不是在for循環。

+0

輝煌,非常感謝! – OAK

58

我想到的是優雅的解決方案是使用where方法(另見API docs):

In [37]: values = df.Prices * df.Amount 

In [38]: df['Values'] = values.where(df.Action == 'Sell', other=-values) 

In [39]: df 
Out[39]: 
    Prices Amount Action Values 
0  3  57 Sell  171 
1  89  42 Sell 3738 
2  45  70 Buy -3150 
3  6  43 Sell  258 
4  60  47 Sell 2820 
5  19  16 Buy -304 
6  56  89 Sell 4984 
7  3  28 Buy  -84 
8  56  69 Sell 3864 
9  90  49 Buy -4410 

進一步,這應該是最快的解決方案。

+0

感謝您的解決方案,他們都工作得很好。 – OAK

+3

你能指出這回答你的問題嗎? –

+1

將此標記爲您的答案,@OAK – Blairg23

0

對於我來說,這是最清晰,最直觀的:

values = [] 
for action in ['Sell','Buy']: 
    amounts = orders_df['Amounts'][orders_df['Action'==action]].values 
    if action == 'Sell': 
     prices = orders_df['Prices'][orders_df['Action'==action]].values 
    else: 
     prices = -1*orders_df['Prices'][orders_df['Action'==action]].values 
    values += list(amounts*prices) 
orders_df['Values'] = values 

.values方法返回一個numpy array讓您輕鬆乘元素方面的,然後你可以累計產生的「添加」給它一個列表。

3

由於這個問題再次提出,我認爲一個很好的乾淨的方法是使用assign

的代碼是相當的表現力和自我描述:

df = df.assign(Value = lambda x: x.Prices * x.Amount * x.Action.replace({'Buy' : 1, 'Sell' : -1})) 
相關問題