Regularmente realizo operaciones de pandas en marcos de datos de más de 15 millones de filas y me encantaría tener acceso a un indicador de progreso para operaciones particulares.
¿Existe un indicador de progreso basado en texto para las operaciones de división, aplicación y combinación de pandas?
Por ejemplo, en algo como:
df_users.groupby(['userID', 'requestDate']).apply(feature_rollup)
donde feature_rollup
es una función algo complicada que toma muchas columnas DF y crea nuevas columnas de usuario a través de varios métodos. Estas operaciones pueden tomar un tiempo para grandes marcos de datos, por lo que me gustaría saber si es posible tener una salida basada en texto en un cuaderno iPython que me actualice sobre el progreso.
Hasta ahora, he probado los indicadores de progreso de bucle canónico para Python, pero no interactúan con los pandas de ninguna manera significativa.
Espero que haya algo que he pasado por alto en la biblioteca / documentación de pandas que le permite a uno saber el progreso de una combinación de aplicación dividida. Una implementación simple podría considerar el número total de subconjuntos de marcos de datos sobre los que apply
funciona la función e informar el progreso como la fracción completa de esos subconjuntos.
¿Es esto quizás algo que debe agregarse a la biblioteca?
Respuestas:
Debido a la demanda popular,
tqdm
ha agregado soporte parapandas
. A diferencia de las otras respuestas, esto no ralentizará notablemente a los pandas : aquí hay un ejemplo paraDataFrameGroupBy.progress_apply
:En caso de que esté interesado en cómo funciona esto (y cómo modificarlo para sus propias devoluciones de llamada), vea los ejemplos en github , la documentación completa en pypi , o importe el módulo y ejecútelo
help(tqdm)
.EDITAR
Para responder directamente a la pregunta original, reemplace:
con:
Nota: tqdm <= v4.8 : para versiones de tqdm por debajo de 4.8, en lugar de lo
tqdm.pandas()
que tenía que hacer:fuente
tqdm
en realidad fue creado para iterables acaba de civil, país de origen:from tqdm import tqdm; for i in tqdm( range(int(1e8)) ): pass
El apoyo pandas era un corte reciente que hice :)from tqdm import tqdm_notebook; tqdm_notebook().pandas(*args, **kwargs)
ver aquítqdm
v5, lo que hace que las cosas estén más modularizadas.Para ajustar la respuesta de Jeff (y tener esto como una función reutilizable).
Nota: el porcentaje de progreso de la aplicación se actualiza en línea . Si su función stdouts entonces esto no funcionará.
Como de costumbre, puede agregar esto a sus objetos groupby como método:
Como se menciona en los comentarios, esta no es una característica que los pandas centrales estarían interesados en implementar. Pero Python le permite crear estos para muchos objetos / métodos de pandas (hacerlo sería bastante trabajo ... aunque debería poder generalizar este enfoque).
fuente
En caso de que necesite soporte sobre cómo usar esto en un cuaderno Jupyter / ipython, como lo hice, aquí hay una guía útil y una fuente del artículo relevante :
Tenga en cuenta el guión bajo en la declaración de importación para
_tqdm_notebook
. Como se menciona en el artículo mencionado, el desarrollo se encuentra en una etapa beta tardía.fuente
Para cualquiera que esté buscando aplicar tqdm en su código personalizado de aplicación de pandas paralelo.
(Probé algunas de las bibliotecas para la paralelización a lo largo de los años, pero nunca encontré una solución de paralelización al 100%, principalmente para la función de aplicación, y siempre tuve que volver por mi código "manual").
df_multi_core : este es el que usted llama. Acepta:
_df_split : esta es una función auxiliar interna que debe colocarse globalmente en el módulo en ejecución (Pool.map es "dependiente de la ubicación"), de lo contrario la ubicaría internamente.
Aquí está el código de mi esencia ( agregaré más pruebas de función de pandas allí):
A continuación se muestra un código de prueba para una aplicación paralela con tqdm "progress_apply".
En la salida puede ver 1 barra de progreso para ejecutar sin paralelización y barras de progreso por núcleo cuando se ejecuta con paralelización. Hay una ligera interrupción y, a veces, el resto de los núcleos aparecen a la vez, pero incluso entonces creo que es útil ya que obtienes las estadísticas de progreso por núcleo (it / sec y registros totales, por ejemplo)
¡Gracias @abcdaa por esta gran biblioteca!
fuente
try: splits = np.array_split(df[subset], njobs) except ValueError: splits = np.array_split(df, njobs)
debido a la excepción KeyError en lugar de ValueError, cambie a Exception para manejar todos los casos.Puedes hacerlo fácilmente con un decorador
luego use la función modified_function (y cambie cuando quiera que se imprima)
fuente
logged_apply(g, func)
función, donde tendría acceso al pedido, y podría iniciar sesión desde el principio.He cambiado la respuesta de Jeff , para incluir un total, de modo que pueda seguir el progreso y una variable para imprimir cada X iteraciones (esto en realidad mejora mucho el rendimiento, si el "print_at" es razonablemente alto)
la función clear_output () es de
si no está en IPython, la respuesta de Andy Hayden lo hace sin ella
fuente