R'den Excel'e yazarken java.lang.OutOfMemoryError hatasını işleme


84

xlsxPaket, okuma ve hatta orta büyük elektronik tablolar için, maalesef R. adlı Excel tabloları yazmak için kullanılabilir java.lang.OutOfMemoryErroroluşabilir. Özellikle,

.Jcall'da hata ("RJavaTools", "Ljava / lang / Object;", "invokeMethod", cl,:
java.lang.OutOfMemoryError: Java yığın alanı

.Jcall'da hata ("RJavaTools", "Ljava / lang / Object;", "newInstance", .jfindClass (class),:
java.lang.OutOfMemoryError: GC ek yük sınırı aşıldı

(Diğer ilgili istisnalar da mümkündür ancak daha nadirdir.)

Elektronik tabloları okurken bu hatayla ilgili benzer bir soru soruldu.

Büyük bir xlsx dosyasını R'ye mi aktarıyorsunuz?

Excel elektronik tablolarını CSV'ye göre veri depolama ortamı olarak kullanmanın ana avantajı, aynı dosyada birden çok sayfa saklayabilmenizdir, bu nedenle burada her çalışma sayfasına bir veri çerçevesi yazılacak veri çerçevelerinin bir listesini ele alıyoruz. Bu örnek veri kümesi, her biri 200.000 satıra kadar iki sütun içeren 40 veri çerçevesi içerir. Sorunlu olması yeterince büyük olacak şekilde tasarlanmıştır, ancak değiştirerek boyutunu değiştirebilir n_sheetsve 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))

Bunu dosyaya yazmanın doğal yöntemi, kullanarak bir çalışma kitabı oluşturmak createWorkbookve ardından her veri çerçevesi çağrısı createSheetve addDataFrame. Son olarak çalışma kitabı dosyaya yazılabilir saveWorkbook. Nereye düştüğünü görmeyi kolaylaştırmak için döngüye mesajlar ekledim.

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")  

Bunu 8GB RAM'e sahip bir makinede 64 bit olarak GC overhead limit exceededçalıştırdığınızda addDataFrame, ilk kez çalışırken hatayı atar .

Kullanarak Excel elektronik tablolarına büyük veri kümelerini nasıl yazabilirim xlsx?

Yanıtlar:


79

Bu bilinen bir sorundur: http://code.google.com/p/rexcel/issues/detail?id=33

Çözülmemiş olsa da, konu sayfası bir çözüm bağlantılar tarafından Gabor Grothendieck yığın boyutu ayarlayarak artırılması gerektiğini düşündüren java.parametersönce seçeneği rJavapaketi yüklenir. ( rJavabir bağımlılıktır xlsx.)

options(java.parameters = "-Xmx1000m")

Değer 1000, Java yığınına izin verilecek megabayt RAM sayısıdır; istediğiniz herhangi bir değerle değiştirilebilir. Bununla ilgili deneylerim, daha büyük değerlerin daha iyi olduğunu ve RAM hakkınızı mutlu bir şekilde kullanabileceğinizi gösteriyor. Örneğin, en iyi sonuçları şunları kullanarak aldım:

options(java.parameters = "-Xmx8000m")

8GB RAM ile makinede.

Döngünün her yinelemesinde bir atık toplama talep edilerek daha fazla iyileştirme elde edilebilir. @Gjabel tarafından belirtildiği gibi, R çöp toplama işlemi kullanılarak gerçekleştirilebilir gc(). Java System.gc()yöntemini çağıran bir Java çöp toplama işlevi tanımlayabiliriz :

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

Ardından döngü şu şekilde güncellenebilir:

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)
}

Bu kod düzeltmelerinin her ikisiyle de kod, i = 29bir hata vermeden öncesine kadar çalıştı .

Başarısızlıkla denediğim tekniklerden biri write.xlsx2, her yinelemede dosyalanacak içeriği yazmak için kullanmaktı . Bu, diğer koddan daha yavaştı ve 10. yinelemede düştü (ancak içeriğin en azından bir kısmı dosyaya yazıldı).

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'dan çok bağımlı olan xlsxpaket için paket değiştirilerek tüm bu sorun artık çözülebilir . openxlsxRcpp
Richie Cotton

4
readxlumut verici görünen bir başka yeni C / C ++ alternatifidir.
Richie Cotton

1
maalesef bunların her ikisinin de tarihleri ​​tespit etmek ve okumak için oldukça gereksiz olduğunu buldum - her ikisi de Excel tarih formatı olan düzeltilemez karmaşanın içinde: \
MichaelChirico

2
@RichieCotton, güzel bir alternatif. Ancak openxlsx, .xls veya .xlm dosyalarını okuyamaz! (2007 excel dosya biçimi).
Espanta

çağrı options(java.parameters = "-Xmx8000m")yükünden önce rJava, xlsxjars, xlsxçözülmüş 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 olarak, Java 1.7.0_79 (Oracle), rJava_0.9-7, xlsxjars_0.6.0, xlsx_0.5.7
İsim Dong

7

@ Richie-cotton cevabına dayanarak gc(), jgcişleve eklemenin CPU kullanımını düşük tuttuğunu gördüm .

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

Önceki fordöngüm hala orijinal jgcişlevle mücadele ediyordu , ancak ekstra komutla artık GC overhead limit exceededhata mesajıyla karşılaşmıyorum.


-1

Satır satır yazıyorsanız, döngü içinde gc () de kullanabilirsiniz. gc (), çöp toplama anlamına gelir. gc () herhangi bir bellek sorunu durumunda kullanılabilir.


-1

Yukarıdaki hatanın çözümü: Lütfen aşağıda belirtilen r kodunu kullanın:

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

Ve dosyayı tekrar içe aktarmayı deneyin ve benim için çalıştığı için herhangi bir hata almayacaksınız.


İki yorum: xlConnect'te aynı sorun var. Daha da önemlisi, birine farklı bir kitaplık kullanmasını söylemek, başvurulan kitapla ilgili soruna bir çözüm değildir. Buradaki amaç xlsx paketinin içinde kalmaktır. XLConnect'e ayrılmış başka konular da var.
Michael Tuchman

-1

Okumak yerine write.xlsx () ile ilgili sorunlar yaşıyordum .... ama sonra yanlışlıkla 32bit R çalıştırdığımı fark ettim. 64bit'e değiştirmek sorunu çözdü.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.