Разделение таблицы data.table с помощью оператора by: функции, которые возвращают числовые значения и / или NA, не работают - PullRequest
11 голосов
/ 01 ноября 2011

У меня есть data.table с двумя столбцами: один ID столбец и один value столбец. Я хочу разделить таблицу по столбцу ID и запустить функцию foo в столбце value. Это отлично работает, пока foo не возвращает NA. В этом случае я получаю ошибку, которая говорит мне, что типы групп не согласованы. Я предполагаю, что - поскольку is.logical(NA) равно TRUE и is.numeric(NA) равно FALSE, data.table внутренне предполагает, что я хочу объединить логические значения с числовыми, и возвращает ошибку. Тем не менее, я считаю это поведение странным. Есть комментарии по этому поводу? Я что-то упускаю здесь очевидное или это действительно предполагаемое поведение? Если так, короткое объяснение было бы здорово. (Обратите внимание, что я знаю обходной путь: просто позвольте foo2 вернуть полное невероятное число и отфильтровать его позже. Однако, это кажется плохим кодированием).

Вот пример:

library(data.table)
foo1 <- function(x) {if (mean(x) < 5) {return(1)} else {return(2)}}
foo2 <- function(x) {if (mean(x) < 5) {return(1)} else {return(NA)}}
DT <- data.table(ID=rep(c("A", "B"), each=5), value=1:10)
DT[, foo1(value), by=ID] #Works perfectly
     ID V1
[1,]  A  1
[2,]  B  2
DT[, foo2(value), by=ID] #Throws error
Error in `[.data.table`(DT, , foo2(value), by = ID) : 
columns of j don't evaluate to consistent types for each group: result for group 2 has column 1 type 'logical' but expecting type 'numeric'

1 Ответ

11 голосов
/ 01 ноября 2011

Это можно исправить, указав, что ваша функция должна возвращать NA_real_, а не NA типа по умолчанию.

foo2 <- function(x) {if (mean(x) < 5) {return(1)} else {return(NA)}}
DT[, foo2(value), by=ID] #Throws error
# Error in `[.data.table`(DT, , foo2(value), by = ID) : 
# columns of j don't evaluate to consistent types for each group: 
# result for group 2 has column 1 type 'logical' but expecting type 'numeric'

foo3 <- function(x) {if (mean(x) < 5) {return(1)} else {return(NA_real_)}}
DT[, foo3(value), by=ID] #Works
#      ID V1
# [1,]  A  1
# [2,]  B NA

Между прочим, сообщение, которое foo2() выдает при сбое, приятно информативно. По сути, это говорит о том, что ваш NA не того типа. Чтобы решить эту проблему, вам просто нужно найти константу NA правильного типа (или класса):

NAs <- list(NA, NA_integer_, NA_real_, NA_character_, NA_complex_)
data.frame(contantName = sapply(NAs, deparse), 
           class       = sapply(NAs, class),
           type        = sapply(NAs, typeof))

#     contantName     class      type
# 1            NA   logical   logical
# 2   NA_integer_   integer   integer
# 3      NA_real_   numeric    double
# 4 NA_character_ character character
# 5   NA_complex_   complex   complex
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...