質問

複数のインデックスを備えた非常に大きなレコードセットを取得し、インデックスのサブセットによって決定されたグループの集計統計を計算し、テーブル内のすべての行に挿入しようとしています。ここでの問題は、これらが非常に大きなテーブルであることです - それぞれ10mを超える列。

データを再現するためのコードは以下にあります。

基本的な考え方は、IX1、IX2、IX3、...、IXKなどのインデックスのセットがあるということです。一般的に、私はそれらのうちの数だけを選択しています、たとえばix1とix2。次に、IX1とIX2の値を一致させるすべての行の集約を計算します(表示されるすべての組み合わせ) val. 。シンプルに保つために、合計に集中します。

次の方法を試しました

  1. スパースマトリックスを介して:値を座標リストに変換します。IE(ix1、ix2、val)を作成し、Sparsematrixを作成します。速度:良いことですが、それは必要以上のことをしており、合計よりも高次元(IX1、IX2、IX3)またはより一般的な関数に一般化することはありません。

  2. の使用 lapplysplit: :すべて(ix1、ix2、...)n-tuppleに一意の新しいインデックスを作成することにより、splitを使用して適用できます。ここで悪いことは、一意のインデックスがによって変換されることです split 要因になり、この変換はそれほど時間がかかります。試す system({zz <- as.factor(1:10^7)}).

  3. 私は今やっています data.table, 、次のようなコマンドを介して sumDT <- DT[,sum(val),by = c("ix1","ix2")]. 。しかし、私はまだマージできる方法がわかりません sumDTDT, 、ようなものを介して DT2 <- merge(DT, sumDT, by = c("ix1","ix2"))

このdata.table結合のために、このdata.table結合にはより速い方法がありますか merge 私が説明した操作?

私も試しました bigsplit から bigtabulate パッケージ、およびその他の方法。要因に変換するものはほとんどありません - 私が知る限り、その変換プロセスは非常に遅いです。


データを生成するコード。当然のことながら、小さいものを試してみる方が良いです N 何かが機能することを確認するために、すべての方法が非常にうまくスケーリングするわけではありません N >> 1000.

N   <-  10^7
set.seed(2011)
ix1 <-  1 + floor(rexp(N, 0.01))
ix2 <-  1 + floor(rexp(N, 0.01))
ix3 <-  1 + floor(rexp(N, 0.01))
val <-  runif(N)

DF  <-  data.frame(ix1 = ix1, ix2 = ix2, ix3 = ix3, val = val)
DF  <- DF[order(DF[,1],DF[,2],DF[,3]),]
DT  <- as.data.table(DF)
役に立ちましたか?

解決

まあ、あなたはあなたのマージをすることはあなたほど長くはないことに気付くかもしれません keySが適切に設定されています。

もう一度問題をセットアップしましょう:

N   <-  10^6      ## not 10^7 because RAM is tight right now
set.seed(2011)
ix1 <-  1 + floor(rexp(N, 0.01))
ix2 <-  1 + floor(rexp(N, 0.01))
ix3 <-  1 + floor(rexp(N, 0.01))
val <-  runif(N)
DT <- data.table(ix1=ix1, ix2=ix2, ix3=ix3, val=val, key=c("ix1", "ix2"))

これで、要約統計を計算できます

info <- DT[, list(summary=sum(val)), by=key(DT)]

列を「data.table way」、またはとマージするか、 merge

m1 <- DT[info]            ## the data.table way
m2 <- merge(DT, info)     ## if you're just used to merge
identical(m1, m2)
[1] TRUE

これらのマージの方法のいずれかが遅すぎる場合、あなたはトリッキーな方法を試すことができます構築することができます info 記憶を犠牲にして:

info2 <- DT[, list(summary=rep(sum(val), length(val))), by=key(DT)]
m3 <- transform(DT, summary=info2$summary)
identical(m1, m3)
[1] TRUE

さて、タイミングを見てみましょう:

#######################################################################
## Using data.table[ ... ] or merge
system.time(info <- DT[, list(summary=sum(val)), by=key(DT)])
   user  system elapsed 
  0.203   0.024   0.232

system.time(DT[info])
   user  system elapsed 
  0.217   0.078   0.296

system.time(merge(DT, info))
   user  system elapsed 
  0.981   0.202   1.185

########################################################################
## Now the two parts of the last version done separately:
system.time(info2 <- DT[, list(summary=rep(sum(val), length(val))), by=key(DT)])
   user  system elapsed 
  0.574   0.040   0.616 

system.time(transform(DT, summary=info2$summary))
   user  system elapsed 
  0.173   0.093   0.267

または、中間体をスキップすることもできます info テーブルビルディング以下があなたの好みに対してあまりにも不可解でないと思われる場合:

system.time(m5 <- DT[ DT[, list(summary=sum(val)), by=key(DT)] ])
   user  system elapsed 
  0.424   0.101   0.525 

identical(m5, m1)
# [1] TRUE
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top