Подтвердить что ты не робот

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, что это может очень хорошо привести к мнениям, и я отлично справляюсь с тем, что не отвечаю на этот вопрос вообще).

4b9b3361

Ответ 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 - это явно противоречиво, но, по крайней мере, менее глупо, поскольку в обоих случаях оно фактически возвращает подмножества исходной таблицы данных.