2012-12-27 15 views
29

Sto provando a moltiplicare due colonne esistenti in un pandas Dataframe (orders_df) - Prezzi (prezzo chiuso magazzino) e Quantità (quantità stock) e aggiungere il calcolo a una nuova colonna denominata "Valore". Per qualche motivo quando eseguo questo codice, tutte le righe sotto la colonna "Valore" sono numeri positivi, mentre alcune delle righe dovrebbero essere negative. Sotto la colonna Azione in DataFrame ci sono sette righe con la stringa "Vendi" e sette con la stringa "Acquista".Voglio moltiplicare due colonne in un DataFrame panda e aggiungere il risultato in una nuova colonna

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) 

Per favore fatemi sapere cosa sto facendo male!

risposta

12

Se siamo disposti a sacrificare la concisione della soluzione di Hayden, si potrebbe anche fare qualcosa di simile:

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 

ora abbiamo eliminato la necessità per l'istruzione if. Usando DataFrame.apply(), eliminiamo anche il ciclo for. Come ha osservato Hayden, le operazioni vettorializzate sono sempre più veloci.

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 

Questa soluzione richiede due righe di codice anziché una, ma è un po 'più facile da leggere. Sospetto che anche i costi computazionali siano simili.

17

È possibile utilizzare il metodo dataframe apply:

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

Di solito è più veloce di utilizzare questi metodi, piuttosto che su per i loop.

+0

brillanti, grazie mille !! – OAK

58

Penso una soluzione elegante è quello di utilizzare il metodo where (si veda anche la 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 

ulteriormente più questa dovrebbe essere la soluzione più veloce.

+0

grazie per la soluzione, entrambi funzionano magnificamente. – OAK

+3

potresti indicare che questo risponde alla tua domanda? –

+1

Contrassegnalo come risposta, @OAK – Blairg23

0

Per me, questa è la più chiara e intuitiva:

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 

Il metodo .values restituisce un numpy array che consente di moltiplicare facilmente elemento-saggio e poi si può cumulativamente generare un elenco da 'aggiungendo' ad esso .

3

Poiché questa domanda è tornata di nuovo, penso che un buon approccio pulito stia usando assign.

Il codice è molto espressiva e di auto-descrizione:

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