2011-10-31 6 views
11

Tengo un data.table con dos columnas: una columna ID y una columna value. Quiero dividir la tabla por la columna ID y ejecutar una función foo en la columna value. Esto funciona bien siempre que foo no devuelva NA. En ese caso, recibo un error que me dice que los tipos de los grupos no son consistentes. Mi suposición es que, dado que is.logical(NA) es igual a TRUE y is.numeric(NA) es igual a FALSE, data.table internamente supone que quiero combinar valores lógicos con valores numéricos y devuelve un error. Sin embargo, encuentro este comportamiento peculiar. ¿Algún comentario sobre eso? ¿Extraño algo obvio aquí o es ese comportamiento intencional? Si es así, una breve explicación sería genial. (Tenga en cuenta que sí sé una solución alternativa: simplemente deje que foo2 devuelva un número completo improbable y filtre para más tarde. Sin embargo, esto parece una mala codificación).División de un data.table con el by-operator: funciones que devuelven valores numéricos y/o NA fallan

Aquí está el ejemplo:

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' 

Respuesta

11

Puede solucionar este problema mediante la especificación de que su función debe devolver un NA_real_, en lugar de un NA del tipo predeterminado.

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 

Por cierto el mensaje que foo2() da cuando no es muy bien informativo. Básicamente, te dice que tu NA es del tipo equivocado. Para solucionar el problema, sólo tiene que buscar la NA constante del tipo correcto (o clase):

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 
+1

Cuanto más trabajo con 'R', cuanto más se dan cuenta de la cantidad de cosas que simplemente no hago saber. Este truco de 'NA_real_' es definitivamente uno de eso. Así que gracias @Josh O'Brien, excelente respuesta. –

+0

Gracias. Agregué un poco más acerca de las constantes 'NA' a mi respuesta, ya que esto a menudo me ha sido útil, y es un aspecto de los valores' NA' que generalmente es invisible para los usuarios. ¡Lo cual es justo como debería ser! –

+0

¿Qué sucede si no conoce la clase con anticipación? Ha sido un gran problema para mí en data.table al usar el argumento 'by ='. ¿Alguna vez te encuentras con un problema como este? – rbatt

Cuestiones relacionadas