【问题标题】:How do I do a negative / nomatch / inverse search in data.table?如何在 data.table 中进行否定/不匹配/反向搜索?
【发布时间】:2012-09-01 09:28:51
【问题描述】:

如果我想使用二进制搜索选择 data.table 中不包含键变量中特定值的所有行,会发生什么情况?顺便说一句,我想做的正确术语是什么?是“不加入”吗?是“负选择”吗?

DT = data.table(x=rep(c("a","b","c"),each=3), y=c(1,3,6), v=1:9)
setkey(DT,x)

让我们对 x=="a" 但使用二分搜索的所有行进行肯定选择

DT["a"]

这很漂亮,但我想要相反的。我想要所有不是“a”的行,换句话说,x!="a"

DT[x!="a"]

那是矢量扫描。上述行有效,但使用矢量扫描。我想使用二进制。我期待以下工作,但唉......

DT[!"a"]
DT[-"a"]

以上两个都不起作用,尝试使用 nomatch 让我无处可去。

【问题讨论】:

  • 你试过DT[x!="a"]吗?还是你问有没有更简单的方法不指定key?
  • @GavinSimpson 我确实尝试过DT[x!="a"],它确实有效。但是,该方法使用矢量扫描,对于大数据集将缓慢扩展。我相信矢量扫描是我们在 data.table 语法中试图摆脱的。
  • 好的,Q 对我来说并不是 100% 清楚。由于不是大 data.table 用户,无法进一步提供帮助。不过这里有几个。
  • 仅供参考,此操作的通用名称是反连接

标签: r select data.table


【解决方案1】:

成语是这样的:

DT[-DT["a", which=TRUE]]

   x y v
1: b 1 4
2: b 3 5
3: b 6 6
4: c 1 7
5: c 3 8
6: c 6 9

灵感来自:


更新。 v1.8.3 中的新功能是非连接语法。 Farrel 的第一个期望(! 而不是-)已经实现:

DT[-DT["a",which=TRUE,nomatch=0],...]   # old idiom
DT[!"a",...]                            # same result, now preferred.

有关更多详细信息和示例,请参阅NEWS 项目。

【讨论】:

  • 我注意到生成的 data.table 丢失了其 key= 信息。如果不希望这样做,请尝试以下轻微修改:res <- setkeyv(DT[-DT["a", which=TRUE]], key(DT))
  • @JoshO'Brien 哎呀,很好发现。刚刚提交了FR#2266 - All negative numeric i should retain key
  • @JoshO'Brien, Andrie DT[!"a"] 现在在 v1.8.3 中。如果您有时间检查它并在预见到任何问题时大喊大叫,非常感谢?谢谢。刚刚添加了对 Andrie 答案的更新。
  • @MatthewDowle——太棒了。我会尽快看看。干杯。
【解决方案2】:

Andrie 的回答很棒,我可能会使用它。不过有趣的是,以下构造似乎(只是稍微)快了一点,尤其是随着 data.tables 大小的增加。

DT[J(x = unique(DT)[x!="a"][,x])]

##-------------------------------- Timings -----------------------------------##

library(data.table)
library(rbenchmark)

DT = data.table(x=rep(c("a","b","c"),each=45e5), y=c(1,3,6), v=1:9, key="x")
Josh <- function() DT[J(x = unique(DT)[x!="a"][,x])]
Andrie <- function() DT[-DT["a", which=TRUE]]

## Compare results
identical(Josh(), setkey(Andrie(), "x"))  
# [1] TRUE

## Compare timings
benchmark(replications = 10, order="relative", Josh=Josh(), Andrie=Andrie())
    test replications elapsed relative user.self sys.self user.child sys.child
1   Josh           10   17.50    1.000     14.78      3.6         NA        NA
2 Andrie           10   18.75    1.071     16.52      3.2         NA        NA

如果DT[,x] 可以返回一个data.table 而不是一个向量,我会特别想使用它。然后,可以将构造稍微简化为DT[unique(DT[,x])[x!="a"]]。此外,即使键中有多个列,它也可以工作,目前还没有。

【讨论】:

  • 哇!很高兴看到友好的竞争。使用 3 次运行中最快的基准(例如 microbenchark,尽管它的名字暗示它仅适用于小时间,它默认报告最小值和最大值)是更符合行业标准:缓存效果在这样的基准中可能很重要。
  • 在结束之前使用一系列输入可能会更好;例如,不连接选择一个大子集而不是一个小子集,并且组的数量和每个组的大小也各不相同。已知的严重减速Bug#2216 也必须在某些情况下咬人。
  • 此外,unique(DT) 将随着列数的增加而变慢,具体取决于唯一性的多少。因子列在这里可能很有用,仅在级别上快速执行setdiff。总之,每种方法的相对优点可以延伸到几页分析!一旦你解决了(我自己也不知道)DT[-"a"] 可以在实施FR#1384 时自动切换到最佳方法! :)
  • 该死——我希望把它扔到以太里(让你抓住)会给我一个明确的答案;)根据你提出的观点,我会更倾向于坚持安德烈的方法(注意重置它丢弃的关键信息)。
猜你喜欢
  • 1970-01-01
  • 2018-03-10
  • 1970-01-01
  • 2014-09-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-09-16
相关资源
最近更新 更多