24

如何选择数据表中主键中缺少值的所有行。

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

选择特定值很容易

DT["a",]  

选择缺失值似乎需要向量搜索。不能使用二分查找。我对么?

DT[NA,]# does not work
DT[is.na(x),] #does work
4

2 回答 2

22

幸运的是,DT[is.na(x),]几乎和 (eg) 一样快DT["a",],所以在实践中,这可能并不重要:

library(data.table)
library(rbenchmark)

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

benchmark(DT["a",],
          DT[is.na(x),],
          replications=20)
#             test replications elapsed relative user.self sys.self user.child
# 1      DT["a", ]           20    9.18    1.000      7.31     1.83         NA
# 2 DT[is.na(x), ]           20   10.55    1.149      8.69     1.85         NA

===

马修的补充(不适合评论):

不过,上面的数据有 3 个非常大的组。因此,二分查找的速度优势在这里主要由创建大子集的时间(1/3 的数据被复制)决定。

benchmark(DT["a",],  # repeat select of large subset on my netbook
    DT[is.na(x),],
    replications=3)
          test replications elapsed relative user.self sys.self
     DT["a", ]            3   2.406    1.000     2.357    0.044
DT[is.na(x), ]            3   3.876    1.611     3.812    0.056

benchmark(DT["a",which=TRUE],   # isolate search time
    DT[is.na(x),which=TRUE],
    replications=3)
                      test replications elapsed relative user.self sys.self
     DT["a", which = TRUE]            3   0.492    1.000     0.492    0.000
DT[is.na(x), which = TRUE]            3   2.941    5.978     2.932    0.004

随着返回的子集的大小减小(例如添加更多组),差异变得明显。单列上的矢量扫描还不错,但在 2 列或更多列上它会迅速降级。

也许 NA 应该可以加入。不过,我似乎记得有一个问题。这是从 FR#1043 链接的一些历史记录Allow or disallow NA in keys?. 它在那里提到NA_integer_内部是一个负整数。这会使基数/计数排序(iirc)出错,从而导致setkey速度变慢。但它在重新访问的列表中。

于 2012-09-28T20:01:03.087 回答
20

这现在在 v1.8.11 中实现。来自新闻

o 二分搜索现在能够对NA/ NaNs 进行子集化,并且还可以通过匹配s/ s 来执行joins和执行。mergesNANaN

尽管此时您必须明确提供正确的NA(NA_real_NA_character_)。

关于OP的数据:

DT[J(NA_character_)] # or for characters simply DT[NA_character_]
#     x y v
# 1: NA 1 7
# 2: NA 3 8
# 3: NA 6 9

此外,这是来自@JoshOBrien 帖子的相同基准,添加了对 NA 的二进制搜索:

library(data.table)
library(rbenchmark)

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

benchmark(DT["a",],
          DT[is.na(x),],
          DT[NA_character_], 
          replications=20)

            test replications elapsed relative user.self sys.self
1      DT["a", ]           20   4.763    1.238     4.000    0.567
2 DT[is.na(x), ]           20   5.399    1.403     4.537    0.794
3         DT[NA]           20   3.847    1.000     3.215    0.600 # <~~~ 
于 2013-12-15T01:06:41.370 回答