Aplicar la función de Python a una columna de pandas y aplicar la salida a varias columnas
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
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 apply
crea columnas individuales, formando un marco de datos que luego puede asignar a cat
y 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.
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.
Estás pasando todo el lugar dataframe
donde solo necesitas pasar la variable lambda ( x
).
df[['cat','subcat']] = df['remark'].apply(lambda x: pd.Series([*conditions(x)]))
*
en iterables, puede utilizarlos unpack
para 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 ...
Puede usar series.replace
con 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