我应该使用 mget()、.. 还是 with=FALSE 来选择 data.table 的列?

ben*_*dae 16 r data.table

多种方法可以通过使用保存所需列名(with=FALSE..mget、 ...)的变量来选择 data.table 的列。

是否就使用哪个(何时)达成共识?一个data.table比其他的多-y 吗?

我可以提出以下论点:

  1. with=FALSE并且..几乎同样快,而mget速度较慢
  2. ..无法“即时”选择连接的列名(编辑:当前的 CRAN 版本1.12.8绝对可以,我使用的是旧版本,不能,所以这个论点是有缺陷的)
  3. mget()接近于的有用语法get(),这似乎是在 j 的计算中使用变量名称的唯一方法

至 (1):

library(data.table)
library(microbenchmark)

a <- mtcars
setDT(a)

selected_cols <- names(a)[1:4]

microbenchmark(a[, mget(selected_cols)],
               a[, selected_cols, with = FALSE],
               a[, ..selected_cols],
               a[, .SD, .SDcols = selected_cols])

#Unit: microseconds
#                             expr     min       lq     mean   median       uq      max neval cld
#          a[, mget(selected_cols)] 468.483 495.6455 564.2953 504.0035 515.4980 4341.768   100   c
#  a[, selected_cols, with = FALSE] 106.254 118.9385 141.0916 124.6670 130.1820  966.151   100 a  
#              a[, ..selected_cols] 112.532 123.1285 221.6683 129.9050 136.6115 2137.900   100 a  
# a[, .SD, .SDcols = selected_cols] 277.536 287.6915 402.2265 293.1465 301.3990 5231.872   100  b 
Run Code Online (Sandbox Code Playgroud)

至 (2):

b <- data.table(x = rnorm(1e6), 
                y = rnorm(1e6, mean = 2, sd = 4), 
                z = sample(LETTERS, 1e6, replace = TRUE))

selected_col <- "y"

microbenchmark(b[, mget(c("x", selected_col))],
               b[, c("x", selected_col), with = FALSE],
               b[, c("x", ..selected_col)])
# Unit: milliseconds
#                                    expr      min       lq      mean   median       uq      max neval cld
#         b[, mget(c("x", selected_col))] 5.454126 7.160000 21.752385 7.771202 9.301334 147.2055   100   b
# b[, c("x", selected_col), with = FALSE] 2.520474 2.652773  7.764255 2.944302 4.430173 100.3247   100  a 
#             b[, c("x", ..selected_col)] 2.544475 2.724270 14.973681 4.038983 4.634615 218.6010   100  ab
Run Code Online (Sandbox Code Playgroud)

至 (3):

b[, sqrt(get(selected_col))][1:5]
# [1] NaN 1.3553462 0.7544402 1.5791845 1.1007728

b[, sqrt(..selected_col)]
# error

b[, sqrt(selected_col), with = FALSE]
# error

Run Code Online (Sandbox Code Playgroud)

编辑:添加.SDcols到 (1) 中的基准测试,b[, c("x", ..selected_col)]到 (2)。

jan*_*cki 4

我应该使用 mget()、.. 还是 with=FALSE 来选择 data.table 的列?

当然,只要不被弃用,您就应该使用您喜欢的任何内容。当所提供的解决方案之间的性能差异会产生真正的差异时,我没有看到任何实际的用例。有一些关于with=FALSE在其他接口上使用的论点,但这些更多地与这些接口的维护相关,而不是真正的用户使用。


在最近的 data.table 版本中,从 1.14.1 开始,有一个新功能可以使用 data.table 进行深度参数化 data.table 查询。这个新接口,我们称之为“ envarg”,可以用来解决您问题中的问题。是的,还有另一种方法可以解决您的问题。这个envarg 接口更加通用,所以在这样一个简单的用例中我仍然会使用with=FALSE. 下面我添加verbose=TRUE了这个新的接口用法,以便读者可以看到如何预处理查询以替换变量。

b = data.table(x = 1L, y = 2, z = "c")
selected_col = "y"

b[, c("x", selected_col), with=FALSE]
#       x     y
#   <int> <num>
#1:     1     2

b[, .cols, env=list(.cols=I(c("x",selected_col))), verbose=T]
#Argument 'j'  after substitute: c("x", "y")
#       x     y
#   <int> <num>
#1:     1     2

b[, .cols, env=list(.cols=as.list(c("x",selected_col))), verbose=T]
#Argument 'j'  after substitute: list(x, y)
#       x     y
#   <int> <num>
#1:     1     2
Run Code Online (Sandbox Code Playgroud)

env界面也将很好地支持(3)

b[, sqrt(.col), env=list(.col=selected_col), verbose=T]
#Argument 'j'  after substitute: sqrt(y)
#[1] 1.414214
Run Code Online (Sandbox Code Playgroud)