web-dev-qa-db-de.com

Ich möchte zwei Spalten in einem Pandas DataFrame multiplizieren und das Ergebnis in eine neue Spalte einfügen

Ich versuche, zwei vorhandene Spalten in einem Pandas Dataframe (orders_df) - Preise (Lagerschlusskurs) und Betrag (Lagerbestände) zu multiplizieren und die Berechnung in eine neue Spalte mit dem Namen 'Value' einzufügen. Aus irgendeinem Grund sind bei der Ausführung dieses Codes alle Zeilen unter der Spalte "Wert" positive Zahlen, während einige der Zeilen negativ sein sollten. In der Action-Spalte des DataFrame befinden sich sieben Zeilen mit der Zeichenfolge "Sell" und sieben mit der Zeichenfolge "Buy".

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!

42
OAK

Wenn wir bereit sind, die Genauigkeit von Haydens Lösung zu opfern, könnte man auch so 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 if-Anweisung nicht mehr benötigt. Mit DataFrame.apply() verzichten wir auch auf die for-Schleife. Wie Hayden bemerkt hat, 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 einer, ist aber etwas lesbarer. Ich vermute, dass die rechnerischen Kosten ebenfalls ähnlich sind. 

15
Aman

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

Außerdem sollte dies die schnellste Lösung sein.

64
bmu

Sie können die DataFrame 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 normalerweise schneller, diese Methoden zu verwenden, als für Schleifen.

22
Andy Hayden

Da diese Frage erneut aufkam, denke ich, dass ein guter sauberer Ansatz die Verwendung von zuweisen ist.

Der Code ist ziemlich ausdrucksstark und selbsterklärend:

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

Um die Dinge ordentlich zu machen, nehme ich Haydens Lösung, aber mache eine kleine Funktion daraus.

def create_value(row):
    if row['Action'] == 'Sell':
        return row['Prices'] * row['Amount']
    else:
        return -row['Prices']*row['Amount']

wenn wir also die Funktion auf unseren Datenrahmen anwenden möchten, können wir Folgendes tun:.

df['Value'] = df.apply(lambda row: create_value(row), axis=1)

... und Änderungen müssen nur in der kleinen Funktion selbst vorgenommen werden.

Prägnant, lesbar und ordentlich!

0
Carson

Für mich ist dies das klarste und intuitivste:

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 einen numpy array zurück, mit dem Sie das Element auf einfache Weise multiplizieren können. Anschließend können Sie eine Liste generieren, indem Sie es hinzufügen.

0

Gute Lösung von BMU. Ich denke, es ist besser lesbar, die Werte in Klammern und außerhalb zu setzen. 

    df['Values'] = np.where(df.Action == 'Sell', 
                            df.Prices*df.Amount, 
                           -df.Prices*df.Amount)

Einige eingebaute Pandas verwenden.

    df['Values'] = np.where(df.Action.eq('Sell'), 
                            df.Prices.mul(df.Amount), 
                           -df.Prices.mul(df.Amount))