Обработка java.ленг.OutOfMemoryError при записи в Excel из R


The xlsx пакет может использоваться для чтения и записи электронных таблиц Excel из R. К сожалению, даже для умеренно больших электронных таблиц,java.lang.OutOfMemoryError может произойти. В частности,

## Error in .jcall("RJavaTools", "Ljava/lang/Object;", "invokeMethod", cl,  : 
##   java.lang.OutOfMemoryError: Java heap space  

## Error in .jcall("RJavaTools", "Ljava/lang/Object;", "newInstance", .jfindClass(class),  : 
##   java.lang.OutOfMemoryError: GC overhead limit exceeded 

(другие связанные исключения также возможны, но реже.)

аналогичный вопрос был задан относительно этой ошибки при чтении электронных таблиц.

импорт большого xlsx файла в R?

основное преимущество использования электронных таблиц Excel в качестве данных носитель данных через CSV в том, что вы можете хранить несколько листов в одном файле, поэтому здесь мы рассмотрим список фреймов данных одного фрейма данных на листе. Этот пример набора данных содержит 40 фреймов данных, каждый с двумя столбцами до 200k строк. Он разработан, чтобы быть достаточно большим, чтобы быть проблематичным, но вы можете изменить размер, изменив n_sheets и n_rows.

library(xlsx)
set.seed(19790801)
n_sheets <- 40
the_data <- replicate(
  n_sheets,
  {
    n_rows <- sample(2e5, 1)
    data.frame(
      x = runif(n_rows),
      y = sample(letters, n_rows, replace = TRUE)
    )
  },
  simplify = FALSE
)
names(the_data) <- paste("Sheet", seq_len(n_sheets))

естественный способ записи этого в файл-создать книгу с помощью createWorkbook, затем цикл по каждому кадру данных вызова createSheet и addDataFrame. Наконец, книга может быть записана в файл с помощью saveWorkbook. Я добавил сообщения в цикл, чтобы было легче увидеть, где он падает.

wb <- createWorkbook()  
for(i in seq_along(the_data))
{
  message("Creating sheet", i)
  sheet <- createSheet(wb, sheetName = names(the_data)[i])
  message("Adding data frame", i)
  addDataFrame(the_data[[i]], sheet)
}
saveWorkbook(wb, "test.xlsx")  

запуск этого в 64-бит на машине с 8 ГБ оперативной памяти, он бросает GC overhead limit exceeded ошибка при запуске addDataFrame в первый раз.

как писать большие наборы данных в Excel электронные таблицы с помощью xlsx?

4 71

4 ответа:

это известная проблема: http://code.google.com/p/rexcel/issues/detail?id=33

пока не решена, страница проблема ссылки на решение by Габор Гротендика предполагая, что размер кучи должен быть увеличен путем установки до rJava пакет загружается. (rJava зависимость xlsx.)

options(java.parameters = "-Xmx1000m")

значение 1000 это количество мегабайт оперативной памяти, чтобы обеспечить Java кучи; он может заменить любое значение. Мои эксперименты с этим показывают, что большие значения лучше, и вы можете с радостью использовать свое полное право на ОЗУ. Например, я получил лучшие результаты, используя:

options(java.parameters = "-Xmx8000m")

на машине с 8 ГБ оперативной памяти.

дальнейшее улучшение может быть получено путем запроса сборки мусора в каждой итерации цикла. Как отмечает @gjabel, сбор мусора R может быть выполнен с помощью gc(). Мы можем определите функцию сборки мусора Java, которая вызывает Java System.gc() способ:

jgc <- function()
{
  .jcall("java/lang/System", method = "gc")
}    

затем цикл может быть обновлен в:

for(i in seq_along(the_data))
{
  gc()
  jgc()
  message("Creating sheet", i)
  sheet <- createSheet(wb, sheetName = names(the_data)[i])
  message("Adding data frame", i)
  addDataFrame(the_data[[i]], sheet)
}

С обоими этими исправлениями кода, код побежал до i = 29 перед тем, как выбросить ошибку.

один метод, который я безуспешно пытался использовать write.xlsx2 для записи содержимого в файл на каждой итерации. Это медленнее, чем другой код, и он упал на 10-й итерации (но, по крайней мере часть содержимого была записана в файл).

for(i in seq_along(the_data))
{
  message("Writing sheet", i)
  write.xlsx2(
    the_data[[i]], 
    "test.xlsx", 
    sheetName = names(the_data)[i], 
    append    = i > 1
  )
}

основываясь на ответе @ richie-cotton, я нашел добавление gc() до jgc функция поддерживала низкую загрузку ЦП.

jgc <- function()
{
  gc()
  .jcall("java/lang/System", method = "gc")
}    

мой петля все еще боролся с оригиналом jgc функция, но с дополнительной командой я больше не сталкиваюсь с GC overhead limit exceeded сообщение об ошибке.

решение для вышеуказанной ошибки: Пожалуйста, используйте указанный ниже r-код:

отсоединить(пакет: xlsx) отсоединить(пакет: XLConnect) библиотека(openxlsx)

и, попробуйте импортировать файл еще раз, и вы не получите никаких ошибок, как это работает для меня.

вы также можете использовать gc() внутри цикла, если вы пишете строку за строкой. gc () означает сбор мусора. ГК() может быть использован в любом случае проблемы с памятью.