seleccionar - que es una lista en r
"Subconjunto" y "[" en el marco de datos dan resultados ligeramente diferentes, ¿por qué? (4)
En una versión (usando [
) sus columnas son enteros, mientras que en la otra versión (usando subset
) sus columnas se denominan enteros.
apply(df_ab, 2, str)
int [1:5] 1 2 3 4 5
int [1:5] 6 5 4 3 2
NULL
apply(df_AB, 2, str)
Named int [1:5] 1 2 3 4 5
- attr(*, "names")= chr [1:5] "1" "2" "3" "4" ...
Named int [1:5] 6 5 4 3 2
- attr(*, "names")= chr [1:5] "1" "2" "3" "4" ...
NULL
¿Podría alguien explicarme por qué obtengo resultados diferentes en mis últimas dos líneas de código (llamadas identical()
a continuación)? Estos dos objetos parecen ser objetos idénticos, pero cuando los uso en una función de aplicación, tengo algunos problemas:
df <- data.frame(a = 1:5, b = 6:2, c = rep(7,5))
df_ab <- df[,c(1,2)]
df_AB <- subset(df, select = c(1,2))
identical(df_ab,df_AB)
[1] TRUE
apply(df_ab,2,function(x) identical(1:5,x))
a b
TRUE FALSE
apply(df_AB,2,function(x) identical(1:5,x))
a b
FALSE FALSE
La función apply()
fuerza su primer argumento a una matriz antes de llamar a la función en cada columna. Así que sus marcos de datos son obligados a los objetos de matriz. Una consecuencia de esa conversión es que as.matrix(df_AB)
no tiene rownames, mientras que as.matrix(df_ab)
no:
> str(as.matrix(df_ab))
int [1:5, 1:2] 1 2 3 4 5 6 5 4 3 2
- attr(*, "dimnames")=List of 2
..$ : NULL
..$ : chr [1:2] "a" "b"
> str(as.matrix(df_AB))
int [1:5, 1:2] 1 2 3 4 5 6 5 4 3 2
- attr(*, "dimnames")=List of 2
..$ : chr [1:5] "1" "2" "3" "4" ...
..$ : chr [1:2] "a" "b"
Por lo tanto, cuando apply()
subconjunto de una columna de df_AB
, obtiene un vector nombrado, que no es idéntico a un vector sin nombre.
apply(df_AB, 2, str)
Named int [1:5] 1 2 3 4 5
- attr(*, "names")= chr [1:5] "1" "2" "3" "4" ...
Named int [1:5] 6 5 4 3 2
- attr(*, "names")= chr [1:5] "1" "2" "3" "4" ...
NULL
Contraste eso con la función subset()
, que selecciona filas usando un vector lógico para el valor de i
. Y parece que subcontratar un data.frame con un valor no faltante para i
causa esta diferencia en el atributo row.names
:
> str(as.matrix(df[1:5, 1:2]))
int [1:5, 1:2] 1 2 3 4 5 6 5 4 3 2
- attr(*, "dimnames")=List of 2
..$ : chr [1:5] "1" "2" "3" "4" ...
..$ : chr [1:2] "a" "b"
> str(as.matrix(df[, 1:2]))
int [1:5, 1:2] 1 2 3 4 5 6 5 4 3 2
- attr(*, "dimnames")=List of 2
..$ : NULL
..$ : chr [1:2] "a" "b"
Puede ver todos los detalles sangrientos de la diferencia entre los cuadros de datos usando la función .Internal(inspect(x))
. Puedes mirarlas tú mismo, si estás interesado.
Como Roland señaló en sus comentarios, puede usar la función .row_names_info()
para ver las diferencias solo en los nombres de las filas.
Observe que cuando falta un i
, el resultado de .row_names_info()
es negativo, pero es positivo si se subcontrata con un i
no faltante.
> .row_names_info(df_ab, type=1)
[1] -5
> .row_names_info(df_AB, type=1)
[1] 5
¿Qué significan estos valores se explica en ?.row_names_info
type: integer. Currently ‘type = 0’ returns the internal ‘"row.names"’ attribute (possibly ‘NULL’), ‘type = 2’ the number of rows implied by the attribute, and ‘type = 1’ the latter with a negative sign for ‘automatic’ row names.
Mirar la estructura de esos dos objetos antes de que se envíen para apply
muestra solo una diferencia: en los nombres conocidos, pero no es una diferencia que hubiera esperado que produjera la diferencia que está viendo. No veo la oferta actual de Joshua de ''subconjunto'' como una indexación lógica que explique esto. Por qué row.names = c(NA, -5L))
produce un resultado con nombre cuando la extracción con "[" aún no se ha explicado.
> dput(df_AB)
structure(list(a = 1:5, b = c(6L, 5L, 4L, 3L, 2L)), .Names = c("a",
"b"), row.names = c(NA, 5L), class = "data.frame")
> dput(df_ab)
structure(list(a = 1:5, b = c(6L, 5L, 4L, 3L, 2L)), .Names = c("a",
"b"), class = "data.frame", row.names = c(NA, -5L))
Estoy de acuerdo en que es la coacción de un.matrix la que necesita más investigación:
> attributes(df_AB[,1])
NULL
> attributes(df_ab[,1])
NULL
> attributes(as.matrix(df_AB)[,1])
$names
[1] "1" "2" "3" "4" "5"
Si desea comparar los valores 1:5
con los valores de las columnas, no debe usar apply
ya que apply
transforma los marcos de datos en matrices antes de aplicar las funciones. Debido a los nombres de las filas en el subconjunto creado con [
(ver la respuesta de @Joshua Ulrich), los valores 1:5
no son idénticos a un vector nombrado que incluye los mismos valores.
En su lugar, debe utilizar sapply
para aplicar la función identical
a las columnas. Esto evita transformar los marcos de datos en matrices:
> sapply(df_ab, identical, 1:5)
a b
TRUE FALSE
> sapply(df_AB, identical, 1:5)
a b
TRUE FALSE
Como puede ver, en ambos marcos de datos los valores en la primera columna son idénticos a 1:5
.