Cómo hacer esto en pandas:
Tengo una función extract_text_features
en una sola columna de texto, devolviendo múltiples columnas de salida. Específicamente, la función devuelve 6 valores.
La función funciona, sin embargo, no parece haber ningún tipo de retorno adecuado (pandas DataFrame / numpy array / Python list) de modo que la salida se pueda asignar correctamente df.ix[: ,10:16] = df.textcol.map(extract_text_features)
Entonces, creo que tengo que volver a iterar df.iterrows()
, ¿según esto ?
ACTUALIZACIÓN: Iterar con df.iterrows()
es al menos 20 veces más lento, así que me entregué y dividí la función en seis .map(lambda ...)
llamadas distintas .
ACTUALIZACIÓN 2: esta pregunta se hizo alrededor de v0.11.0 . Por lo tanto, gran parte de las preguntas y respuestas no son demasiado relevantes.
df.ix[: ,10:16]
. Creo que tendrás quemerge
incluir tus funciones en el conjunto de datos.apply
Respuestas:
Partiendo de la respuesta del usuario1827356, puede hacer la tarea de una sola vez usando
df.merge
:EDITAR: Tenga en cuenta el gran consumo de memoria y la baja velocidad: https://ys-l.github.io/posts/2015/08/28/how-not-to-use-pandas-apply/ !
fuente
Usualmente hago esto usando
zip
:fuente
temp = list(zip(*df['num'].map(powers))); for i, c in enumerate(columns): df[c] = temp[c]
for i, c in enumerate(columns): df[c] = temp[i]
. Gracias a esto, realmente obtuve el propósito deenumerate
: Dzip(*df['col'].map(function))
es probablemente el camino a seguir.Esto es lo que he hecho en el pasado.
Edición para completar
fuente
df[['col1', 'col2']] = df['col3'].apply(lambda x: pd.Series('val1', 'val2'))
Esta es la forma correcta y más fácil de lograr esto para el 95% de los casos de uso:
fuente
pd.Series({k:v})
ay serializar la asignación de columna como en la respuesta de Ewan?En 2018, uso
apply()
con argumentoresult_type='expand'
fuente
pd.Series
que siempre es bueno con respecto a los problemas de rendimientodf.apply
devuelve adict
, las columnas aparecerán nombradas de acuerdo con las teclas.Solo usa
result_type="expand"
fuente
Resumen: si solo desea crear unas pocas columnas, use
df[['new_col1','new_col2']] = df[['data1','data2']].apply( function_of_your_choosing(x), axis=1)
Para esta solución, el número de columnas nuevas que está creando debe ser igual al número de columnas que usa como entrada para la función .apply (). Si quieres hacer otra cosa, mira las otras respuestas.
Detalles Supongamos que tiene un marco de datos de dos columnas. La primera columna es la altura de una persona cuando tiene 10 años; el segundo es la altura de dicha persona cuando tiene 20 años.
Suponga que necesita calcular tanto la media de las alturas de cada persona como la suma de las alturas de cada persona. Eso es dos valores por cada fila.
Puede hacerlo a través de la siguiente función, que pronto se aplicará:
Puede usar esta función así:
(Para ser claros: esta función de aplicación toma los valores de cada fila en el marco de datos subconjunto y devuelve una lista).
Sin embargo, si haces esto:
creará 1 nueva columna que contenga las listas [mean, sum], que probablemente querría evitar, porque eso requeriría otra Lambda / Apply.
En cambio, desea dividir cada valor en su propia columna. Para hacer esto, puede crear dos columnas a la vez:
fuente
df["mean"], df["sum"] = df[['height_at_age_10','height_at_age_20']] .apply(mean_and_sum(x),axis=1)
return pd.Series([mean,sum])
Para mí esto funcionó:
Entrada df
Función
Crea 2 nuevas columnas:
Salida:
fuente
He buscado varias formas de hacer esto y el método que se muestra aquí (devolver una serie de pandas) no parece ser el más eficiente.
Si comenzamos con un marco de datos más grande de datos aleatorios:
El ejemplo que se muestra aquí:
Un método alternativo:
Según mis cálculos, es mucho más eficiente tomar una serie de tuplas y luego convertirlas en un DataFrame. Sin embargo, me interesaría escuchar el pensamiento de las personas si hay un error en mi trabajo.
fuente
La solución aceptada será extremadamente lenta para muchos datos. La solución con el mayor número de votos positivos es un poco difícil de leer y también lenta con datos numéricos. Si cada nueva columna se puede calcular independientemente de las demás, simplemente asignaría cada una de ellas directamente sin usarlas
apply
.Ejemplo con datos de personajes falsos
Crea 100,000 cadenas en un DataFrame
Digamos que queríamos extraer algunas características del texto como se hizo en la pregunta original. Por ejemplo, extraigamos el primer carácter, cuentemos la aparición de la letra 'e' y capitalicemos la frase.
Tiempos
Sorprendentemente, puede obtener un mejor rendimiento al recorrer cada valor
Otro ejemplo con datos numéricos falsos
Crea 1 millón de números aleatorios y prueba la
powers
función desde arriba.Asignar cada columna es 25 veces más rápido y muy legible:
Hice una respuesta similar con más detalles aquí sobre por qué
apply
generalmente no es el camino a seguir.fuente
Han publicado la misma respuesta en otras dos preguntas similares. La forma en que prefiero hacer esto es envolver los valores de retorno de la función en una serie:
Y luego use aplicar de la siguiente manera para crear columnas separadas:
fuente
puede devolver la fila completa en lugar de valores:
donde la función devuelve la fila
fuente
extract_text_features
a todas las columnas del df, solo a la columna de textodf.textcol
Esto funcionó para mí. Se creará una nueva columna con datos procesados de la columna anterior.
fuente