更新: これは v1.8.10 でかなり前に修正されています。NEWS より:
o on の遅さtransform()
がdata.table
修正されまし#2599
た。でも、使ってください:=
。
ドキュメンテーションと?transform.data.table
(SenorO の投稿からも) 慣用的な方法は (参照による割り当て) を使用することであり、これは信じられないほど高速であることは明らかですが、なぜが遅い:=
のかを知ることは依然として興味深いと思います。これまでに理解できたことから、常に遅いとは限りません。 transform
data.table
transform.data.table
私はここでそれに答えようとします。transform.data.table
関数の呼び出しではなく、それ自体の問題ではないようですdata.table()
。を見るとdata.table:::transform.data.table
、ラグは次の行に由来します。
ans <- do.call("data.table", c(list(`_data`), e[!matched]))
data.table
それでは、この行を大きな値で順番にベンチマークしてみましょう。
DT <- data.table(x=1:1e5, y=1:1e5, z=1:1e5)
system.time(do.call("data.table", c(list(DT), list(d=1))))
user system elapsed
0.003 0.003 0.026
ああ、これは非常に高速です!同じベンチマークを行いましょう。ただし、値が正しくありません。
DT <- data.table(x=sample(1e5), y=sample(1e5), z=sample(1e5))
system.time(do.call("data.table", c(list(DT), list(d=1))))
user system elapsed
7.986 0.016 8.099
# tested on 1.8.8 and 1.8.9
遅くなります。この違いの原因は何ですか?そのためには、関数をデバッグする必要がありdata.table()
ます。することで
DT <- data.table(x=as.numeric(1:1e5), y=as.numeric(1:1e5), z=as.numeric(1:1e5))
debugonce(data.table)
transform(DT, d=1)
「Enter」キーを連続して押すと、そのような速度低下の理由が次の行にあることがわかります。
exptxt = as.character(tt) # roughly about 7.2 seconds
それが問題になることは明らかですas.character
。なんで?これを行うには、次を比較します。
as.character(data.frame(x=1:10, y=1:10))
# [1] "1:10" "1:10"
as.character(data.frame(x=sample(10), y=sample(10)))
# [1] "c(9, 10, 4, 7, 6, 5, 1, 3, 8, 2)" "c(8, 5, 3, 7, 6, 10, 9, 1, 4, 2)"
より大きなデータでこれを繰り返してas.character
、サンプルdata.frame
が遅くなることを確認します。
さて、問題は、なぜそうでないのかということです
data.table(x = sample(1e5), y=sample(1e5))
時間がかかる?これは、data.table()
関数に与えられた入力が(で)置換subsitute()
されるためです。この場合、は次のようにtt
なります。
$x
sample(1e+05)
$y
sample(1e+05)
そしてas.character(tt)
、次のようになります。
# [1] "sample(1e+05)" "sample(1e+05)"
これは、次のことを行う場合を意味します。
DT <- data.table(x = c(1,3,4,1,4,1,3,1,2...), y = c(1,1,4,1,3,4,1,1,3...))
これにはかなりの時間がかかると思います(通常はそうではないため、問題はありません)。