2012-09-13 73 views
10

我有一个data.table包含一些组。我操作每个组,一些组返回数字,其他组返回NA。由于某些原因,data.table无法将所有内容重新组合在一起。这是一个错误还是我误解?这里有一个例子:NA in data.table

dtb <- data.table(a=1:10) 
f <- function(x) {if (x==9) {return(NA)} else { return(x)}} 
dtb[,f(a),by=a] 

Error in `[.data.table`(dtb, , f(a), by = a) : 
    columns of j don't evaluate to consistent types for each group: result for group 9 has  column 1 type 'logical' but expecting type 'integer' 

我的理解是NA是在R数字,因为很显然,我们可以有一个data.tableNA值兼容。我知道我可以返回NULL,这将工作正常,但问题是与NA

+2

的可能重复[为什么平均行程达data.table(整数与双)?(HTTP:// stackoverflow.com/questions/12125364/why-does-median-trip-up-data-table-integer-versus-double) –

+2

我也有一个相关的问题:[用运算符分割数据表:函数返回数值和/或NAs失败](http://stackoverflow.com/questions/7960798/splitting-a-data-table-with-the-by-operator-functions-that-return-numeric-value) –

+0

@Alex当问题是关于错误消息时,尝试搜索SO为错误消息。例如[this search](http://stackoverflow.com/search?q=%5Bdata.table%5D+%22columns+of+j+don%27t+evaluate+to+consistent+types+for+each+group% 22&submit = search)返回上面的2个链接和第3个链接。 –

回答

14

?NA

NA是长度为1的逻辑常数,其包含丢失值指示符。 NA可以被强制转换为除原始的任何其他矢量类型。还有支持缺失值的其他原子矢量类型的常量NA_integer_,NA_real_,NA_complex_和NA_character_:所有这些都是R语言中的保留字。

您必须指定正确的类型为您的功能工作 -

您可以在函数中强制匹配的x类型(注意,我们需要any这对于情况超过工作1行中的一个子集!

f <- function(x) {if any((x==9)) {return(as(NA, class(x)))} else { return(x)}} 

更多data.table * ISH *的做法

它可能会更有意义data.table使用set(或:=)以设置/替换参考。

set(dtb, i = which(dtb[,a]==9), j = 'a', value=NA_integer_) 

或在[:=使用a==9

dtb[a == 9, a := NA_integer_] 

或用二进制搜索

setkeyv(dtb, 'a') 
dtb[J(9), a := NA_integer_] 

有用沿着:=矢量扫描注意

如果使用:=点或set的方法,你似乎没有需要指定NA

无论下面的工作

dtb <- data.table(a=1:10) 
setkeyv(dtb,'a') 
dtb[a==9,a := NA] 

dtb <- data.table(a=1:10) 
setkeyv(dtb,'a') 
set(dtb, which(dtb[,a] == 9), 'a', NA) 

这给出了一个非常有用的错误信息,让你知道的原因及解决方法:

错误[.data.table(DTC,J(9),:=(一,NA)): 类型RHS的( '逻辑')必须匹配LHS( '整数')。对于最快的情况,检查和强制会对性能造成太大影响。要么改变目标列的类型,要么强制:=你自己的RHS(例如,通过使用代替1)


1L哪个是最快

具有合理的大在data.set其中a替换原位

原位

library(data.table) 

set.seed(1) 
n <- 1e+07 
DT <- data.table(a = sample(15, n, T)) 
setkeyv(DT, "a") 
DTa <- copy(DT) 
DTb <- copy(DT) 
DTc <- copy(DT) 
DTd <- copy(DT) 
DTe <- copy(DT) 

f <- function(x) { 
    if (any(x == 9)) { 
     return(as(NA, class(x))) 
    } else { 
     return(x) 
    } 
} 

system.time({DT[a == 9, `:=`(a, NA_integer_)]}) 
## user system elapsed 
## 0.95 0.24 1.20 
system.time({DTa[a == 9, `:=`(a, NA)]}) 
## user system elapsed 
## 0.74 0.17 1.00 
system.time({DTb[J(9), `:=`(a, NA_integer_)]}) 
## user system elapsed 
## 0.02 0.00 0.02 
system.time({set(DTc, which(DTc[, a] == 9), j = "a", value = NA)}) 
## user system elapsed 
## 0.49 0.22 0.67 
system.time({set(DTc, which(DTd[, a] == 9), j = "a", value = NA_integer_)}) 
## user system elapsed 
## 0.54 0.06 0.58 
system.time({DTe[, `:=`(a, f(a)), by = a]}) 
## user system elapsed 
## 0.53 0.12 0.66 
# The are all the same! 
all(identical(DT, DTa), identical(DT, DTb), identical(DT, DTc), identical(DT, 
    DTd), identical(DT, DTe)) 
## [1] TRUE 

替换不出所料,二进制搜索方法是最快的

+0

有趣!你能否详细说明一下?我没有意识到存在不同类型的“NA”值。 – Alex

+0

我会尽快接受你的答案 – Alex

+1

查看NA?整合NA_integer_,NA_real_,NA_complex_和NA_character_ * – mnel

0

你也可以做这样的事情:

dtb <- data.table(a=1:10) 

mat <- ifelse(dtb == 9,NA,dtb$a) 

上面的命令会给你矩阵,但你可以改回它data.table

new.dtb <- data.table(mat) 
new.dtb 
    a 
1: 1 
2: 2 
3: 3 
4: 4 
5: 5 
6: 6 
7: 7 
8: 8 
9: NA 
10: 10 

希望这有助于。

-1

如果你想要到NAS分配给许多变量,你可以使用approach suggested here

v_1 <- c(0,0,1,2,3,4,4,99) 
v_2 <- c(1,2,2,2,3,99,1,0) 
dat <- data.table(v_1,v_2) 

for(n in 1:2) { 
    chari <- paste0(sprintf('v_%s' ,n), ' %in% c(0,99)') 
    charj <- sprintf('v_%s := NA_integer_', n) 
    dat[eval(parse(text=chari)), eval(parse(text=charj))] 
}