понедельник, 3 июня 2013 г.

Progress bar в R

Блог переехал. Актуальная версия поста находится по адресу: http://aakinshin.net/ru/blog/r/progress-bar/.


Давайте поговорим о долгих расчётах, ведь они не так редко встречаются в мире вычислений. Когда вы запускаете скрипт, который будет заведомо долго работать, то приятно смотреть на состояние прогресса. Эта информация поможет прикинуть время до конца вычислений («осталось ещё 30%, я успею выпить чашку кофе») или просигнализировать о бесконечном цикле («1438% выполнено, что-то пошло не так...»). Давайте научим наш скрипт сообщать пользователю о проценте выполненных работ. Пусть у нас есть очень полезная функция, которая делает что-то очень важное некоторое время:
foo <- function() {
  Sys.sleep(0.1)
}
И эта функция запускается несколько раз:
for (i in 1:10) {
  foo()
}
Казалось бы, самое простое решение — выводить на экран количество выполненных операцией:
for (i in 1:10) {
  foo()
  print(i)
}
Но такой фокус не всегда будет работать. Дело в том, что R любит буфферезировать вывод на консоль, т.е. не обязательно мы увидим вывод команды сразу после её выполнения. К счастью, есть способ, победить эту проблему — нам поможет строчка для обновления консоли: flush.console().
for (i in 1:10) {
  foo()
  print(i)
  flush.console()
}
Решение работает, но оно не такое уж и красивое. Давайте сделаем настоящий progress bar. Для начала простенький, текстовый. Сделать это весьма просто:
pb <- txtProgressBar(min = 0, max = 10, style = 3) # Создаём progress bar
for(i in 1:10){
   foo()
   setTxtProgressBar(pb, i) # Обновляем progress bar
}
close(pb) # Закрываем progress bar
Но можно пойти ещё дальше по пути к созданию прекраснейшего progress bar-а. А поможет нам в этом пакет tcltk:
pb <- tkProgressBar(title = "progress bar", min = 0,
                    max = 10, width = 300) # Создаём progress bar
 
for(i in 1:10){
   foo()
   setTkProgressBar(pb, i, label=paste(
                    round(i/10 * 100, 0), "% done")) # Обновляем progress bar
}
close(pb) # Закрываем progress bar
А для пользователей Windows можно предложить ещё один способ:
pb <- winProgressBar(title = "progress bar", min = 0,
                     max = 10, width = 300)  # Создаём progress bar
for(i in 1:10){
   foo()
   setWinProgressBar(pb, i, title=paste( 
                     round(i/10 * 100, 0), "% done"))  # Обновляем progress bar
}
close(pb)  # Закрываем progress bar

Ну вот и всё, теперь вы умеете создавать разнообразные progress bar-ы и делать процесс выполнения R-скрипта более информативным.
Навеяно постом: R: Monitoring the function progress with a progress bar.