【问题标题】:Efficiently counting non-NA elements in data.table有效计算 data.table 中的非 NA 元素
【发布时间】:2015-04-16 19:01:44
【问题描述】:

有时我需要计算data.table 中一列或另一列中非NA 元素的数量。最好的data.table-tailored 方式是什么?

为了具体起见,让我们使用这个:

DT <- data.table(id = sample(100, size = 1e6, replace = TRUE),
                 var = sample(c(1, 0, NA), size = 1e6, replace = TRUE), key = "id")

我想到的第一件事是这样的:

DT[!is.na(var), N := .N, by = id]

但这有一个不幸的缺点,即N 不会被分配到缺少var 的任何行,即DT[is.na(var), N] = NA

所以我通过附加来解决这个问题:

DT[!is.na(var), N:= .N, by = id][ , N := max(N, na.rm = TRUE), by = id] #OPTION 1

但是,我不确定这是最好的方法;我想到的另一种选择,以及thisdata.frames 的类似问题的建议是:

DT[ , N := length(var[!is.na(var)]), by = id] # OPTION 2

DT[ , N := sum(!is.na(var)), by = id] # OPTION 3

比较这些计算时间(平均超过 100 次试验),最后一个似乎是最快的:

OPTION 1 | OPTION 2 | OPTION 3
  .075   |   .065   |   .043

有人知道data.table 的更快方法吗?

【问题讨论】:

    标签: r data.table


    【解决方案1】:

    是的,第 3 个选项似乎是最好的。我添加了另一个只有当您考虑将 data.table 的键从 id 更改为 var 时才有效,但选项 3 仍然是您数据上最快的。

    library(microbenchmark)
    library(data.table)
    
    dt<-data.table(id=(1:100)[sample(10,size=1e6,replace=T)],var=c(1,0,NA)[sample(3,size=1e6,replace=T)],key=c("var"))
    
    dt1 <- copy(dt)
    dt2 <- copy(dt)
    dt3 <- copy(dt)
    dt4 <- copy(dt)
    
    microbenchmark(times=10L,
                   dt1[!is.na(var),.N,by=id][,max(N,na.rm=T),by=id],
                   dt2[,length(var[!is.na(var)]),by=id],
                   dt3[,sum(!is.na(var)),by=id],
                   dt4[.(c(1,0)),.N,id,nomatch=0L])
    # Unit: milliseconds
    #                                                         expr      min       lq      mean    median        uq       max neval
    #  dt1[!is.na(var), .N, by = id][, max(N, na.rm = T), by = id] 95.14981 95.79291 105.18515 100.16742 112.02088 131.87403    10
    #                     dt2[, length(var[!is.na(var)]), by = id] 83.17203 85.91365  88.54663  86.93693  89.56223 100.57788    10
    #                             dt3[, sum(!is.na(var)), by = id] 45.99405 47.81774  50.65637  49.60966  51.77160  61.92701    10
    #                        dt4[.(c(1, 0)), .N, id, nomatch = 0L] 78.50544 80.95087  89.09415  89.47084  96.22914 100.55434    10
    

    【讨论】:

    • @MichaelChirico,看看Keys and binary search based subsets(如果您发现不清楚/要添加的内容,请告诉我们here
    • 还有另一个选项:dt5[,.N[!is.na(var)],by=id] - 在我的系统上第三快,比选项 1 和 2 好很多。出于某种原因,选项 3 产生二进制响应 (0,1) 而不是计数,如果使用了多个“by”变量。建议的选项 5 给出了正确的计数。
    猜你喜欢
    • 2018-08-28
    • 1970-01-01
    • 2019-03-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-17
    • 1970-01-01
    • 2014-08-06
    • 1970-01-01
    相关资源
    最近更新 更多