我对data.table
的行为感到有些惊讶。我想从data.table
所有非NA
值中选择一行。
有NA
个值,它正在运作:
t = data.table(a=1,b=NA)
t[, !is.na(t), with=F]
没有NA
值,它无法正常工作:
t = data.table(a=1, b=2)
t[, !is.na(t), with=F]
基本区别在于t[, !c(F, F), with=F]
不起作用。有趣的是t[, c(T, T), with=F]
做得很好。
我知道有很多方法可以实现所需的输出,但我只对此感兴趣 - 对我来说很奇怪 - data.table
的行为。
答案 0 :(得分:5)
我调查了data.table:::`[.data.table`
source code
这对我来说确实看起来像个错误。基本上发生的是,!is.na()
来电分为!
和is.na()
来电。然后,它将此向量相加,如果长度为零则返回null.data.table()
。问题是,对于dt <- data.table(a = 1, b = 2)
,sum(is.na(dt))
始终为零。
下面是一段缩短的代码,用以说明引擎盖下的内容
sim_dt <- function(...) {
## data.table catches the call
jsub <- substitute(...)
cat("This is your call:", paste0(jsub, collapse = ""))
## data.table separates the `!` from the call and sets notj = TRUE instead
## and saves `is.na(t)` into `jsub`
if (is.call(jsub) && deparse(jsub[[1L]], 500L, backtick=FALSE) %in% c("!", "-")) { # TODO is deparse avoidable here?
notj = TRUE
jsub = jsub[[2L]]
} else notj = FALSE
cat("\nnotj:", notj)
cat("\nThis is the new jsub: ", paste0(jsub, collapse = "("), ")", sep = "")
## data.table evaluates just the `jsub` part which obviously return a vector of `FALSE`s (because `!` was removed)
cat("\nevaluted j:", j <- eval(jsub, setattr(as.list(seq_along(dt)), 'names', names(dt)), parent.frame()))# else j will be evaluated for the first time on next line
## data.table checks if `j` is a logical vector and looks if there are any TRUEs and gets an empty vector
if (is.logical(j)) cat("\nj after `which`:", j <- which(j))
cat("\njs length:", length(j), "\n\n")
## data.table checks if `j` is empty (and it's obviously is) and returns a null.data.table
if (!length(j)) return(data.table:::null.data.table()) else return(dt[, j, with = FALSE])
}
## Your data.table
dt <- data.table(a = 1, b = 2)
sim_dt(!is.na(dt))
# This is your call: !is.na(dt)
# notj: TRUE
# This is the new jsub: is.na(dt)
# evaluted j: FALSE FALSE
# j after `which`:
# js length: 0
#
# Null data.table (0 rows and 0 cols)
dt <- data.table(a = 1, b = NA)
sim_dt(!is.na(dt))
# This is your call: !is.na(dt)
# notj: TRUE
# This is the new jsub: is.na(dt)
# evaluted j: FALSE TRUE
# j after `which`: 2
# js length: 1
#
# b
# 1: NA
答案 1 :(得分:1)
@Roland已经提到is.na(t)
输出是一个矩阵,你需要一个向量来选择列。
但是列选择应该在OP
给出的示例中起作用,因为它在data.table中只有一行。我们需要做的就是将它包装在()
中以进行评估。例如:
library(data.table)
t = data.table(a=1, b=2)
t[,(!c(FALSE,FALSE)),with=FALSE]
# a b
# 1: 1 2
t[,(!is.na(t)),with=FALSE]
# a b
# 1: 1 2