より多くの RAM を搭載したマシンで作業する以外に、 で大きなリストを操作するにはどうすればよいR
ですか。
私が使用しているタイプのリストを生成するためのコードを次に示します
n = 50; i = 100
WORD <- vector(mode = "integer", length = n)
for (i in 1:n){
WORD[i] <- paste(sample(c(rep(0:9,each=5),LETTERS,letters),5,replace=TRUE),collapse='')
}
dat <- data.frame(WORD = WORD,
COUNTS = sample(1:50, n, replace = TRUE))
dat_list <- lapply(1:i, function(i) dat)
私の実際の使用例では、ここでの簡単な例とは異なり、リスト内の各データ フレームは一意です。n=4000、i=100,000を目指しています
これは、このデータフレームのリストでやりたいことの一例です。
FUNC <- function(x) {rep(x$WORD, times = x$COUNTS)}
la <- lapply(dat_list, FUNC)
私の実際の使用例では、これは数時間実行され、RAM とほとんどのスワップがいっぱいになり、その後 RStudio がフリーズして爆弾を含むメッセージが表示されます (R セッションでエラーが発生したため、RStudio は強制的に終了されました)。
これはbigmemory
行列に限定されており、ff
リストを処理していないようです。他のオプションは何ですか?sqldf
ここで、または関連するメモリ不足の方法が可能な場合、どうすれば始められますか? ドキュメントから十分な情報を得ることができず、進歩を遂げることができず、ポインタがあれば感謝しています。「RAM を追加購入する」という指示は無視されることに注意してください。これは、平均的なデスクトップ コンピューター (学部生のコンピューター ラボ) に適していると期待しているパッケージ用です。
更新SimonO101 と Ari からの有益なコメントをフォローアップして、dataframe と data.tables、loops と lapply、gc の有無を比較したベンチマークをいくつか示します。
# self-contained speed test of untable
n = 50; i = 100
WORD <- vector(mode = "integer", length = n)
for (i in 1:n){
WORD[i] <- paste(sample(c(rep(0:9,each=5),LETTERS,letters),5,replace=TRUE),collapse='')
}
# as data table
library(data.table)
dat_dt <- data.table(WORD = WORD, COUNTS = sample(1:50, n, replace = TRUE))
dat_list_dt <- lapply(1:i, function(i) dat_dt)
# as data frame
dat_df <- data.frame(WORD = WORD, COUNTS = sample(1:50, n, replace = TRUE))
dat_list_df <- lapply(1:i, function(i) dat_df)
# increase object size
y <- 10
dt <- c(rep(dat_list_dt, y))
df <- c(rep(dat_list_df, y))
# untable
untable <- function(x) rep(x$WORD, times = x$COUNTS)
# preallocate objects for loop to fill
df1 <- vector("list", length = length(df))
dt1 <- vector("list", length = length(dt))
df3 <- vector("list", length = length(df))
dt3 <- vector("list", length = length(dt))
# functions for lapply
df_untable_gc <- function(x) { untable(df[[x]]); if (x%%10) invisible(gc()) }
dt_untable_gc <- function(x) { untable(dt[[x]]); if (x%%10) invisible(gc()) }
# speedtests
library(microbenchmark)
microbenchmark(
for(i in 1:length(df)) { df1[[i]] <- untable(df[[i]]); if (i%%10) invisible(gc()) },
for(i in 1:length(dt)) { dt1[[i]] <- untable(dt[[i]]); if (i%%10) invisible(gc()) },
df2 <- lapply(1:length(df), function(i) df_untable_gc(i)),
dt2 <- lapply(1:length(dt), function(i) dt_untable_gc(i)),
for(i in 1:length(df)) { df3[[i]] <- untable(df[[i]])},
for(i in 1:length(dt)) { dt3[[i]] <- untable(dt[[i]])},
df4 <- lapply(1:length(df), function(i) untable(df[[i]]) ),
dt4 <- lapply(1:length(dt), function(i) untable(dt[[i]]) ),
times = 10)
そして、これが結果です。明示的なガベージ コレクションを使用しない場合、data.table はループよりもはるかに高速で、lapply はわずかに高速です。明示的なガベージ コレクションを使用すると (SimonO101 が示唆していると思われるように)、それらはすべてほぼ同じ速度であり、はるかに遅くなります! usinggc
は少し議論の余地があり、この場合はおそらく役に立たないことはわかっていますが、実際のユースケースで試してみて、違いがあるかどうかを確認します. もちろん、これらの関数のメモリ使用に関するデータはありません。これが私の主な関心事です。タイミング機能に相当するメモリベンチマーク用の機能がないようです(とにかくWindows用)。
Unit: milliseconds
expr
for (i in 1:length(df)) { df1[[i]] <- untable(df[[i]]) if (i%%10) invisible(gc()) }
for (i in 1:length(dt)) { dt1[[i]] <- untable(dt[[i]]) if (i%%10) invisible(gc()) }
df2 <- lapply(1:length(df), function(i) df_untable_gc(i))
dt2 <- lapply(1:length(dt), function(i) dt_untable_gc(i))
for (i in 1:length(df)) { df3[[i]] <- untable(df[[i]]) }
for (i in 1:length(dt)) { dt3[[i]] <- untable(dt[[i]]) }
df4 <- lapply(1:length(df), function(i) untable(df[[i]]))
dt4 <- lapply(1:length(dt), function(i) untable(dt[[i]]))
min lq median uq max neval
37436.433962 37955.714144 38663.120340 39142.350799 39651.88118 10
37354.456809 38493.268121 38636.424561 38914.726388 39111.20439 10
36959.630896 37924.878498 38314.428435 38636.894810 39537.31465 10
36917.765453 37735.186358 38106.134494 38563.217919 38751.71627 10
28.200943 29.221901 30.205502 31.616041 34.32218 10
10.230519 10.418947 10.665668 12.194847 14.58611 10
26.058039 27.103217 27.560739 28.189448 30.62751 10
8.835168 8.904956 9.214692 9.485018 12.93788 10