Pandas – Calcular nuevo valor basado en referencia cruzada con otra columna

Estoy tratando de calcular nuevos valores en una columna cuyos valores son referencias cruzadas a otra columna.

>>> import pandas as pd >>> df = pd.DataFrame( {"A":[0., 100., 80., 40., 0., 60.], "B":[12, 12, 3, 19, 3, 19]} ) >>> df AB 0 0.0 12 1 100.0 12 2 80.0 3 3 40.0 19 4 0.0 3 5 60.0 19 

Quiero encontrar todos los valores en la columna A que son 0, encontrar el valor correspondiente en la columna B, luego cambiar todos los valores de la columna A que tienen el mismo valor de la columna B, de acuerdo con alguna función. Por ejemplo, en el ejemplo anterior me gustaría cambiar los dos primeros valores de la columna A, df.A[0] y df.A[1] , respectivamente, 0. y 100., a 0.5 y 99.5, porque df.A[0] es 0. y tiene el mismo valor df.B[0] = 12 en la columna B que df.B[1] = 12 .

 df AB 0 0.5 12 1 99.5 12 2 79.5 3 3 40.0 19 4 0.5 3 5 60.0 19 

Intenté encadenar las funciones loc, agregadas, grupales y de máscara, pero no estoy teniendo éxito. ¿Es el único camino a través de un bucle for?


EDITAR: Ejemplo ampliado para ilustrar mejor la intención.

Esto funcionará:

 import pandas as pd df = pd.DataFrame( {"A":[0., 100., 40., 60.], "B":[12, 12, 19, 19]} ) def f(series): return (series + 0.5).where(series == 0, series - 0.5) B_value = df.loc[df['A'] == 0, 'B'][0] df.loc[df['B'] == B_value, 'A'] = df.loc[df['B'] == B_value, 'A'].transform(f) print(df) 

Salida:

  AB 0 0.5 12 1 99.5 12 2 40.0 19 3 60.0 19 

Puedes pasar una función arbitraria a transform .

Puede haber una forma más limpia de hacer esto; Me parece un poco desordenado.

Encontré una solución de trabajo, aunque probablemente sub-óptima. Encadenar groupby, filtrar y transformar para obtener una serie deseada, y luego reemplazar el resultado en el dataframe original.

 import pandas as pd df = pd.DataFrame( {"A":[0., 100., 80., 40., 0., 60.], "B":[12, 12, 3, 19, 3, 19]} ) u = ( df.groupby(by="B", sort=False) .filter(lambda x: xAmin() == 0, dropna=False) .A.transform( lambda x: (x+0.5).where(x == 0, x - 0.5) ) ) df.loc[pd.notnull(u), "A"] = u 

da los siguientes resultados

 print("\ninitial df\n",df,"\n\nintermediate series\n",u,"\n\nfinal result",df) initial df AB 0 0.0 12 1 100.0 12 2 80.0 3 3 40.0 19 4 0.0 3 5 60.0 19 intermediate series 0 0.5 1 99.5 2 79.5 3 NaN 4 0.5 5 NaN Name: A, dtype: float64 final result AB 0 0.5 12 1 99.5 12 2 79.5 3 3 40.0 19 4 0.5 3 5 60.0 19