DT [! (X ==.)] И DT [x! =.] Обрабатывают NA в x непоследовательно
Это то, что я подумал, что я должен спросить этот вопрос. Я хотел бы подтвердить, если это ошибка/несогласованность, прежде чем записывать ее как таковой в трекер R-forge.
Рассмотрим это data.table
:
require(data.table)
DT <- data.table(x=c(1,0,NA), y=1:3)
Теперь, чтобы получить доступ ко всем строкам DT, которые не являются 0, мы могли бы сделать это следующими способами:
DT[x != 0]
# x y
# 1: 1 1
DT[!(x == 0)]
# x y
# 1: 1 1
# 2: NA 3
Доступ к DT[x != 0]
и DT[!(x==0)]
дает разные результаты, когда базовая логическая операция эквивалентна.
Примечание.. Преобразование этого в файл data.frame и выполнение этих операций даст результаты, идентичные друг другу для обеих логически эквивалентных операций, но этот результат отличается от обоих данных data.table, Для объяснения причины смотрите ?`[`
в разделе NAs in indexing
.
Изменить:. Поскольку некоторые из вас подчеркнули для равенства с data.frame
, здесь фрагмент вывода из тех же операций в data.frame:
DF <- as.data.frame(DT)
# check ?`[` under the section `NAs in indexing` as to why this happens
DF[DF$x != 0, ]
# x y
# 1 1 1
# NA NA NA
DF[!(DF$x == 0), ]
# x y
# 1 1 1
# NA NA NA
Я думаю, что это несогласованность, и оба должны обеспечить тот же результат. Но, в результате? В документации для [.data.table
говорится:
i --- > Целое число, логический или символьный вектор, выражение имен столбцов, списка или data.table.
целочисленные и логические векторы работают так же, как и в [.data.frame. Помимо NA в логическом i, они рассматриваются как FALSE, и один логический элемент NA не перерабатывается, чтобы соответствовать количеству строк, как это показано в [.data.frame.
Это ясно, почему результаты отличаются от того, что можно получить от выполнения той же операции на data.frame
. Но все же, в data.table, если это так, то оба из них должны возвращать:
# x y
# 1: 1 1
Я прошел через [.data.table
исходный код и теперь понимаю, почему это происходит. Подробнее о том, почему это происходит, см. этот пост.
Вкратце, x != 0
оценивается как "логический", а NA
заменяется на FALSE. Тем не менее, !(x==0)
, сначала (x == 0)
оценивается как логическое, а NA
заменяется на FALSE. Затем происходит отрицание, которое приводит к тому, что NA
в основном становится TRUE
.
Итак, мой первый (или, скорее, главный) вопрос заключается в том, что это ошибка/несогласованность? Если это так, я отправлю его как один в data.table R-forge tracker. Если нет, я хотел бы узнать причину этой разницы, и я хотел бы предложить исправление к документации, объясняющей эту разницу (к уже потрясающей документации!).
Изменить: После комментариев с комментариями второй вопрос заключается в том, должна ли data.table
обработка подмножества индексированием с столбцами, содержащими NA
, напоминать значение data.frame
? (Но я согласен, следуя комментарию @Roland, что это может очень хорошо привести к мнениям, и я отлично справляюсь с тем, что не отвечаю на этот вопрос вообще).
Ответы
Ответ 1
Начиная с версия 1.8.11 !
не запускает не-объединение для логических выражений и результаты для двух выражений одинаковы:
DT <- data.table(x=c(1,0,NA), y=1:3)
DT[x != 0]
# x y
#1: 1 1
DT[!(x == 0)]
# x y
#1: 1 1
Несколько других выражений, упомянутых в ответе @mnel, также ведут себя более предсказуемым образом:
DT[!(x != 0)]
# x y
#1: 0 2
DT[!!(x == 0)]
# x y
#1: 0 2
Ответ 2
Я думаю, что это документальное и последовательное поведение.
Главное отметить, что префикс !
в аргументе i
является флагом для не объединения, поэтому x != 0
и !(x==0)
больше не являются той же логической операцией при работе с документированная обработка NA в data.table
Раздел из новостей о not join
A new "!" prefix on i signals 'not-join' (a.k.a. 'not-where'), #1384i.
DT[-DT["a", which=TRUE, nomatch=0]] # old not-join idiom, still works
DT[!"a"] # same result, now preferred.
DT[!J(6),...] # !J == not-join
DT[!2:3,...] # ! on all types of i
DT[colA!=6L | colB!=23L,...] # multiple vector scanning approach (slow)
DT[!J(6L,23L)] # same result, faster binary search
'!' has been used rather than '-' :
* to match the 'not-join'/'not-where' nomenclature
* with '-', DT[-0] would return DT rather than DT[0] and not be backwards
compatible. With '!', DT[!0] returns DT both before (since !0 is TRUE in
base R) and after this new feature.
* to leave DT[+J...] and DT[-J...] available for future use
И от ?data.table
Все типы "i" могут иметь префикс!. Это сигнализирует об отсутствии соединения или не должен быть выбран. На протяжении всей документации data.table, где мы говорим о типе "i" , мы имеем в виду тип "i" после '!', если имеется. См. Примеры.
Почему это согласуется с документированной обработкой NA в data.table
Значения NA
считаются FALSE. Подумайте об этом, как сделать isTRUE
для каждого элемента.
поэтому DT[x!=0]
индексируется с помощью TRUE FALSE NA
, который становится TRUE FALSE FALSE
из-за документированной обработки NA.
Вы хотите подмножество, когда вещи TRUE.
Это означает, что вы получаете те, где x!= 0 имеет значение TRUE (а не NA)
DT[!(x==0)]
использует не присоединяет состояние, в котором вы хотите все, что не равно 0 (что может и будет включать значения NA
).
последующие запросы/дополнительные примеры
DT[!(x!=0)]
## returns
x y
1: 0 2
2: NA 3
x!=0
имеет значение ИСТИНА для одного значения, поэтому не будет возвращать то, что не соответствует действительности. (т.е. что было FALSE
(фактически == 0
) или NA
DT[!!(x==0)]
## returns
x y
1: 0 2
2: NA 3
Это анализируется как !(!(x==0))
. Префикс !
означает не объединение, а внутренний !(x==0)
анализируется идентично с x!=0
, поэтому применяются рассуждения из случая, приведенного выше.
Ответ 3
Я опоздал на этот месяц, но со свежими глазами и прочитал все комментарии... да, я считаю, что DT[x != .]
было бы лучше, если бы оно включало любые строки с NA в x
в результате и мы должны изменить его для этого.
Новый ответ добавлен в связанный вопрос с дополнительным фоном под другим углом:
fooobar.com/questions/261407/...
Ответ 4
Мое мнение состоит в том, что subset
делает правильную вещь, а data.table
и data.frame
не работает, причем data.frame
делает самые глупые из них. Итак, что касается вашего вопроса - нет, я не думаю, что data.table
должен делать то же самое, что и data.frame
, он должен делать то же самое, что и subset
.
Для записи здесь вывод subset
:
subset(DF, x != 0)
# x y
#1 1 1
subset(DF, !(x == 0))
# x y
#1 1 1
#
# or if you want the NA as well
subset(DF, is.na(x) | x != 0)
# x y
#1 1 1
#3 NA 3
Я хочу немного рассказать о том, почему вывод data.frame
глупо. В самой первой строке описания [.data.frame
говорится - "Извлечь или заменить подмножества кадров данных". Результат, который он возвращает, где у него есть строка с rowname = NA
и все элементы, равные NA
, ни в коем случае не являются "подмножествами" данного кадра данных, делая вывод несовместимым со значением функции, Это также огромная проблема с точки зрения пользователя, поскольку нужно всегда знать об этих вещах и находить способы обойти это поведение.
Что касается вывода data.table
- это явно противоречиво, но, по крайней мере, менее глупо, поскольку в обоих случаях оно фактически возвращает подмножества исходной таблицы данных.