Quiero multiplicar dos columnas en un DataFrame de pandas y agregar el resultado en una nueva columna

Estoy tratando de multiplicar dos columnas existentes en un Dataframe de pandas (orders_df) – Precios (precio de cierre de stock) e Cantidad (cantidades de stock) y agregar el cálculo a una nueva columna llamada “Valor”. Por alguna razón, cuando ejecuto este código, todas las filas debajo de la columna ‘Valor’ son números positivos, mientras que algunas de las filas deberían ser negativas. Debajo de la columna Acción en el Marco de datos hay siete filas con la cadena “Vender” y siete con la cadena “Comprar”.

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) 

Por favor, déjame saber lo que estoy haciendo mal!

Si estamos dispuestos a sacrificar lo sucinto de la solución de Hayden, también se podría hacer algo como esto:

 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 

Ahora hemos eliminado la necesidad de la sentencia if . Usando DataFrame.apply() , también eliminamos el bucle for . Como señaló Hayden, las operaciones vectorizadas son siempre más rápidas.

 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 

Esta solución toma dos líneas de código en lugar de una, pero es un poco más fácil de leer. Sospecho que los costos computacionales también son similares.

Creo que una solución elegante es usar el método where (también vea los 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 

Además, esta debería ser la solución más rápida.

Puede utilizar el método de apply DataFrame:

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

Por lo general, es más rápido usar estos métodos en lugar de hacerlo en los bucles.

Desde que surgió esta pregunta nuevamente, creo que un buen enfoque limpio es usar asignar .

El código es bastante expresivo y autodescriptivo:

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

Para mí, este es el más claro e intuitivo:

 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 

El método .values devuelve una numpy array que le permite multiplicar fácilmente los elementos y, a continuación, puede generar una lista de forma acumulativa “agregándole”.

Buena solución de bmu. Creo que es más legible poner los valores entre paréntesis y fuera.

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

Usando algunas pandas incorporadas en funciones.

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

Para aclarar las cosas, tomo la solución de Hayden pero le hago una pequeña función.

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

de modo que cuando queremos aplicar la función a nuestro dataframe, podemos hacer …

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

… y cualquier modificación solo debe ocurrir en la pequeña función.

¡Conciso, legible, y aseado!