Operación matemática de los pandas, condicional al valor de la columna.

Necesito hacer una operación matemática que esté condicionada al valor en una segunda columna. Aquí está la configuración.

Dado un simple dataframe ( df ):

 df = pd.DataFrame({ 'col1' : ['A', 'A', 'B', np.nan, 'D', 'C'], 'col2' : [2, 1, 9, 8, 7, 4], 'col3': [0, 1, 9, 4, 2, 3], }) In [11]: df Out[11]: col1 col2 col3 0 A 2 0 1 A 1 1 2 B 9 9 3 NaN 8 4 4 D 7 2 5 C 4 3 

Puedo agregar nuevas columnas ( math ) y luego rellenarlas con una expresión matemática basada en la sum de 10 y col3 .

 df['math'] = 10 + df['col3'] In [14]: df Out[14]: col1 col2 col3 math 0 A 2 0 10 1 A 1 1 11 2 B 9 9 19 3 NaN 8 4 14 4 D 7 2 12 5 C 4 3 13 

pero lo que no puedo entender es cómo condicionar la expresión al valor en otra columna (por ejemplo, solo si col1 == B ). La salida deseada sería:

 In [14]: df Out[14]: col1 col2 col3 math 0 A 2 0 NaN 1 A 1 1 NaN 2 B 9 9 19 3 NaN 8 4 NaN 4 D 7 2 NaN 5 C 4 3 NaN 

Para mayor aclaración, col1 una variable para el valor col1 en un for loop . Como resultado, no pude hacer que .group_by() funcione como se describe aquí o aquí . Creo que estoy buscando algo como esto …

 df['math'] = 10 + df.loc[[df['col1'] == my_var], 'col3'] 

que obtuve del comentario en el segundo ejemplo anterior, pero no puedo hacerlo funcionar. ValueError un ValueError para demasiados valores, es decir, estoy tratando de pasar el filtro y la columna de la operación juntos, pero solo está esperando el filtro. Esta publicación de SO también usa el .loc similar a mi expresión anterior, pero con un col1 estático.

Usando loc

 df['math'] = df.loc[df.col1.eq('B'), 'col3'].add(10) col1 col2 col3 math 0 A 2 0 NaN 1 A 1 1 NaN 2 B 9 9 19.0 3 NaN 8 4 NaN 4 D 7 2 NaN 5 C 4 3 NaN 

where

Realizo la matemática y luego la enmascaré usando pandas.Series.where al pasar la serie booleana df.col1.eq('B')

 df.assign(math=df.col3.add(10).where(df.col1.eq('B'))) col1 col2 col3 math 0 A 2 0 NaN 1 A 1 1 NaN 2 B 9 9 19.0 3 NaN 8 4 NaN 4 D 7 2 NaN 5 C 4 3 NaN 

Uso: (No es una forma segura de lograrlo, vea el comentario a continuación)

 df['New']=df.col3[df.col1=='B']+10 df Out[11]: col1 col2 col3 New 0 A 2 0 NaN 1 A 1 1 NaN 2 B 9 9 19.0 3 NaN 8 4 NaN 4 D 7 2 NaN 5 C 4 3 NaN 

Actualizar

 pd.concat([df,(df.col3[df.col1=='B']+10).to_frame('New')],1) Out[51]: col1 col2 col3 New 0 A 2 0 NaN 1 A 1 1 NaN 2 B 9 9 19.0 3 NaN 8 4 NaN 4 D 7 2 NaN 5 C 4 3 NaN 

También pude hacer lo siguiente …

 df['math'] = 10 + df.loc[df['col1'] == 'B']['col3'] 

Que es una variación en @ user3483203 respuesta anterior. En última instancia, mi 'B' es una variable, así que modifiqué los comentarios de @RafaelC.

Estaba lanzando ValueError ya que no estaba usando la ubicación correctamente. Aquí está la solución usando loc:

 df.loc[:,'math'] = 10 + df.loc[df['col1'] == "B", 'col3'] 

Salida:

  col1 col2 col3 math 0 A 2 0 NaN 1 A 1 1 NaN 2 B 9 9 19.0 3 NaN 8 4 NaN 4 D 7 2 NaN 5 C 4 3 NaN