[r] R에서 Excel로 쓸 때 java.lang.OutOfMemoryError 처리

xlsx패키지는 R에서 Excel 스프레드 시트를 읽고 쓰는 데 사용할 수 있습니다. 안타깝게도 중간 크기의 스프레드 시트에서도 java.lang.OutOfMemoryError발생할 수 있습니다. 특히,

.jcall ( “RJavaTools”, “Ljava / lang / Object;”, “invokeMethod”, cl, :
java.lang.OutOfMemoryError : Java 힙 공간에 오류가 있습니다.

.jcall ( “RJavaTools”, “Ljava / lang / Object;”, “newInstance”, .jfindClass (class), :
java.lang.OutOfMemoryError : GC 오버 헤드 제한 초과

(기타 관련 예외도 가능하지만 더 드뭅니다.)

스프레드 시트를 읽을 때이 오류와 관련하여 유사한 질문이 제기되었습니다.

큰 xlsx 파일을 R로 가져 오시겠습니까?

CSV보다 Excel 스프레드 시트를 데이터 저장 매체로 사용할 때의 주요 이점은 동일한 파일에 여러 시트를 저장할 수 있다는 것입니다. 따라서 여기서는 워크 시트 당 하나의 데이터 프레임을 작성하는 데이터 프레임 목록을 고려합니다. 이 예제 데이터 세트에는 40 개의 데이터 프레임이 포함되어 있으며 각 프레임에는 최대 200,000 개의 행이있는 두 개의 열이 있습니다. 문제가 될 수있는 충분히 큰 수 있도록 설계되어 있지만 변경하여 크기를 변경할 수 있습니다 n_sheetsn_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각각의 데이터 프레임을 통해 호출 후, 루프 createSheetaddDataFrame. 마지막으로 통합 문서는 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")

8GB RAM이있는 시스템에서 64 비트로 GC overhead limit exceeded실행 addDataFrame하면 처음 실행하는 동안 오류가 발생 합니다.

을 사용하여 대용량 데이터 세트를 Excel 스프레드 시트에 어떻게 작성 xlsx합니까?



답변

이것은 알려진 문제입니다.
http://code.google.com/p/rexcel/issues/detail?id=33

해결되지 않은 동안 문제 페이지 는 패키지가로드 되기 전에 옵션 을 설정하여 힙 크기를 늘려야한다고 제안하는 Gabor Grothendieck 의 솔루션연결됩니다 . ( 의 종속성입니다 .)java.parametersrJavarJavaxlsx

options(java.parameters = "-Xmx1000m")

1000은 Java 힙을 허용하는 RAM의 MB 수입니다. 원하는 값으로 바꿀 수 있습니다. 이것에 대한 나의 실험은 더 큰 값이 더 낫다는 것을 시사하며 전체 RAM 권한을 행복하게 사용할 수 있습니다. 예를 들어 다음을 사용하여 최상의 결과를 얻었습니다.

options(java.parameters = "-Xmx8000m")

8GB RAM이있는 컴퓨터에서.

루프를 반복 할 때마다 가비지 콜렉션을 요청하여 추가 개선을 얻을 수 있습니다. @gjabel에서 언급했듯이 R 가비지 수집은 gc(). Java System.gc()메소드 를 호출하는 Java 가비지 콜렉션 함수를 정의 할 수 있습니다 .

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 답변을 바탕으로 기능에 추가 하면 CPU 사용량이 낮다 gc()는 것을 알았습니다 jgc.

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

내 이전 for루프는 여전히 원래 jgc기능으로 어려움을 겪었 지만 추가 명령을 사용하면 더 이상 GC overhead limit exceeded오류 메시지가 표시 되지 않습니다 .


답변

행 단위로 쓰는 경우 루프 내에서 gc ()를 사용할 수도 있습니다. gc ()는 가비지 콜렉션을 의미합니다. gc ()는 메모리 문제의 모든 경우에 사용할 수 있습니다.


답변

위 오류에 대한 해결 방법 : 아래에 언급 된 r 코드를 사용하십시오.

detach(package:xlsx)
detach(package:XLConnect)
library(openxlsx)

그리고 파일을 다시 가져 오면 저에게 작동하므로 오류가 발생하지 않습니다.


답변

읽는 대신 write.xlsx ()에 문제가 있었지만 실수로 32 비트 R을 실행했음을 깨달았습니다. 64 비트로 바꾸면 문제가 해결되었습니다.


답변