17

私の仕事では、いくつかのテーブル (顧客の詳細、取引記録など) を使用していました。それらのいくつかは非常に大きい(数百万行)ので、最近data.tableパッケージに切り替えました(マシューに感謝します)。ただし、それらの一部は非常に小さく (数百行と 4/5 列)、数回呼び出されます。そのため、 ですでに明確に説明されているように、値を set() するのではなく、データを取得する際[.data.tableのオーバーヘッドについて考え始めました。ここでは、テーブルのサイズに関係なく、1 つの項目が約 2 マイクロ秒 (CPU に依存) で設定されます。?set

ただし、正確な行と列を知ってsetいるものから値を取得するのと同等のものは存在しないようです。data.table一種のループ可能な [.data.table.

library(data.table)
library(microbenchmark)

m = matrix(1,nrow=100000,ncol=100)
DF = as.data.frame(m)
DT = as.data.table(m)  # same data used in ?set

> microbenchmark(DF[3450,1] , DT[3450, V1], times=1000) # much more overhead in DT

Unit: microseconds
expr     min      lq   median      uq      max neval
DF[3450, 1]  32.745  36.166  40.5645  43.497  193.533  1000
DT[3450, V1] 788.791 803.453 813.2270 832.287 5826.982  1000

> microbenchmark(DF$V1[3450], DT[3450, 1, with=F], times=1000)  # using atomic vector and
                                                                # removing part of DT overhead
Unit: microseconds                                              
expr     min      lq  median      uq      max neval
DF$V1[3450]   2.933   3.910   5.865   6.354   36.166  1000
DT[3450, 1, with = F] 297.629 303.494 305.938 309.359 1878.632  1000

> microbenchmark(DF$V1[3450], DT$V1[3450], times=1000) # using only atomic vectors
Unit: microseconds
        expr   min    lq median    uq    max neval
 DF$V1[3450] 2.933 2.933  3.421 3.422 40.565  1000    # DF seems still a bit faster (23%)
 DT$V1[3450] 3.910 3.911  4.399 4.399 16.128  1000

最後の方法は、1 つの要素を複数回すばやく取得するのに最適な方法です。ただし、setさらに高速です

> microbenchmark(set(DT,1L,1L,5L), times=1000)
Unit: microseconds
                expr   min    lq median    uq    max neval
 set(DT, 1L, 1L, 5L) 1.955 1.956  2.444 2.444 24.926  1000

問題は、2.444 マイクロ秒の値を取得できる場合、それより短い (または少なくとも同様の) 時間で値を取得setできるはずがないということです。ありがとう。

編集:提案されたようにさらに2つのオプションを追加します:

> microbenchmark(`[.data.frame`(DT,3450,1), DT[["V1"]][3450], times=1000)
Unit: microseconds
                        expr    min     lq median     uq      max neval
 `[.data.frame`(DT, 3450, 1) 46.428 47.895 48.383 48.872 2165.509  1000
            DT[["V1"]][3450] 20.038 21.504 23.459 24.437  116.316  1000

残念ながら、以前の試みよりも高速ではありません。

4

1 に答える 1

7

@hadley のおかげで解決策が見つかりました!

> microbenchmark(DT$V1[3450], set(DT,1L,1L,5L), .subset2(DT, "V1")[3450], times=1000, unit="us")
Unit: microseconds
                     expr   min    lq median    uq    max neval
              DT$V1[3450] 2.566 3.208  3.208 3.528 27.582  1000
      set(DT, 1L, 1L, 5L) 1.604 1.925  1.925 2.246 15.074  1000
 .subset2(DT, "V1")[3450] 0.000 0.321  0.322 0.642  8.339  1000
于 2013-06-09T14:36:06.600 に答える