Как создать индикатор выполнения для загрузки данных в R?
Возможно ли создать индикатор выполнения для данных, загруженных в R, используя load()?
Для проекта анализа данных большие массивы загружаются в R из файлов .RData, для загрузки которых требуется несколько минут. Я хотел бы иметь индикатор выполнения, чтобы контролировать, насколько дольше он будет загружен. R уже имеет приятный индикатор выполнения, но load() не имеет крючков для контроля того, сколько данных было прочитано. Если я не могу использовать нагрузку напрямую, есть ли косвенный способ создать такой индикатор выполнения? Возможно, загрузите файл .RData в патроны и соедините их для R. Есть ли у кого-нибудь какие-либо мысли или предложения по этому поводу?
Ответы
Ответ 1
Я придумал следующее решение, которое будет работать для файлов размером менее 2 ^ 32 - 1 байт.
Объект R должен быть сериализован и сохранен в файле, как это сделано с помощью следующего кода.
saveObj <- function(object, file.name){
outfile <- file(file.name, "wb")
serialize(object, outfile)
close(outfile)
}
Затем мы читаем двоичные данные в кусках, отслеживая, насколько много читается и обновляет индикатор выполнения соответственно.
loadObj <- function(file.name){
library(foreach)
filesize <- file.info(file.name)$size
chunksize <- ceiling(filesize / 100)
pb <- txtProgressBar(min = 0, max = 100, style=3)
infile <- file(file.name, "rb")
data <- foreach(it = icount(100), .combine = c) %do% {
setTxtProgressBar(pb, it)
readBin(infile, "raw", chunksize)
}
close(infile)
close(pb)
return(unserialize(data))
}
Код можно запустить следующим образом:
> a <- 1:100000000
> saveObj(a, "temp.RData")
> b <- loadObj("temp.RData")
|======================================================================| 100%
> all.equal(b, a)
[1] TRUE
Если мы сопоставим метод индикатора выполнения с прочтением файла в одном блоке, мы видим, что индикатор уровня выполнения немного медленнее, но этого недостаточно, чтобы беспокоиться.
> system.time(unserialize(readBin(infile, "raw", file.info("temp.RData")$size)))
user system elapsed
2.710 0.340 3.062
> system.time(b <- loadObj("temp.RData"))
|======================================================================| 100%
user system elapsed
3.750 0.400 4.154
Таким образом, хотя вышеописанный метод работает, я считаю, что он абсолютно бесполезен из-за ограничений размера файла. Полосы прогресса полезны только для больших файлов, которые занимают много времени.
Было бы здорово, если бы кто-то мог придумать что-то лучшее, чем это решение!
Ответ 2
Могу ли я вместо этого предложить ускорить загрузку (и сохранить) раз, чтобы индикатор выполнения не нужен? Если вы читаете одну матрицу "быстро", тогда вы можете сообщить о прогрессе между каждой прочитанной матрицей (если ее много).
Здесь некоторые измерения. Просто устанавливая compress = FALSE, скорость загрузки удваивается. Но, написав простой матричный сериализатор, скорость загрузки почти в 20 раз быстрее.
x <- matrix(runif(1e7), 1e5) # Matrix with 100k rows and 100 columns
system.time( save('x', file='c:/foo.bin') ) # 13.26 seconds
system.time( load(file='c:/foo.bin') ) # 2.03 seconds
system.time( save('x', file='c:/foo.bin', compress=FALSE) ) # 0.86 seconds
system.time( load(file='c:/foo.bin') ) # 0.92 seconds
system.time( saveMatrix(x, 'c:/foo.bin') ) # 0.70 seconds
system.time( y <- loadMatrix('c:/foo.bin') ) # 0.11 seconds !!!
identical(x,y)
Где saveMatrix/loadMatrix определяются следующим образом. В настоящее время они не обрабатывают dimnames и другие атрибуты, но это может быть легко добавлено.
saveMatrix <- function(m, fileName) {
con <- file(fileName, 'wb')
on.exit(close(con))
writeBin(dim(m), con)
writeBin(typeof(m), con)
writeBin(c(m), con)
}
loadMatrix <- function(fileName) {
con <- file(fileName, 'rb')
on.exit(close(con))
d <- readBin(con, 'integer', 2)
type <- readBin(con, 'character', 1)
structure(readBin(con, type, prod(d)), dim=d)
}