redundancia - DT[!(X==.)] Y DT[x!=.] Tratan NA en x inconsistentemente
sistema de ecuaciones lineales 2x2 inconsistente (4)
Esto es algo que pensé que debería preguntar después de esta pregunta . Me gustaría confirmar si esto es un error / inconsistencia antes de archivarlo como tal en el R-forge tracker.
Considere esta data.table
:
require(data.table)
DT <- data.table(x=c(1,0,NA), y=1:3)
Ahora, para acceder a todas las filas del DT que no son 0, podríamos hacerlo de la siguiente manera:
DT[x != 0]
# x y
# 1: 1 1
DT[!(x == 0)]
# x y
# 1: 1 1
# 2: NA 3
Al acceder a DT[x != 0]
y DT[!(x==0)]
obtienen resultados diferentes cuando la operación lógica subyacente es equivalente.
Nota: Convertir esto en un data.frame y ejecutar estas operaciones dará resultados que son idénticos entre sí para ambas operaciones lógicamente equivalentes, pero ese resultado es diferente de ambos resultados de la tabla de datos. Para una explicación de por qué, mire ?`[`
la sección NAs in indexing
.
Edición: ya que algunos de ustedes han enfatizado la igualdad con data.frame
, aquí está el fragmento de la salida de las mismas operaciones en 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
Creo que esto es una inconsistencia y ambos deberían proporcionar el mismo resultado. Pero, ¿qué resultado? La documentación para [.data.table
dice:
i ---> Vector entero, lógico o de caracteres, expresión de nombres de columna, lista o tabla de datos.
los vectores enteros y lógicos funcionan de la misma manera que lo hacen en [.data.frame. Aparte de las NA, las lógicas i se tratan como FALSE y una única lógica NA no se recicla para que coincida con el número de filas, como lo está en [.data.frame.
Está claro por qué los resultados son diferentes de lo que se obtendría al hacer la misma operación en un data.frame
. Pero aún así, dentro de data.table, si este es el caso, entonces ambos deberían regresar:
# x y
# 1: 1 1
[.data.table
código fuente de [.data.table
y ahora entiendo por qué sucede esto. Consulte esta publicación para obtener una explicación detallada de por qué sucede esto.
Brevemente, x != 0
evalúa como "lógico" y NA
se reemplaza a FALSE. Sin embargo !(x==0)
, primero (x == 0)
se evalúa como lógico y NA
se reemplaza a FALSE. Luego ocurre la negación, lo que hace que NA
convierta en TRUE
.
Entonces, mi primera (o más bien la principal) pregunta es: ¿es esto un error / inconsistencia? Si es así, lo archivaré como uno en data.table R-forge tracker. Si no, me gustaría saber la razón de esta diferencia y me gustaría sugerir una corrección a la documentación que explica esta diferencia (¡a la documentación ya increíble!).
Edición: Siguiendo con los comentarios, la segunda pregunta es si el manejo de data.table para subconjuntos mediante la indexación con columnas que contienen NA
asemeja al de data.frame
(Pero estoy de acuerdo, siguiendo el comentario de @ Roland de que esto puede conducir a opiniones y estoy perfectamente bien si no contesto esta pregunta en absoluto).
Creo que es un comportamiento documentado y consistente.
Lo más importante a tener en cuenta es que el prefijo !
dentro del argumento i
hay un indicador para no unirse, por lo que x != 0
y !(x==0)
ya no son la misma operación lógica cuando se trabaja con el manejo documentado de NA dentro de data.table
La sección de noticias sobre el 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
Y a partir de ?data.table
Todos los tipos de ''i'' pueden tener el prefijo!. Esto indica que se debe realizar una no combinación o no selección. En la documentación de data.table, donde nos referimos al tipo de ''i'', nos referimos al tipo de ''i'' después de ''!'', Si está presente. Ver ejemplos
¿Por qué es consistente con el manejo documentado de NA dentro de data.table?
NA
valores de NA
se consideran FALSOS. Piensa en ello como hacer isTRUE
en cada elemento.
por lo tanto, DT[x!=0]
se indexa con TRUE FALSE NA
que se convierte en TRUE FALSE FALSE
debido al manejo documentado de NA.
Usted está queriendo sub-establecer cuando las cosas son VERDADERAS.
Esto significa que está obteniendo aquellos donde x! = 0 es VERDADERO (y no NA)
DT[!(x==0)]
usa los estados de no unión que desea que no sean 0 (que pueden incluir los valores de NA
).
consultas de seguimiento / otros ejemplos
DT[!(x!=0)]
## returns
x y
1: 0 2
2: NA 3
x!=0
es VERDADERO para un valor, por lo que la no unión devolverá lo que no es verdadero. (es decir, lo que era FALSE
(en realidad == 0
) o NA
DT[!!(x==0)]
## returns
x y
1: 0 2
2: NA 3
Esto se analiza como !(!(x==0))
. El prefijo !
denota una no unión, y el interior !(x==0)
se analiza de manera idéntica a x!=0
, por lo que se aplica el razonamiento del caso anterior.
Llego un mes tarde a esta discusión, pero con nuevos ojos y leyendo todos los comentarios ... sí, creo que sería mejor que DT[x != .]
Incluyera alguna fila con NA en x
en el resultado, y Debería cambiarlo para hacer eso.
Nueva respuesta agregada a la pregunta vinculada con más antecedentes desde un ángulo diferente:
https://.com/a/17008872/403310
Mi opinión es que el subset
hace lo correcto y tanto data.table
como data.frame
no lo hacen, data.frame
que data.frame
el más tonto de todos. Así que en lo que respecta a su pregunta, no, no creo que data.table
deba hacer lo mismo que data.frame
, debería hacer lo mismo que un subset
.
Para el registro, aquí está la salida del 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''s as well
subset(DF, is.na(x) | x != 0)
# x y
#1 1 1
#3 NA 3
Quiero desarrollar un poco sobre por data.frame
salida de data.frame
es tonta. La primera línea en la descripción de [.data.frame
dice: "Extraiga o reemplace subconjuntos de marcos de datos" . La salida que devuelve, donde tiene una fila con rowname = NA
y todos los elementos iguales a NA
son en absoluto "subconjuntos" de la trama de datos dada, haciendo que la salida sea inconsistente con el significado de la función. También es una gran molestia desde el punto de vista del usuario, ya que uno tiene que estar siempre al tanto de estas cosas y encontrar formas de evitar este comportamiento.
En lo que data.table
salida de data.table
, es claramente inconsistente, pero al menos menos tonta, ya que en ambos casos en realidad devuelve subconjuntos de la tabla de datos original.
A partir de la versión 1.8.11 la !
no activa una no unión para las expresiones lógicas y los resultados para las dos expresiones son los mismos:
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
Un par de otras expresiones mencionadas en la respuesta de @mnel también se comportan de una manera más predecible ahora:
DT[!(x != 0)]
# x y
#1: 0 2
DT[!!(x == 0)]
# x y
#1: 0 2