Tengo una trama de datos pandas, df_test
. Contiene una columna 'tamaño' que representa el tamaño en bytes. Calculé KB, MB y GB con el siguiente código:
df_test = pd.DataFrame([
{'dir': '/Users/uname1', 'size': 994933},
{'dir': '/Users/uname2', 'size': 109338711},
])
df_test['size_kb'] = df_test['size'].astype(int).apply(lambda x: locale.format("%.1f", x / 1024.0, grouping=True) + ' KB')
df_test['size_mb'] = df_test['size'].astype(int).apply(lambda x: locale.format("%.1f", x / 1024.0 ** 2, grouping=True) + ' MB')
df_test['size_gb'] = df_test['size'].astype(int).apply(lambda x: locale.format("%.1f", x / 1024.0 ** 3, grouping=True) + ' GB')
df_test
dir size size_kb size_mb size_gb
0 /Users/uname1 994933 971.6 KB 0.9 MB 0.0 GB
1 /Users/uname2 109338711 106,776.1 KB 104.3 MB 0.1 GB
[2 rows x 5 columns]
He ejecutado esto en más de 120,000 filas y el tiempo toma aproximadamente 2.97 segundos por columna * 3 = ~ 9 segundos según% timeit.
¿Hay alguna forma de que pueda hacer esto más rápido? Por ejemplo, ¿puedo en lugar de devolver una columna a la vez después de aplicarla y ejecutarla 3 veces, puedo devolver las tres columnas en una sola pasada para volver a insertarlas en el marco de datos original?
Todas las otras preguntas que he encontrado quieren tomar varios valores y devolver un solo valor . Quiero tomar un solo valor y devolver varias columnas .
rows_list
en esta respuesta?pd.Series(data, index=...)
. De lo contrario, obtendrá errores crípticos cuando intente volver a asignar el resultado al marco de datos principal.Use aplicar y sellar 3 veces más rápido que en serie.
Los resultados de la prueba son:
fuente
Algunas de las respuestas actuales funcionan bien, pero quiero ofrecer otra opción, tal vez más "pandificada". Esto funciona para mí con los pandas actuales 0.23 (no estoy seguro de si funcionará en versiones anteriores):
Tenga en cuenta que el truco está en el
result_type
parámetro deapply
, que expandirá su resultado a unDataFrame
que se puede asignar directamente a columnas nuevas / antiguas.fuente
Solo otra forma legible. Este código agregará tres columnas nuevas y sus valores, devolviendo series sin parámetros de uso en la función de aplicación.
Un ejemplo general de: https://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.apply.html
fuente
¡Respuestas realmente geniales! ¡Gracias Jesse y jaumebonet! Solo una observación con respecto a:
zip(* ...
... result_type="expand")
Aunque expandir es un poco más elegante ( pandificado ), zip es al menos ** 2 veces más rápido . En este simple ejemplo a continuación, obtuve 4 veces más rápido .
fuente
El desempeño entre las respuestas principales es significativamente variado, y Jesse y famaral42 ya han discutido esto, pero vale la pena compartir una comparación justa entre las respuestas principales y desarrollar un detalle sutil pero importante de la respuesta de Jesse: el argumento pasó a la función, también afecta el rendimiento .
(Python 3.7.4, Pandas 1.0.3)
Aquí están los resultados:
Observe cómo devolver tuplas es el método más rápido, pero lo que se pasa en un argumento, también afecta al rendimiento. La diferencia en el código es sutil pero la mejora del rendimiento es significativa.
La prueba n. ° 4 (pasar un solo valor) es dos veces más rápida que la prueba n. ° 3 (pasar una serie), aunque la operación realizada es aparentemente idéntica.
Pero hay más ...
En algunos casos (# 1a y # 4a), aplicar la función a un DataFrame en el que las columnas de salida ya existen es más rápido que crearlas desde la función.
Aquí está el código para ejecutar las pruebas:
fuente
Creo que la versión 1.1 rompe el comportamiento sugerido en la respuesta principal aquí.
El código anterior se ejecutó en pandas 1.1.0 devuelve:
Mientras que en pandas 1.0.5 regresó:
Lo que creo que es lo que esperarías.
No estoy seguro de cómo las notas de la versión explican este comportamiento, sin embargo, como se explica aquí, evitar la mutación de las filas originales al copiarlas resucita el comportamiento anterior. es decir:
fuente
Generalmente, para devolver múltiples valores, esto es lo que hago
Devolver un marco de datos definitivamente tiene sus ventajas, pero a veces no es obligatorio. Puedes mirar lo que
apply()
devuelve y jugar un poco con las funciones;)fuente
Proporciona un nuevo marco de datos con dos columnas del original.
fuente