7

我有一个data.table这样的结构(除了我的真的很大):

dt <- data.table(x=1:5, y=3:7, key='x')

我想通过另一个变量来查找该结构中的行,该变量的名称为x(注意 - 与键的名称相同dt):

x <- 3:4
dt2 <- dt[ J(x) ]

这不起作用,因为查找首先看到列名,并且局部变量被遮挡:

dt2
#    x y
# 1: 1 3
# 2: 2 4
# 3: 3 5
# 4: 4 6
# 5: 5 7

我考虑了 的with论点[.data.table,但这仅适用于j论点,而不适用于i论点。

i这个论点有类似的东西吗?

如果没有,当我使用局部变量并且我不知道 中的列名的完整列表时,这样的事情会很方便dt,以避免冲突。

4

4 回答 4

13

1.8.2 的 NEWS 中有一项建议..()将在某个时候添加语法,从而允许这样做

新的 DT[.(...)] 语法(采用 plyr 包的样式)与 DT[list(...)]、DT[J(...)] 和 DT[data.table(.. .)]。我们还计划添加 ..(),以便 .() 和 ..() 类似于文件系统的 ./ 和 ../;即, .() 在父范围内的 DT 和 ..() 框架内进行评估。

同时,您可以get从适当的环境中

dt[J(get('x', envir = parent.frame(3)))]
##    x y
## 1: 3 5
## 2: 4 6

或者你可以eval打电话给list(x)J(x)

dt[eval(list(x))]
dt[eval(J(x))]
dt[eval(.(x))]
于 2013-02-27T00:37:42.340 回答
2

新答案,现在我想我明白了要求的内容:

> X <- data.table(x=x)
> merge(dt, X)
   x y
1: 3 6
2: 4 7
于 2013-02-27T00:57:42.577 回答
2

不需要设置密钥,而且速度更快:

dt[eval(dt[, x %in% ..x])]

   x y
1: 3 5
2: 4 6

使用之前发布的答案进行基准测试

microbenchmark(dt[eval(dt[, x %in% ..x])],
               dt[J(get('x', parent.frame(3)))],
               dt[eval(list(x))],
               dt[eval(J(x))],
               dt[eval(.(x))],
               merge(dt, data.table(x)),
               times = 100L)

Unit: microseconds
                                  expr    min      lq     mean  median      uq    max neval
      dt[eval(dt[, x %in% ..x])]  486.1  500.60  518.529  503.70  512.65 1238.0   100
dt[J(get("x", parent.frame(3)))]  837.3  853.25  891.424  860.00  868.30 1675.3   100
               dt[eval(list(x))]  831.8  842.70  929.521  851.95  859.85 3878.3   100
                  dt[eval(J(x))]  833.8  845.50  948.535  856.00  870.00 4599.2   100
                  dt[eval(.(x))]  828.6  846.40  871.054  851.75  859.35 1985.6   100
        merge(dt, data.table(x)) 1766.0 1804.70 1907.617 1819.95 1870.95 3123.1   100
于 2019-10-12T20:13:32.453 回答
0

根据要求添加一些基准测试结果。

dt是一个 53080731 x 5 的data.table对象,由一个具有大约 100 个唯一值的数字列作为键,分布相当均匀。 x是包含其中 5 个值的向量。

library(microbenchmark)
> mb <- microbenchmark(
+     dt[eval(J(x))],
+     merge(dt, data.table(x)),
+     times=10
+ )
> mb
Unit: milliseconds
                     expr      min       lq    median       uq      max neval
           dt[eval(J(x))]  127.324  127.549  133.5305  154.410  159.433    10
 merge(dt, data.table(x)) 5028.349 5083.792 5129.6590 5170.451 5250.255    10

@Tyler,如果您可以帮助我了解如何使用qdap::lookup()多列来处理这种情况,我也可以添加它。

于 2013-02-27T23:11:08.203 回答