Ответ 1
Чтобы решить вопрос:
Вы должны использовать %in%
. Это возвращает логический вектор.
a %in% ""
# [1] FALSE TRUE FALSE
x[!a %in% ""]
# a
# 1: 1
# 2: NA
Чтобы узнать, почему это происходит в data.table
:
(как показано на data.frame
)
Если вы посмотрите исходный код 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
оценивает объект класса 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)
Вот где произошло волшебство. На данный момент отрицание отменено. И помните, что это все еще объект вызова класса. Таким образом, это оценивается (используя eval
) для логического повторения. Итак, (a=="")
оценивается до c(FALSE, TRUE, NA)
.
Теперь это отмечено для is.logical
в part 3
. Итак, здесь NA
заменяется на FALSE
. Поэтому он становится c(FALSE, TRUE, FALSE)
. В какой-то момент позже выполняется which(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 [irows] would do this for each
# column when irows contains negatives.
}
Учитывая это, я думаю, что есть некоторые несоответствия с синтаксисом. И если мне удастся найти время, чтобы сформулировать проблему, я скоро напишу сообщение.