1

小さなdata.tableがあり、transformそれを使用すると永遠に時間がかかります。再現可能な例を次に示します。

library(data.table)
#data.table 1.8.8
set.seed(1) 

dataraw <- data.table(sig1 = runif(80000, 0, 9999),
                      sig2 = runif(80000, 0, 9999),
                      sig3 = runif(80000, 0, 9999))

system.time(transform(dataraw, d = 1))
#  user      system     elapsed 
#16.345       0.016      16.359 

dataraw2 <- as.data.frame(dataraw)

system.time(transform(dataraw2, d = 1))
# user      system     elapsed 
#0.002       0.002       0.005 

transformdata.frame で使用した場合と比較して、data.table で非常に遅いのはなぜですか?

4

2 に答える 2

13

更新: これは v1.8.10 でかなり前に修正されています。NEWS より:

o on の遅さtransform()data.table修正されまし#2599た。でも、使ってください:=


ドキュメンテーションと?transform.data.table(SenorO の投稿からも) 慣用的な方法は (参照による割り当て) を使用することであり、これは信じられないほど高速であることは明らかですが、なぜが遅い:=のかを知ることは依然として興味深いと思います。これまでに理解できたことから、常に遅いとは限りません。 transformdata.tabletransform.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...))

これにはかなりの時間がかかると思います(通常はそうではないため、問題はありません)。

于 2013-08-14T08:20:53.320 に答える
11

から?transform.data.table:

transform by group is particularly slow. Please use := by group instead.

within, transform and other similar functions in data.table are not just provided 
for users who expect them to work, but for non-data.table-aware packages to 
retain keys, for example. Hopefully the (much) faster and more convenient 
data.table syntax will be used in time. 

@Roland が示唆するように、コードのコンポーネントを分解して、実際に時間/リソースを消費しているものを見つける必要があります。この場合、そうではありませlogtransform:=data.tables、transformdata.frames、リストなどに使用します。

犯人はそうではありませんlog

> dt <- data.table(A=1:1000000)
> system.time(transform(as.data.frame(dt), B=A * 1))
   user  system elapsed 
   0.00    0.02    0.01 
> system.time(transform(dt, B=A * 1))
   user  system elapsed 
  14.61    0.00   14.61 
于 2013-08-13T19:11:20.323 に答える