Barra de progreso en R

Añade barras de progreso en R a bucles for y a las funciones apply

Cuando se ejecutan estudios de simulación que tardan mucho en acabar, es muy útil añadir una barra de progreso para verificar el porcentaje completado de las iteraciones. En este tutorial aprenderás a agregar una barra de progreso en R mediante diferentes métodos, para verificar el progreso de los bucles for y de las funciones de la familia apply.

Insertar barra de progreso

La función txtProgressBar

Las funciones usadas de forma más habitual para crear barras de progreso son las funciones txtProgressBar y setTxtProgressBar de R base.

En el siguiente bloque de código mostramos cómo agregar una barra de progreso a un bucle for, describiendo brevemente los argumentos que puedes personalizar.

n_iter <- 50 # Número de iteraciones del bucle
# Inicializa la barra de progreso
pb <- txtProgressBar(min = 0,      # Valor mínimo de la barra de progreso
                     max = n_iter, # Valor máximo de la barra de progreso
                     style = 3,    # Estilo de la barra (también style = 1 y style = 2)
                     width = 50,   # Ancho de la barra. Por defecto: getOption("width")
                     char = "=")   # Carácter usado para crear la barra

for(i in 1:n_iter) {

    #-------------------
    # Aquí va tu código:
    #-------------------
  
    Sys.sleep(0.1) # Borra esta línea y añade tu código
  
    #-------------------
 
    # Actualiza la barra de progreso al estado actual
    setTxtProgressBar(pb, i)
}

close(pb) # Cerramos la conexión
|==================================================| 100%>

A modo ilustrativo, para que el bucle tarde unos segundos en finalizar y se vea el avance de la barra de progreso en el ejemplo anterior se utiliza la función Sys.sleep, que para la ejecución del código tantos segundos como se pasen como parámetro.

Tiempo transcurrido y restante estimado

Sin embargo, la función solo muestra el porcentaje actual de iteraciones que se han ejecutado.

De esta forma, con el objetivo de proporcionar mayor funcionalidad, hemos desarrollado una manera de mostrar el tiempo transcurrido y una estimación del tiempo restante estimado, basado en la media del tiempo que tomaron las iteraciones previas en ejecutarse. Ten en cuenta que para mostrar horas, minutos y segundos se utiliza la función seconds_to_perior del paquete lubridate.

# install.packages("lubridate")
library(lubridate)

n_iter <- 20

pb <- txtProgressBar(min = 0,
                     max = n_iter,
                     style = 3,
                     width = n_iter, # Necesario para evitar múltiples prints
                     char = "=") 

inicio <- numeric(n_iter)
fin <- numeric(n_iter)


for(i in 1:n_iter){
  
    inicio[i] <- Sys.time()
  
    #-------------------
    # Aquí va tu código:
    #-------------------
  
    Sys.sleep(0.1) # Borra esta línea y añade tu código
  
    #-------------------
    
    fin[i] <- Sys.time()

    setTxtProgressBar(pb, i)
    tiempo <- round(seconds_to_period(sum(fin - inicio)), 0)
  
    # Tiempo restante estimado basado en el tiempo
    # medio que tardaron en ejecutarse las iteraciones previas
    est <- n_iter * (mean(fin[fin != 0] - inicio[inicio != 0])) - tiempo
    restante <- round(seconds_to_period(est), 0)
  
    cat(paste(" // Tiempo ejecución:", tiempo,
              " // Tiempo restante estimado:", restante), "")
  
}

close(pb)
|====================| 100% // Tiempo ejecución: 2S  // Tiempo restante estimado: 0S >

Si los valores especificados en los argumentos max y width son menores que el número de iteraciones, la función cat imprimirá los valores múltiples veces.

El paquete progress

Como alternativa a las funciones anteriores puedes usar el paquete progress, que permite mayor flexibilidad en la configuración de la salida.

Existen varios argumentos que puedes personalizar, así que recuerda escribir ?progress para obtener detalles adicionales, pero el más relevante de ellos es el argumento format, que permite modificar el formato de la barra de progreso como se quiera, mediante diferentes tipos de configuraciones.

En el siguiente bloque de código se muestra un ejemplo completo, con un spinner, la barra, el porcentaje completado, el tiempo transcurrido y el tiempo restante estimado:

# install.packages("progress")
library(progress)

n_iter <- 100

pb <- progress_bar$new(format = "(:spin) [:bar] :percent [Tiempo transcurrido: :elapsedfull || Tiempo restante estimado: :eta]",
                       total = n_iter,
                       complete = "=",   # Caracteres de las iteraciones finalizadas
                       incomplete = "-", # Caracteres de las iteraciones no finalizadas
                       current = ">",    # Carácter actual
                       clear = FALSE,    # Si TRUE, borra la barra cuando termine
                       width = 100)      # Ancho de la barra de progreso

for(i in 1:n_iter) {
  
    # Actualiza el estado actual
    pb$tick()
  
    #-------------------
    # Aquí va tu código:
    #-------------------
  
    Sys.sleep(0.1) # Borra esta línea y añade tu código
  
    #-------------------
  
}
(|) [=========>---]  85% [Tiempo transcurrido: 00:00:08 || Tiempo restante estimado:  2s]

Barra de progreso de Windows con la función winProgressBar

Las barras de progreso descritas en las secciones anteriores estaban hechas con caracteres que se imprimían en la consola. Sin embargo, si lo prefieres, también es posible crear barras de progreso con una ventana estilo Windows con la funciones winProgressBar y setWinProgressBar.

El proceso para agregar la barra de progreso es análogo a los ejemplos anteriores, pero en este caso también puedes agregar un título y una descripción con los argumentos title y label, respectivamente. Ten en cuenta que si especificas una descripción o un título en la funciónsetWinProgressBar, sobreescribirá los argumentos correspondientes establecidos en la función winProgressBar.

n_iter <- 50 # Número de iteraciones

pb <- winProgressBar(title = "Barra de progreso de Windows", # Título de la ventana
                     label = "Porcentaje completado",        # Texto de la ventana
                     min = 0,      # Valor mínimo de la barra
                     max = n_iter, # Valor máximo de la barra
                     initial = 0,  # Valor inicial de la barra
                     width = 300L) # Ancho de la ventana

for(i in 1:n_iter) {

    #-------------------
    # Aquí va tu código:
    #-------------------
  
    Sys.sleep(0.1) # Borra esta línea y añade tu código
  
    #-------------------

    pctg <- paste(round(i/n_iter *100, 0), "% completado")
    setWinProgressBar(pb, i, label = pctg) # Al pasar pctg al argumento label se sobreescribirá
                                           # el texto del argumento label de la función winProgressBar
}

close(pb) # Cerramos la conexión

Barra de progreso de Windows en R

Barra de progreso Tk (Unix) con la función tkProgressBar

La función descrita en la subsección anterior solo funcionará para sistemas Windows. Sin embargo, las funciones tkProgressBar y setTkProgressBar del paquete tcltk te permitirán crear una barra de progreso Tk en plataformas Unix, como Linux:

# install.packages("tcltk")
library(tcltk)

n_iter <- 50 # Número de iteraciones

pb <- tkProgressBar(title = "Barra de progreso Tk",  # Título de la ventana
                    label = "Porcentaje completado", # Texto de la ventana
                    min = 0,      # Valor mínimo de la barra
                    max = n_iter, # Valor máximo de la barra
                    initial = 0,  # Valor inicial de la barra
                    width = 300)  # Ancho de la ventana

for(i in 1:n_iter) {

    #-------------------
    # Aquí va tu código:
    #-------------------
  
    Sys.sleep(0.1) # Borra esta línea y añade tu código
  
    #-------------------

    pctg <- paste(round(i/n_iter *100, 0), "% completado")
    setTkProgressBar(pb, i, label = pctg)
}

close(pb) # Cerramos la conexión

Barra de progreso Tk en R para dispositivos Unix como Linux

Barra de progreso con funciones apply: el paquete pbapply

En la sección anterior revisamos cómo añadir barras de progreso a bucles for, por lo que en esta sección discutiremos cómo usar el paquete pbapply, para añadir barras de progreso a las funciones de la familia apply.

El paquete proporciona las funciones pbapply, pblapply, pbsapply, pbtapply, pbmapply y pbreplicate. En el siguiente bloque de código mostramos un ejemplo usando la función pblapply, pero todas las funciones proporcionan la misma funcionalidad.

# install.packages("pbapply")
library(pbapply)

pblapply(1:3, function(i){
            Sys.sleep(1)  # Sustituye estas líneas
             i ^ 3        # por tu código
})
  |++++++++++++++++++++++++++++++++++++++++++++++++++| 100%  elapsed=03s 
[[1]]
[1] 1

[[2]]
[1] 8

[[3]]
[1] 27

Además, puedes personalizar el tipo de barra de progreso que se muestra con el argumento type de la función pboptions. Los posibles valores son "timer" (por defecto), que muestra una barra de progreso con el tiempo restante estimado y el transcurrido, "txt", que elimina los tiempos, "win", que establece una barra de progreso de Windows, "tk" para una barra estilo TK y "none", para no mostrar ninguna barra.

# Guardamos las opciones actuales
op <- pboptions()

# Establecemos un nuevo tipo de barra
pboptions(type = "win")
pbsapply(1:3, Sys.sleep) # Sustituye Sys.sleep por la función que quieras

# Volvemos a las opciones por defecto
pboptions(op)

Existen varios argumentos que puedes personalizar. Como ejemplo, puedes cambiar el carácter usado para crear la barra de progreso con el argumento char, pero escribe ?pboptions para obtener argumentos y detalles adicionales.

# Volvemos a las opciones por defecto,
# modificando el carácter de la barra
op <- pboptions(type = "timer", char = "=")

Paquete beepr: notificaciones de sonido cuando la ejecución finaliza

Por último, a pesar de que no proporciona una barra de progreso, el paquete beepr package permite reproducir una notificación de audio con la función beep, lo que puede ser muy útil cuando ejecutas un estudio de simulación que tarda mucho en finalizar y lo dejas de fondo. Por tanto, cuando la ejecución termine, un sonido te notificará. A continuación se muestra un ejemplo junto con una barra de progreso.

# install.packages("beepr")
library(beepr)

n_iter <- 100 

pb <- txtProgressBar(style = 3) 

for(i in 1:n_iter) {

    #-------------------
    # Aquí va tu código:
    #-------------------
  
    Sys.sleep(0.1) # Borra esta línea y añade tu código
  
    #-------------------

   setTxtProgressBar(pb, i)
}

beep(0) # Notificación aleatoria

close(pb) # Cerramos la conexión

Ten en cuenta que beep(0) ejecuta un sonido al azar entre los disponibles, pero también puedes especificar un número entre 1 y 10 o establecer "ping", "coin", "fanfare", "complete", "treasure", "ready", "shotgun", "mario", "wilhelm" o "facebook", respectivamente.