Aplicar la función de Python a una columna de pandas y aplicar la salida a varias columnas

Aug 20 2020

Hola comunidad,

¡He leído tantas respuestas y blogs, pero no puedo entender qué cosa simple me estoy perdiendo !. Estoy usando la función 'condiciones' para definir todas las condiciones y aplicarlas a una columna de marco de datos. Y si la condición se cumple, debería crear / actualizar 2 nuevas columnas de marco de datos 'cat' y 'subcat'.

¡Sería de gran ayuda si ustedes pudieran ayudarme aquí!

dict = {'remark':['NA','NA','Category1','Category2','Category3'],
        'desc':['Present','Present','NA','Present','NA']
} 

df = pd.DataFrame(dict) 

El marco de datos se parece a esto:

          remark       desc
0         NA           Present      
1         NA           Present        
2         Category1    NA                   
3         Category2    Present                   
4         Category3    NA            

He escrito una función para definir las condiciones de la siguiente manera:

def conditions(s):

    if (s == 'Category1'):
        x = 'insufficient'
        y = 'resolution'
    elif (s=='Category2):
        x= 'insufficient'
        y= 'information'
    elif (s=='Category3):
        x= 'Duplicate'
        y= 'ID repeated'
    else:
        x= 'NA'
        y= 'NA'
    
    return (x,y)

Tengo varias ideas para ejecutar la función anterior en la columna del marco de datos, pero no tuve suerte.

df[['cat','subcat']] = df['remark'].apply(lambda x: pd.Series([conditions(df)[0],conditions(df)[1]]))

Mi marco de datos esperado debería verse así:

          remark       desc        cat           subcat
0         NA           Present     NA            NA      
1         NA           Present     NA            NA
2         Category1    NA          insufficient  resolution         
3         Category2    Present     insufficient  information              
4         Category3    NA          Duplicate     ID repeated

Muchas gracias.

Respuestas

2 sammywemmy Aug 20 2020 at 04:10

Una forma de evitar esto es con una lista de comprensión:

df[['cat', 'subcat']] = [("insufficient", "resolution")  if word == "Category1" else 
                         ("insufficient", "information") if word == "Category2" else
                         ("Duplicate", "ID repeated")    if word == "Category3" else 
                         ("NA", "NA")
                         for word in df.remark]

  remark      desc               cat         subcat
0   NA        Present          NA              NA
1   NA        Present          NA              NA
2   Category1   NA          insufficient    resolution
3   Category2   Present     insufficient    information
4   Category3   NA          Duplicate       ID repeated

La respuesta de @ dm2 muestra cómo lograrlo con su función. El primero apply(conditions)crea una serie que contiene tuplas, el segundo applycrea columnas individuales, formando un marco de datos que luego puede asignar a caty subcat.

La razón por la que sugiero una lista de comprensión es porque, en una que se trata de cadenas, y en Pandas, trabajar con cadenas a través de vanilla python es a menudo más rápido que no. Además, con la comprensión de la lista, el procesamiento se realiza una vez, no es necesario aplicar la función de condiciones y luego llamar pd.Series. Eso te da una velocidad más rápida. Las pruebas afirmarán o desacreditarán esto.

2 dm2 Aug 20 2020 at 04:12

Podrías hacerlo:

 df[['cat','subcat']] = df['remark'].apply(conditions).apply(pd.Series)

Salida:

  remark      desc               cat         subcat
0   NA        Present          NA              NA
1   NA        Present          NA              NA
2   Category1   NA          insufficient    resolution
3   Category2   Present     insufficient    information
4   Category3   NA          Duplicate       ID repeated

Editar: Esta podría ser la forma más sencilla de aplicar su función que ya tiene, pero en caso de que tenga un DataFrame enorme, para un código más rápido, consulte la respuesta de @sammywemmy usando la comprensión de listas.

1 Quentin Aug 20 2020 at 04:13

Estás pasando todo el lugar dataframedonde solo necesitas pasar la variable lambda ( x).

df[['cat','subcat']] = df['remark'].apply(lambda x: pd.Series([*conditions(x)]))

*en iterables, puede utilizarlos unpackpara que no necesite llamar a la misma función dos veces para extraer la salida. Quizás el compilador resuelva esto pero no lo creo ...

RichieV Aug 20 2020 at 04:11

Puede usar series.replacecon un diccionario de mapas

df['cat'] = df.remark.replace({'Category1': 'insufficient',
    'Category2': 'insufficient', 'Category3': 'Duplicate'})
df['subcat'] = df.remark.replace({'Category1': 'resolution',
    'Category2': 'information', 'Category3': 'ID repeated'})

print(df)
      remark     desc           cat       subcat
0         NA  Present            NA           NA
1         NA  Present            NA           NA
2  Category1       NA  insufficient   resolution
3  Category2  Present  insufficient  information
4  Category3       NA     Duplicate  ID repeated