2012-12-27 3 views
29

Ich versuche, zwei vorhandene Spalten in einem Pandas Dataframe zu multiplizieren (orders_df) - Preise (Lager schließen Preis) und Menge (Lagermengen) und fügen Sie die Berechnung zu einer neuen Spalte mit dem Namen "Value" hinzu. Aus irgendeinem Grund, wenn ich diesen Code ausführen, sind alle Zeilen unter der Spalte "Wert" positive Zahlen, während einige der Zeilen negativ sein sollten. In der Action-Spalte im DataFrame gibt es sieben Zeilen mit der Zeichenfolge 'Sell' und sieben mit der Zeichenfolge 'Buy'.Ich möchte zwei Spalten in einem Pandas DataFrame multiplizieren und das Ergebnis in eine neue Spalte einfügen

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) 

Bitte lassen Sie mich wissen, was ich falsch mache!

Antwort

12

Wenn wir bereit sind, die Prägnanz der Hayden-Lösung zu opfern, könnte man auch etwas tun:

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 

Jetzt haben wir die Notwendigkeit, dass die if Rechnung eliminiert. Mit DataFrame.apply() verzichten wir auch auf die for Schleife. Wie Hayden bemerkte, sind vektorisierte Operationen immer schneller.

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 

Diese Lösung benötigt zwei Codezeilen anstelle von einem, ist aber ein wenig einfacher zu lesen. Ich vermute, dass die Rechenkosten ähnlich sind.

17

können Sie die Datenrahmen apply Methode verwenden:

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

Es ist in der Regel schneller, diese Methoden zu verwenden, anstatt über for-Schleifen.

+0

brillant, vielen Dank !! – OAK

58

Ich denke, eine elegante Lösung, um die where Methode zu verwenden ist (siehe auch die 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 

Weiter mehr dies die schnellste Lösung sein sollte.

+0

danke für die Lösung, beide von ihnen arbeiten wunderbar. – OAK

+3

können Sie angeben, dass dies Ihre Frage beantwortet? –

+1

Markieren Sie dies als Ihre Antwort, @OAK – Blairg23

0

Für mich ist dies die klarste und intuitiv:

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 

Die .values Methode gibt ein numpy array so dass Sie leicht elementweise multiplizieren und dann können Sie kumulativ eine Liste erzeugen, indem es ‚Hinzufügen‘ .

3

Da diese Frage wieder aufkam, denke ich, ein guter sauberer Ansatz ist assign.

Der Code ist sehr ausdrucksstark und selbsterklärend:

df = df.assign(Value = lambda x: x.Prices * x.Amount * x.Action.replace({'Buy' : 1, 'Sell' : -1})) 
Verwandte Themen