Course
Tqdm Python: Una guía con ejemplos prácticos
¿Te has encontrado alguna vez en una situación en la que un guión de Python de larga duración te hacía preguntarte si pasaba algo detrás de la pantalla?
La incertidumbre sobre el progreso puede llevarte a cancelar una ejecución casi completa o a esperar interminablemente una ejecución de script ya interrumpida.
La página tqdm
Python aborda este problema proporcionando indicadores de progreso para tus scripts.
¿Qué es tqdm?
Tqdm es una biblioteca de Python que proporciona barras de progreso rápidas y extensibles para bucles e iterables. Es una forma sencilla de seguir el avance de las tareas que requieren mucho tiempo.
El nombre de la biblioteca significa "progreso" en árabe (taqadum, تقدّم), y es una abreviatura de "te quiero demasiado" en español (te quiero demasiado).
Tdqm realiza un seguimiento del progreso y actualiza la visualización de la barra de progreso contando las iteraciones, calculando el tiempo transcurrido y el tiempo restante, y visualizando el progreso global en el relleno de la barra.
Utiliza algoritmos inteligentes para predecir el tiempo restante, y omite las visualizaciones de iteración innecesarias para minimizar la sobrecarga. Utilizar tqdm
ofrece varias ventajas, entre ellas
- Retroalimentación visual: Las barras de progreso permiten a los usuarios ver qué parte de una tarea se ha completado y estimar cuánto tiempo puede llevar la parte restante.
- Funciona en todas partes: La biblioteca
tqdm
funciona en cualquier plataforma (Linux, Windows, Mac, FreeBSD, NetBSD, SunOS), en cualquier consola o en una GUI. - Fácil integración:
Tqdm
se integra perfectamente con los cuadernos Jupyter, bibliotecas comunes como Pandasy construcciones comunes de Python como los bucles. - Personalización: Ofrece varias opciones para adaptar el aspecto y el comportamiento de las barras de progreso, en las que entraremos más adelante.
- Rendimiento: Mientras que paquetes similares como ProgressBar tienen una sobrecarga de 800ns/iteración, la sobrecarga de tdqm de 60ns/iteración funciona mucho más rápido.
Conviértete en Ingeniero de Datos
Desarrolla tus habilidades en Python para convertirte en un ingeniero de datos profesional.
Cómo instalar Tqdm
Como para la mayoría de las bibliotecas de Python, la forma más sencilla de instalar tqdm
es utilizar el gestor de paquetes pip
.
pip install tqdm
Tqdm: Ejemplo sencillo
Para crear una barra de progreso, envolvemos nuestro iterable con la función tqdm()
(que importamos del módulo tqdm
). Veamos un ejemplo sencillo. La función time.sleep(0.01)
sirve como marcador de posición para el código que se supone que se ejecuta en cada iteración.
from tqdm import tqdm
for i in tqdm(range(1000)):
time.sleep(0.01)
# …
Como atajo para tdqm(range(n))
también puedes utilizar trange(n)
. El código siguiente devolverá exactamente el mismo resultado que el anterior:
from tqdm import tqdm
for i in trange(1000):
time.sleep(0.01)
# …
Ambos ejemplos devolverán una barra de progreso parecida a la anterior.
Fíjate bien en la barra de progreso para ver qué información proporciona. Desglosemos los detalles presentados por tqdm
:
- Indicadores de progreso:
- Porcentaje de iteraciones
- Relleno de barra
- Fracción de iteraciones totales
- Métricas:
- Tiempo transcurrido
- Tiempo estimado restante
- Rendimiento (iteraciones por segundo)
Personalización Tqdm: Progresar con tus propias barras
Tqdm
ofrece varias opciones de personalización para adaptar el aspecto y el comportamiento de las barras de progreso. Echaremos un vistazo a los parámetros de personalización más importantes antes de examinar casos de uso más avanzados de tqdm
.
Añadir una descripción de la barra de progreso
Una personalización común es añadir una etiqueta descriptiva utilizando el parámetro desc
, lo que hace que la barra de progreso sea más informativa y ayuda a mantener una visión general sobre los diferentes iterables.
Por ejemplo, si añades el parámetro desc=”Processing large range”
, aparecerá el título "Procesando rango grande" a la izquierda de la barra de progreso.
for _ in tqdm(range(20000000), desc="Processing large range"):
continue
Te animo a que ejecutes el código anterior en tu entorno con y sin el parámetro desc
y notes las diferencias.
Especificar el número total de iteraciones
El parámetro total
especifica el número total de iteraciones del bucle, lo que permite a tqdm
proporcionar estimaciones más precisas del tiempo restante y del porcentaje de finalización.
En un ejemplo básico que utilice tqdm(range())
o trange()
esto no es necesario, puesto que el número de iteraciones ya está incluido en los corchetes. Sin embargo, hay dos situaciones principales en las que puede ser útil añadir el parámetro total=n
(siendo n el número total):
1. Iterables sin método len()
: Para iterables sin método len()
, como generadores con un número desconocido de elementos, tienes que proporcionar el valor total
manualmente. Sin este parámetro, tqdm()
sólo mostrará el recuento de iteraciones completadas. Ten en cuenta que la barra de progreso comienza de nuevo, si el número real de elementos supera el número total
especificado.
from tqdm import tqdm
import time
import random
# Function generating random number between 1 and 100
def generate_random_numbers():
while True:
yield random.randint(1, 100)
# Without total: tqdm() only shows number of iterations, does not know total
for num in tqdm(generate_random_numbers(), desc=’Random Iteration’):
time.sleep(0.01)
# …
Este es el aspecto que tiene si se desconoce el número de artículos y no especificamos el total.
# With total (assuming you know the desired number of iterations): tqdm() shows progress
num_iterations = 1000
for num in tqdm(generate_random_numbers(), total=num_iterations, desc="Random Iteration"):
time.sleep(0.01)
# …
Mucho mejor, ¡ahora se muestra la barra de progreso!
2. Actualizaciones manuales: Si estamos actualizando la barra de progreso manualmente dentro de una función utilizando el método update()
, es necesario especificar el valor total para garantizar un seguimiento correcto del progreso. El método update()
permite, por ejemplo, responder a procesos que cambian dinámicamente o realizar un seguimiento personalizado del progreso. Ya hablaremos de ello más adelante.
Ajustar el aspecto visual
Si queremos ajustar el orden de colocación en el que aparecen los elementos de la barra de progreso, podemos establecer el parámetro bar_format
a la cadena de formato preferida. De esta forma, podemos controlar la colocación de varios elementos como el porcentaje, el tiempo transcurrido y el carácter de relleno de la barra. Para más detalles, puedes consultar la documentación.
Otro ajuste del aspecto visual puede hacerse utilizando el parámetro colour
. Es posible utilizar cadenas de palabras como "verde" o cadenas de código hexadecimal como "#00ff00".
El parámetro leave
se refiere más a la desaparición que a la aparición: determina si la barra de progreso permanece visible o no tras su finalización. Si se establece en True
, la barra persistirá después de que termine el bucle; si se establece en False
, desaparecerá.
Veamos las diferencias visuales de los resultados en otro ejemplo. El código siguiente crea tres barras de progreso: una con la configuración por defecto, otra en la que se cambian el orden y el color de los elementos, y otra que se configura para que desaparezca una vez completada. Los resultados son visibles en el GIF siguiente.
from tqdm import tqdm
import time
# Progress bar 1: Default settings
for i in tqdm(range(300)):
time.sleep(0.01)
# Progress bar 2: Customized bar format and color
for i in tqdm(range(300), bar_format='[{elapsed}<{remaining}] {n_fmt}/{total_fmt} | {l_bar}{bar} {rate_fmt}{postfix}', colour='yellow'):
time.sleep(0.01)
# Progress bar 3: Customized bar format and color, leave=False
for i in tqdm(range(300), bar_format='[{elapsed}<{remaining}] {n_fmt}/{total_fmt} | {l_bar}{bar} {rate_fmt}{postfix}', colour='red', leave=False):
time.sleep(0.01)
Uso avanzado: Manejo de escenarios más complejos
Ahora que sabemos cómo construir una barra de progreso sencilla y cómo personalizarla, podemos pasar a algunos casos más avanzados.
Barras de progreso anidadas
Los bucles anidados son bucles que están contenidos dentro de otros bucles. En consecuencia, las barras de progreso anidadas son una serie de barras de progreso para cada iteración de bucles contenidos dentro de otros bucles. Para crearlos, envuelve cada bucle con una función tqdm()
y añade etiquetas descriptivas para cada iterable.
El código siguiente tiene tres bucles anidados y es capaz de dar un ejemplo de cómo aparecerán las barras de progreso anidadas:
from tqdm import trange
import time
for i in trange(3, desc='outer loop'):
for j in trange(2, desc='middle loop'):
for k in trange(6, desc='inner loop'):
time.sleep(0.01)
En la salida final anterior, podemos reconocer un patrón en el que se actualizan las distintas barras de progreso. Tqdm empezará siempre por el bucle más externo hasta llegar al más interno, cuyas iteraciones se procesarán y la barra de progreso se actualizará en consecuencia.
Supongamos que tenemos tres bucles anidados, como en el ejemplo. Tras la iteración interna inicial, pasará al bucle central, lo actualizará como si tuviera una iteración completa, antes de volver al iterable interno. Este proceso se repite hasta que el bucle central se marca como completo, lo que hará que aparezca la barra exterior con una iteración completa.
Lo mismo ocurre entre el bucle exterior y el central. Al final, la última iteración interna completa la iterable media, que a su vez completa la última iteración externa.
Actualizaciones manuales
Actualizar manualmente las barras de progreso con tqdm
puede ser útil en varios escenarios:
- Iterables de longitud desconocida: Cuando trabajamos con iterables que no tienen una longitud definida (por ejemplo, generadores, flujos de red), podemos actualizar manualmente la barra de progreso en función de la cantidad de datos procesados o del número de operaciones completadas.
- Procesos dinámicamente cambiantes: Si el número de iteraciones o el tiempo de procesamiento por iteración pueden cambiar durante la ejecución, las actualizaciones manuales nos permiten ajustar la barra de progreso en consecuencia.
- Seguimiento personalizado del progreso: Para tener un control más granular sobre la barra de progreso, podemos actualizarla manualmente en función de criterios o eventos específicos. Por ejemplo, podríamos querer actualizar la barra de progreso en función de la finalización de determinados hitos o del progreso de tareas individuales dentro de un proceso mayor.
- Integración con sistemas externos: Si estamos integrando
tqdm
con sistemas o bibliotecas externas que no proporcionan una forma natural de seguir el progreso, se pueden utilizar actualizaciones manuales para sincronizar la barra de progreso con el proceso externo.
Para actualizar manualmente una barra de progreso tqdm
, es importante que el parámetro total
se especifique como la estimación del número máximo esperado de iteraciones. Luego, a medida que el código procesa cada nuevo elemento, la barra de progreso debe actualizarse utilizando el método update()
. El valor de actualización debe representar el número de iteraciones procesadas desde la última actualización.
Supongamos que esperamos que nuestro iterable contenga hasta 750 elementos. En este ejemplo, la longitud real es un número aleatorio entre 100 y 1000, que desconocemos. Iniciamos la progress_bar
, fijando estimated_total
en 750. Luego iteramos a través de los datos, actualizando la barra de progreso después de procesar cada punto.
from tqdm import tqdm
def process_data(data):
time.sleep(0.01) # simulate processing data
processed_data = data
return processed_data
# Generate an iterable with random length between 100 and 1,000
random_length = random.randint(100, 1000)
data_list = [i for i in range(random_length)]
# Define estimated maximum number of iterations
estimated_total = 750
# Define the progress bar using the estimated_total
progress_bar = tqdm(total=estimated_total)
# Iterating through data list of unknown length
for data in data_list:
processed_data = process_data(data)
progress_bar.update(1)
Subestimamos la longitud del iterable, haciendo que la salida siguiera contando iteraciones después de alcanzar el 100% de progreso.
Multiprocesamiento
El multiprocesamiento y los hilos son técnicas utilizadas para ejecutar tareas de forma concurrente, mejorando el rendimiento y la capacidad de respuesta. En estos escenarios, puede resultar difícil seguir el progreso de las tareas individuales o el progreso global de la ejecución paralela. Tqdm
puede ser una herramienta valiosa para proporcionar información visual y controlar el progreso de estas operaciones concurrentes.
El módulo tqdm.contrib.concurrent
proporciona funciones especializadas para crear barras de progreso en contextos de multiprocesamiento o roscado. Estas funciones se encargan de la sincronización y comunicación entre el proceso principal y los procesos o hilos trabajadores, garantizando que la barra de progreso se actualice correctamente. Están diseñados para funcionar perfectamente con la API concurrent.futures
, utilizando la función ProcessPoolExecutor()
o ThreadPoolExecutor()
.
Aquí tienes un ejemplo que utiliza el módulo tqdm.contrib.concurrent.futures:
import concurrent.futures
from tqdm.contrib.concurrent import process_map
def process_data(data):
for i in tqdm(range(100), desc=f"Processing {data['name']}"):
# Process data
time.sleep(0.01)
if __name__ == '__main__':
with concurrent.futures.ProcessPoolExecutor() as executor:
results = process_map(process_data, [
{'name': 'dataset1'},
{'name': 'dataset2'},
# …
])
En este ejemplo, la función process_data()
incluye una barra de progreso tqdm
para seguir su evolución. La función process_data()
se ejecutará simultáneamente para cada dato de la lista. Esto significa que se mostrarán varias barras de progreso simultáneamente, cada una representando el progreso de un proceso distinto. El parámetro desc
está configurado para crear dinámicamente una descripción para cada barra de progreso basada en el nombre del conjunto de datos correspondiente, lo que nos ayuda a distinguir entre las distintas barras de progreso.
Integración con pandas
El módulo tqdm.pandas
proporciona una forma cómoda de añadir barras de progreso a las operaciones de pandas
. Esto es especialmente útil para operaciones que requieren mucho tiempo en grandes MarcosDeDatosya que proporciona información visual sobre el progreso de la tarea. Podemos aplicar el decorador tqdm.pandas()
a cualquier función de pandas
que opere sobre filas o columnas.
Para empezar, definimos un DataFrame aleatorio con 100.000 filas y llamamos al decorador tqdm.pandas()
. Si queremos personalizar la barra de progreso, ahora es el momento de hacerlo, ya que las funciones progress_apply()
y progress_map()
no toman los parámetros tqdm()
. Aquí queremos dar un nombre a las siguientes barras de progreso, por lo que también especificamos el parámetro desc
.
import pandas as pd
import numpy as np
from tqdm import tqdm
df = pd.DataFrame(np.random.randint(0, 10, (100000, 6)))
tqdm.pandas(desc='DataFrame Operation')
Ahora podemos aplicar funciones a filas, columnas o a todo el DataFrame. En lugar de utilizar una de las funciones apply()
o map()
, llama a progress_apply()
o progress_map()
, y se mostrará la barra de progreso. Recuerda que apply()
y progress_apply()
pueden aplicarse a DataFrames, filas o columnas, mientras que map()
y progress_map()
sólo pueden aplicarse a Series o columnas. Por ejemplo:
# Halving each value in the DataFrame using progress_apply()
Result_apply = df.progress_apply(lambda x: x / 2)
# Doubling each element of the first column using progress_map()
result_map = df[0].progress_map(lambda x: x * 2)
Tqdm: Problemas comunes y soluciones
Analicemos algunos problemas y errores comunes de Tqdm y aprendamos a solucionarlos.
La barra de progreso no se actualiza
Uno de los problemas más frecuentes al utilizar tqdm
es que la barra de progreso no se actualiza. Esto ocurre a menudo debido a problemas de almacenamiento en búfer, especialmente en entornos como Cuadernos Jupyter. Cuando la salida se almacena en la memoria intermedia, es posible que la barra de progreso no se muestre o actualice inmediatamente, dando lugar a la percepción de un proceso congelado o que no responde.
Utilizando el módulo tqdm.notebook
se pueden solucionar los problemas de almacenamiento en búfer y garantizar que la barra de progreso se actualice correctamente en los Cuadernos Jupyter. Este módulo proporciona una barra de progreso basada en GUI que está diseñada específicamente para entornos Jupyter.
Además, ofrece indicaciones de color fáciles de usar (azul: normal, verde: completado, rojo: error/interrupción).
Si interrumpimos el código de nuestro ejemplo de barra de progreso anidada, queda así:
Barras de progreso anidadas en Python utilizando tqdm.notebook
, ilustrando el esquema de colores de las barras completadas frente a las interrumpidas.
Otra forma eficaz de solucionar el problema de las barras de progreso que no se actualizan es vaciar explícitamente el flujo de salida. Cuando se escriben datos en el flujo de salida estándar (por ejemplo, utilizando print()
), los datos suelen almacenarse en un búfer antes de ser enviados al dispositivo de salida real. La descarga del flujo de salida obliga al intérprete de Python a enviar inmediatamente cualquier dato almacenado en el búfer al dispositivo de salida, garantizando que los datos se muestren o escriban sin demora.
Para vaciar la salida, utiliza el método flush()
del flujo de salida estándar. Para obtener una salida más sensible, considera la posibilidad de vaciar el flujo de salida con más frecuencia, quizás cada pocas iteraciones o después de cierto tiempo. Ten en cuenta que hay una compensación, ya que vaciar el flujo de salida puede introducir una sobrecarga adicional. He aquí un ejemplo de cómo incorporar el método a un proceso sencillo de tqdm
:
import sys
import time
from tqdm import tqdm
for i in tqdm(range(100)):
time.sleep(0.1)
sys.stdout.flush() # Flush the output stream after each iteration
Problemas de compatibilidad
Aunque tqdm
es generalmente compatible con la mayoría de los entornos y bibliotecas de Python, puede haber problemas ocasionales de compatibilidad o comportamientos inesperados. Algunas situaciones habituales que hay que tener en cuenta son
- Flujos de salida personalizados: Al utilizar flujos de salida personalizados o redirigir la salida a archivos, es posible que
tqdm
no funcione como se espera. Debemos asegurarnos de que el flujo de salida que utilizamos admite las operaciones necesarias para mostrar la barra de progreso. - Bibliotecas de terceros: En algunos casos,
tqdm
puede interactuar de forma inesperada con bibliotecas de terceros, especialmente con las que gestionan ellas mismas la salida o el seguimiento del progreso. Podemos probar a desactivar o modificar las funciones pertinentes de la biblioteca de terceros para ver si se resuelve el problema. - Compatibilidad de la versión: Siempre es una buena práctica utilizar versiones compatibles de
tqdm
y otras bibliotecas. Consulta la documentación de la biblioteca para conocer cualquier problema de compatibilidad conocido con versiones específicas de Python u otras dependencias.
Cuando nos encontremos con problemas de compatibilidad, podemos considerar las siguientes soluciones:
- Baja o sube: Podemos probar una versión diferente de
tqdm
. - Modifica el código: Si es necesario, podemos hacer ajustes en nuestro código para solucionar cualquier conflicto de compatibilidad.
- Busca ayuda en la comunidad: Si todo eso no ayuda, podemos acudir a la comunidad
tqdm
o a los foros en línea en busca de ayuda y posibles soluciones.
Teniendo en cuenta estos posibles problemas de compatibilidad y sus soluciones, podemos solucionar eficazmente cualquier problema que surja al utilizar tqdm
en nuestros proyectos de proyectos Python.
Conclusión
En conclusión, Tqdm es una biblioteca de Python que nos proporciona barras de progreso y otras estadísticas útiles, facilitando la supervisión y gestión de la ejecución del código.
Si estás iterando sobre grandes conjuntos de datos, entrenando modelos de aprendizaje automáticoo cualquier otra operación que requiera mucho tiempo, tqdm te ofrece una forma sencilla pero eficaz de controlar el progreso y mantenerte informado sobre el estado de tu código.
Para profundizar más, no dudes en consultar los otros tutoriales de Python del DataCampy la documentación de Tqdmo su código fuente y Readme en GitHub.
Preguntas frecuentes
¿Cómo puedo crear una barra de progreso sencilla con tqdm?
Instala e importa la biblioteca tqdm
, y luego envuelve tu iterable con la función tqdm()
.
¿Puedo utilizar tqdm con pandas DataFrames u otras bibliotecas?
Sí, puedes utilizar tqdm
con pandas DataFrames y otras bibliotecas. El módulo tqdm.pandas
proporciona funciones específicas para integrar tqdm
con pandas.
¿Puedo personalizar el aspecto de la barra de progreso de Tqdm?
Sí, puedes personalizar el formato de la barra, el color, el número total de iteraciones y mucho más utilizando los parámetros de Tqdm.
La barra de progreso de Tqdm no se actualiza correctamente, ¿qué debo hacer?
Comprueba si hay problemas de almacenamiento en búfer, especialmente en los cuadernos Jupyter. Prueba a utilizar tqdm.notebook
o a vaciar explícitamente la salida. Asegúrate también de que se utilizan correctamente los parámetros de total
.
Tras construir una base sólida en economía, derecho y contabilidad en mis estudios duales en la administración financiera regional, entré en contacto por primera vez con la estadística en mis estudios de ciencias sociales y mi trabajo como tutora. Realizando análisis empíricos cuantitativos, descubrí una pasión que me llevó a continuar mi viaje adentrándome en el hermoso campo de la ciencia de datos y a aprender herramientas analíticas como R, SQL y Python. Actualmente, estoy mejorando mis habilidades prácticas en Deutsche Telekom, donde puedo recibir mucha experiencia práctica en la codificación de rutas de datos para importar, procesar y analizar datos utilizando Python.
Los mejores cursos de Python
Course
Python Toolbox
Course
Introduction to Testing in Python
tutorial
Introducción al trazado con Matplotlib en Python
Kevin Babitz
25 min
tutorial
Pandas Profiling (ydata-profiling) en Python: Guía para principiantes
Satyam Tripathi
9 min
tutorial
Tutorial de multiprocesamiento en Python
tutorial
Tutorial de visualización de datos con Python y Tableau
tutorial
Tutorial de Docstrings en Python
tutorial