NA в data.table

У меня есть data.table, который содержит несколько групп. Я работаю с каждой группой, и некоторые группы возвращают числа, другие возвращают NA. По какой-то причине data.table не может собрать все обратно. Это баг или я неправильно понимаю? Вот пример:

dtb <- data.table(a=1:10)
f <- function(x) {if (x==9) {return(NA)} else { return(x)}}
dtb[,f(a),by=a]

Error in `[.data.table`(dtb, , f(a), by = a) : 
  columns of j don't evaluate to consistent types for each group: result for group 9 has     column 1 type 'logical' but expecting type 'integer'

Насколько я понял, NA совместим с числами в R, поскольку ясно, что у нас может быть data.table, который имеет NA значений. Я понимаю, что могу вернуть NULL, и это будет работать нормально, но проблема связана с NA.


person Alex    schedule 13.09.2012    source источник
comment
возможный дубликат Почему медиана отключает data.table ( целое число против двойного)?   -  person Matt Dowle    schedule 13.09.2012
comment
У меня тоже была связанная проблема: value">Разделение data.table с помощью оператора by: функции, которые возвращают числовые значения и/или NA, не работают   -  person Christoph_J    schedule 13.09.2012
comment
@Alex Когда вопрос касается сообщения об ошибке, попробуйте выполнить поиск S.O. для сообщения об ошибке. Например, этот поиск возвращает 2 ссылки выше и 3-ю ссылку.   -  person Matt Dowle    schedule 13.09.2012
comment
спасибо за ссылки! Я попытался найти NA в data.table в Google, но не нашел многого. Я попробую найти сообщение об ошибке в следующий раз. ценю помощь.   -  person Alex    schedule 13.09.2012


Ответы (3)


От 1_

NA — логическая константа длины 1, содержащая индикатор отсутствующего значения. NA можно привести к любому другому типу вектора, кроме исходного. Существуют также константы NA_integer_, NA_real_, NA_complex_ и NA_character_ других типов атомарных векторов, которые поддерживают пропущенные значения: все они являются зарезервированными словами в языке R.

Вам нужно будет указать правильный тип для работы вашей функции -

Вы можете заставить функцию соответствовать типу x (обратите внимание, что нам нужно any, чтобы это работало в ситуациях с более чем 1 строкой в ​​подмножестве!

f <- function(x) {if any((x==9)) {return(as(NA, class(x)))} else { return(x)}}

Больше data.table*ish* подхода

Возможно, имеет больше смысла использовать data.table для установки/замены по ссылке с помощью set (или :=).

set(dtb, i = which(dtb[,a]==9), j = 'a', value=NA_integer_)

Или := в пределах [, используя векторное сканирование для a==9

dtb[a == 9, a := NA_integer_]

Или := вместе с бинарным поиском

setkeyv(dtb, 'a')
dtb[J(9), a := NA_integer_] 

Полезно отметить

Если вы используете подходы := или set, вам не нужно указывать тип NA

Оба следующих будут работать

dtb <- data.table(a=1:10)
setkeyv(dtb,'a')
dtb[a==9,a := NA]

dtb <- data.table(a=1:10)
setkeyv(dtb,'a')
set(dtb, which(dtb[,a] == 9), 'a', NA)

Это дает очень полезное сообщение об ошибке, которое позволяет узнать причину и решение:

Ошибка в [.data.table(DTc, J(9), :=(a, NA)) : тип RHS («логический») должен соответствовать LHS («целое число»). Проверка и принуждение слишком сильно повлияют на производительность в самых быстрых случаях. Либо измените тип целевого столбца, либо задайте правую часть := самостоятельно (например, используя 1L вместо 1)


Что быстрее

с разумным большим набором данных, где a заменяется на месте

Заменить на месте

library(data.table)

set.seed(1)
n <- 1e+07
DT <- data.table(a = sample(15, n, T))
setkeyv(DT, "a")
DTa <- copy(DT)
DTb <- copy(DT)
DTc <- copy(DT)
DTd <- copy(DT)
DTe <- copy(DT)

f <- function(x) {
    if (any(x == 9)) {
        return(as(NA, class(x)))
    } else {
        return(x)
    }
}

system.time({DT[a == 9, `:=`(a, NA_integer_)]})
##    user  system elapsed 
##    0.95    0.24    1.20 
system.time({DTa[a == 9, `:=`(a, NA)]})
##    user  system elapsed 
##    0.74    0.17    1.00 
system.time({DTb[J(9), `:=`(a, NA_integer_)]})
##    user  system elapsed 
##    0.02    0.00    0.02 
system.time({set(DTc, which(DTc[, a] == 9), j = "a", value = NA)})
##    user  system elapsed 
##    0.49    0.22    0.67 
system.time({set(DTc, which(DTd[, a] == 9), j = "a", value = NA_integer_)})
##    user  system elapsed 
##    0.54    0.06    0.58 
system.time({DTe[, `:=`(a, f(a)), by = a]})
##    user  system elapsed 
##    0.53    0.12    0.66 
# The are all the same!
all(identical(DT, DTa), identical(DT, DTb), identical(DT, DTc), identical(DT, 
    DTd), identical(DT, DTe))
## [1] TRUE

Неудивительно, что подход бинарного поиска является самым быстрым.

person mnel    schedule 13.09.2012
comment
интересно! не могли бы вы немного уточнить? я не знал, что существуют разные типы значений NA.. - person Alex; 13.09.2012
comment
Посмотрите на ?NA (в кавычках) *Есть также константы NA_integer_, NA_real_, NA_complex_ и NA_character_ * - person mnel; 13.09.2012
comment
Это немного глупо для R, не так ли? В этом игрушечном примере вы можете просто сделать as(NA, class(x)), но в ситуации, когда вы не знаете, например, будет ли значение результата integer или double, что делать - person Alex; 13.09.2012
comment
Если ваши данные относятся к классу integer, то они вернут NA_integer, если они двойные, то они будут класса numeric и вернут NA_real_. Большую часть времени вам все равно, и больше подходов data.tableish не требуют, чтобы вы указывали - person mnel; 13.09.2012
comment
да, но на самом деле в моем конкретном случае происходит то, что вещи в моем f преобразуются в xts, выполняются некоторые вычисления и возвращается ответ. поэтому я не могу использовать ваше предложение, к сожалению. в итоге я удалил значения NA из возвращаемого значения в моем варианте использования. - person Alex; 13.09.2012
comment
Опубликуйте небольшой пример того, каковы ваши фактические функции и данные, тогда мы сможем подойти к вашей проблеме. - person mnel; 13.09.2012
comment
Здесь есть несколько векторных сканирований (== в i), которые, похоже, предназначены для бинарного поиска? Кроме того, я проголосовал за то, чтобы закрыть как дубликат (см. Другой вопрос), но, возможно, @Alex мог бы вместо этого обновить заголовок вопроса, поскольку := тоже кажется подходящим, и в этом ответе есть хорошая информация. - person Matt Dowle; 13.09.2012
comment
@mnel, поскольку вы нажимаете DT на a, максимальная скорость для этого простого примера, по-видимому, достигается с использованием DT[J(9), a := NA_integer_]`? Возможно, это спорный вопрос, учитывая предыдущий комментарий ОП. - person BenBarnes; 13.09.2012
comment
Исправлена ​​проблема с бинарным поиском. Я думал, что пробовал это, и это выдало ошибку. Бинарный поиск побеждает с большим отрывом! - person mnel; 13.09.2012

вы также можете сделать что-то вроде этого:

dtb <- data.table(a=1:10)

mat <- ifelse(dtb == 9,NA,dtb$a)

Приведенная выше команда даст вам матрицу, но вы можете изменить ее обратно на data.table.

new.dtb <- data.table(mat)
new.dtb
     a
 1:   1
 2:   2
 3:   3
 4:   4
 5:   5
 6:   6
 7:   7
 8:   8
 9:  NA
10:  10

Надеюсь это поможет.

person user1021713    schedule 13.09.2012

Если вы хотите назначить NA многим переменным, вы можете использовать подход, предложенный здесь:

v_1  <- c(0,0,1,2,3,4,4,99)
v_2  <- c(1,2,2,2,3,99,1,0)
dat  <-  data.table(v_1,v_2)

for(n in 1:2) {
  chari <-  paste0(sprintf('v_%s' ,n), ' %in% c(0,99)')
  charj <- sprintf('v_%s := NA_integer_', n)
  dat[eval(parse(text=chari)), eval(parse(text=charj))]
}
person sdaza    schedule 06.12.2012