为您的问题提供解决方案:
你应该使用%in%
. 它给你一个逻辑向量。
a %in% ""
# [1] FALSE TRUE FALSE
x[!a %in% ""]
# a
# 1: 1
# 2: NA
要找出为什么会发生这种情况data.table
:
(相对于data.frame
)
如果您查看function 下data.table
文件的源代码,则会发现一组该检查参数。其中之一是:data.table.R
"[.data.table"
if-statements
i
if (!missing(i)) {
# Part (1)
isub = substitute(i)
# Part (2)
if (is.call(isub) && isub[[1L]] == as.name("!")) {
notjoin = TRUE
if (!missingnomatch) stop("not-join '!' prefix is present on i but nomatch is provided. Please remove nomatch.");
nomatch = 0L
isub = isub[[2L]]
}
.....
# "isub" is being evaluated using "eval" to result in a logical vector
# Part 3
if (is.logical(i)) {
# see DT[NA] thread re recycling of NA logical
if (identical(i,NA)) i = NA_integer_
# avoids DT[!is.na(ColA) & !is.na(ColB) & ColA==ColB], just DT[ColA==ColB]
else i[is.na(i)] = FALSE
}
....
}
为了解释这种差异,我在这里粘贴了重要的一段代码。我还将它们标记为 3 个部分。
首先,为什么dt[a != ""]
不能按预期工作(由 OP)?
首先,part 1
评估为 class 的对象call
。if 语句的第二部分part 2
返回 FALSE。之后,call
被“评估”为c(TRUE, FALSE, NA)
。然后part 3
被执行。因此,NA
被替换为FALSE
(逻辑循环的最后一行)。
为什么x[!(a== "")]
按预期工作(由OP)?
part 1
再次返回呼叫。但是,part 2
评估为 TRUE 并因此设置:
1) `notjoin = TRUE`
2) isub <- isub[[2L]] # which is equal to (a == "") without the ! (exclamation)
这就是魔法发生的地方。否定现在已被删除。请记住,这仍然是类call的对象。所以这被评估(使用eval
)再次合乎逻辑。因此,(a=="")
评估为c(FALSE, TRUE, NA)
。
现在,这是is.logical
在part 3
. 所以,在这里,NA
被替换为FALSE
. 因此变成,c(FALSE, TRUE, FALSE)
。在稍后的某个时间点, awhich(c(F,T,F))
被执行,这导致 2 这里。因为notjoin = TRUE
(from part 2
) seq_len(nrow(x))[-2]
= c(1,3) 返回。所以,x[!(a=="")]
基本上返回x[c(1,3)]
了想要的结果。这是相关的代码片段:
if (notjoin) {
if (bywithoutby || !is.integer(irows) || is.na(nomatch)) stop("Internal error: notjoin but bywithoutby or !integer or nomatch==NA")
irows = irows[irows!=0L]
# WHERE MAGIC HAPPENS (returns c(1,3))
i = irows = if (length(irows)) seq_len(nrow(x))[-irows] else NULL # NULL meaning all rows i.e. seq_len(nrow(x))
# Doing this once here, helps speed later when repeatedly subsetting each column. R's [irows] would do this for each
# column when irows contains negatives.
}
鉴于此,我认为语法存在一些不一致之处。如果我设法抽出时间来阐述问题,那么我很快就会写一篇文章。