RからExcelに書き込むときのjava.lang.OutOfMemoryErrorの処理


84

この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スプレッドシートを使用する主な利点は、同じファイルに複数のシートを保存できることです。そこで、ここでは、データフレームのリストをワークシートごとに1つのデータフレームと見なします。このサンプルデータセットには40個のデータフレームが含まれ、各フレームには最大200k行の2つの列があります。問題があることが十分に大きいように設計されていますが、変更することによってサイズを変更することができます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")  

これを8GBのRAMを搭載したマシンで64ビットでGC overhead limit exceeded実行addDataFrameすると、初めて実行するときにエラーがスローされます。

を使用して大きなデータセットをExcelスプレッドシートに書き込むにはどうすればよいxlsxですか?

回答:


79

これは既知の問題です:http//code.google.com/p/rexcel/issues/detail?id = 33

未解決ですが、問題ページGabor Grothendieckによる解決策にリンクしてjava.parametersおり、rJavaパッケージをロードする前にオプションを設定してヒープサイズを増やす必要があることを示唆しています。(rJavaはの依存関係ですxlsx。)

options(java.parameters = "-Xmx1000m")

1000は、Javaヒープを許可するRAMのメガバイト数です。好きな値に置き換えることができます。これを使った私の実験では、値が大きいほど良いことが示唆されており、RAMのフルエンタイトルメントを問題なく使用できます。たとえば、次を使用して最良の結果が得られました。

options(java.parameters = "-Xmx8000m")

8GBのRAMを搭載したマシン。

ループの各反復でガベージコレクションを要求することにより、さらに改善することができます。@gjabelが指摘しているように、Rガベージコレクションはを使用して実行できますgc()。JavaSystem.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エラーをスローする前まで実行されました。

私が失敗したテクニックの1つは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
  )
}

38
この問題全体は、Javaではなく依存してxlsxいるopenxlsxパッケージとパッケージを交換することで回避できるようになりましたRcpp
リッチーコットン

4
readxl有望に見えるもう1つの新しいC / C ++の代替手段です。
リッチーコットン

1
残念ながら、どちらも日付の検出と読み取りにはかなりの問題があることがわかりました。どちらも、Excelの日付形式である
手に負えない混乱に陥ってい

2
@RichieCotton、いい選択肢。ただし、openxlsxは.xlsまたは.xlmファイルを読み取ることができません。(2007年のExcelファイル形式)。
エスパンタ2015

呼び出すoptions(java.parameters = "-Xmx8000m")ロードする前にrJavaxlsxjarsxlsx解決Error in .jcall("RJavaTools", "Ljava/lang/Object;", "invokeMethod", cl, : org.apache.poi.POIXMLException: java.lang.reflect.InvocationTargetException Calls: getNetwork ... <Anonymous> -> .jrcall -> .jcall -> .jcheck -> .Call Execution haltedRHEL 6.3 x86_64版では、Javaの1.7.0_79(オラクル)、rJava_0.9-7、xlsxjars_0.6.0、xlsx_0.5.7
ニック・ドン

7

@ richie-cottonの回答に基づいgc()て、jgc関数に追加するとCPU使用率が低く抑えられることがわかりました。

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

以前のforループはまだ元のjgc関数で苦労していましたが、追加のコマンドを使用すると、GC overhead limit exceededエラーメッセージが表示されなくなりました。


-1

行ごとに書き込む場合は、ループ内でgc()を使用することもできます。gc()はガベージコレクションを表します。gc()は、メモリの問題が発生した場合に使用できます。


-1

上記のエラーの解決策:下記のr-コードを使用してください:

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

そして、ファイルをもう一度インポートしてみてください。それが私のために機能するので、エラーは発生しません。


2つのコメント:xlConnectにも同じ問題があります。さらに重要なことに、別のライブラリを使用するように誰かに指示することは、参照されているライブラリの問題の解決策ではありません。ここでの目標は、xlsxパッケージ内にとどまることです。XLConnect専用の他のスレッドがあります。
MichaelTuchman20年

-1

読み取りではなくwrite.xlsx()で問題が発生していましたが、誤って32ビットRを実行していたことに気付きました。64ビットにスワップアウトすると問題が修正されました。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.