【问题标题】:Keyed lookup on data.table without 'with'在没有“with”的情况下对 data.table 进行键控查找
【发布时间】:2013-02-12 16:02:35
【问题描述】:

我有一个像这样的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

我想到了 [.data.tablewith 参数,但这仅适用于 j 参数,不适用于 i 参数。

i 参数有类似的东西吗?

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

【问题讨论】:

  • 1.8.2 的 NEWS 中有一个项目表明计划使用 ..() 语法,以在调用框架中进行评估。它似乎不在1.8.7

标签: r indexing data.table


【解决方案1】:

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

New DT[.(...)] 语法(采用 plyr 包的风格)与 DT[list(...)]、DT[J(...)] 和 DT[data.table(...)]。我们也计划添加 ..(),所以 .() 和 ..() 类似于文件系统的 ./ 和 ../; IE。, 。() 在父作用域中的 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))]

【讨论】:

  • 您必须使用不同的dt 或不同的x
  • 啊,是的,我的x &lt;- 2:3(我可以发誓我从这个问题中复制过来,(尽管它在 5 分钟的宽限期内)
  • 谢谢@mnel,看起来这使用了索引连接而merge() 没有,所以我将把我接受的答案换成你的。我之前尝试过I() 而不是eval() 并收到很多警告,我没想过尝试eval()
  • @mnel,我想知道parent.frame(3) 中的 3 来自哪里? (相对于 2)
  • @RicardoSaporta -- 反复试验(2 是我最初的想法)。这将取决于 i 参数在 [.data.table 中的解析方式,因此在未来版本中可能会发生变化。
【解决方案2】:

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

> X <- data.table(x=x)
> merge(dt, X)
   x y
1: 3 6
2: 4 7

【讨论】:

  • data.table(x)可以节省两次击键
  • 我刚刚意识到(从基准测试)这不使用dt 上的索引,所以很遗憾这不起作用。我以为我在某处读到 merge 应该尽可能使用索引?
【解决方案3】:

无需设置密钥,速度更快:

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

【讨论】:

    【解决方案4】:

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

    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(),我也可以添加。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-11-08
      • 2021-06-13
      • 2023-04-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多