str - tipos de objetos en r
La diferencia entre el corchete[] y el corchete doble[[]] para acceder a los elementos de una lista o marco de datos (12)
R proporciona dos métodos diferentes para acceder a los elementos de una lista o data.frame- los operadores []
y [[]]
.
¿Cuál es la diferencia entre los dos? ¿En qué situaciones debo usar uno sobre el otro?
Adicionalmente:
Siguiendo el ENLACE de la RESPUESTA aquí.
Aquí hay un pequeño ejemplo que trata el siguiente punto:
x[i, j] vs x[[i, j]]
df1 <- data.frame(a = 1:3)
df1$b <- list(4:5, 6:7, 8:9)
df1[[1,2]]
df1[1,2]
str(df1[[1,2]])
str(df1[1,2])
Ambas son formas de subconjunto. El corchete único devolverá un subconjunto de la lista, que en sí misma será una lista. es decir: puede o no contener más de un elemento. Por otro lado, un soporte doble devolverá solo un elemento de la lista.
-Un solo corchete nos dará una lista. También podemos usar corchetes individuales si deseamos devolver varios elementos de la lista. Considere la siguiente lista:
>r<-list(c(1:10),foo=1,far=2);
Ahora tenga en cuenta la forma en que se devuelve la lista cuando intento mostrarla. Escribo r y presiono enter
>r
#the result is:-
[[1]]
[1] 1 2 3 4 5 6 7 8 9 10
$foo
[1] 1
$far
[1] 2
Ahora veremos la magia del soporte único: -
>r[c(1,2,3)]
#the above command will return a list with all three elements of the actual list r as below
[[1]]
[1] 1 2 3 4 5 6 7 8 9 10
$foo
[1] 1
$far
[1] 2
que es exactamente el mismo que cuando intentamos mostrar el valor de r en la pantalla, lo que significa que el uso de corchete simple ha devuelto una lista, donde en el índice 1 tenemos un vector de 10 elementos, luego tenemos dos elementos más con nombres foo y lejos También podemos optar por dar un solo índice o nombre de elemento como entrada al corchete único. p.ej:
> r[1]
[[1]]
[1] 1 2 3 4 5 6 7 8 9 10
En este ejemplo, dimos un índice "1" y a cambio obtuvimos una lista con un elemento (que es una matriz de 10 números)
> r[2]
$foo
[1] 1
En el ejemplo anterior, dimos un índice "2" y a cambio obtuvimos una lista con un elemento
> r["foo"];
$foo
[1] 1
En este ejemplo, pasamos el nombre de un elemento y, a cambio, se devolvió una lista con un elemento.
También puedes pasar un vector de nombres de elementos como:
> x<-c("foo","far")
> r[x];
$foo
[1] 1
$far
[1] 2
En este ejemplo pasamos un vector con dos nombres de elementos "foo" y "far"
A cambio conseguimos una lista con dos elementos.
En resumen, el corchete sencillo siempre le devolverá otra lista con el número de elementos igual al número de elementos o el número de índices que pasa al corchete individual.
En contraste, un soporte doble siempre devolverá solo un elemento. Antes de pasar al soporte doble una nota para tener en cuenta. NOTE:THE MAJOR DIFFERENCE BETWEEN THE TWO IS THAT SINGLE BRACKET RETURNS YOU A LIST WITH AS MANY ELEMENTS AS YOU WISH WHILE A DOUBLE BRACKET WILL NEVER RETURN A LIST. RATHER A DOUBLE BRACKET WILL RETURN ONLY A SINGLE ELEMENT FROM THE LIST.
Voy a sitio algunos ejemplos. Mantenga una nota de las palabras en negrita y vuelva a ellas una vez que haya terminado con los ejemplos a continuación:
El corchete doble le devolverá el valor real en el índice. ( NO devolverá una lista)
> r[[1]]
[1] 1 2 3 4 5 6 7 8 9 10
>r[["foo"]]
[1] 1
para los corchetes dobles, si intentamos ver más de un elemento pasando un vector, se producirá un error simplemente porque no se creó para satisfacer esa necesidad, sino solo para devolver un solo elemento.
Considera lo siguiente
> r[[c(1:3)]]
Error in r[[c(1:3)]] : recursive indexing failed at level 2
> r[[c(1,2,3)]]
Error in r[[c(1, 2, 3)]] : recursive indexing failed at level 2
> r[[c("foo","far")]]
Error in r[[c("foo", "far")]] : subscript out of bounds
La definición de lenguaje R es útil para responder a estos tipos de preguntas:
R tiene tres operadores de indexación básicos, con la sintaxis mostrada por los siguientes ejemplos
x[i] x[i, j] x[[i]] x[[i, j]] x$a x$"a"
Para vectores y matrices, las
[[
formas rara vez se usan, aunque tienen algunas diferencias semánticas leves con respecto a la[
forma (por ejemplo, elimina cualquier atributo de nombres o nombres, y esa comparación parcial se usa para los índices de caracteres). Al indexar estructuras multidimensionales con un solo índice,x[[i]]
ox[i]
devolverá eli
th elemento secuencial dex
.Para las listas, generalmente se usa
[[
para seleccionar cualquier elemento individual, mientras que[
devuelve una lista de los elementos seleccionados.La
[[
forma permite que solo un elemento sea seleccionado usando índices enteros o de caracteres, mientras que[
permite la indexación por vectores. Tenga en cuenta que para una lista, el índice puede ser un vector y cada elemento del vector se aplica a la lista, el componente seleccionado, el componente seleccionado de ese componente, etc. El resultado sigue siendo un solo elemento.
Las diferencias significativas entre los dos métodos son la clase de los objetos que devuelven cuando se usan para la extracción y si pueden aceptar un rango de valores, o solo un valor único durante la asignación.
Considere el caso de extracción de datos en la siguiente lista:
foo <- list( str=''R'', vec=c(1,2,3), bool=TRUE )
Digamos que nos gustaría extraer el valor almacenado por bool de foo y usarlo dentro de una sentencia if()
. Esto ilustrará las diferencias entre los valores de retorno de []
y [[]]
cuando se utilizan para la extracción de datos. El método []
devuelve objetos de la lista de clases (o data.frame si foo era un data.frame), mientras que el método [[]]
devuelve objetos cuya clase está determinada por el tipo de sus valores.
Entonces, usar el método []
da como resultado lo siguiente:
if( foo[ ''bool'' ] ){ print("Hi!") }
Error in if (foo["bool"]) { : argument is not interpretable as logical
class( foo[ ''bool'' ] )
[1] "list"
Esto se debe a que el método []
devolvió una lista y una lista no es un objeto válido para pasar directamente a una instrucción if()
. En este caso, necesitamos usar [[]]
porque devolverá el objeto "bare" almacenado en ''bool'' que tendrá la clase apropiada:
if( foo[[ ''bool'' ]] ){ print("Hi!") }
[1] "Hi!"
class( foo[[ ''bool'' ]] )
[1] "logical"
La segunda diferencia es que el operador []
se puede usar para acceder a un rango de ranuras en una lista o columnas en un marco de datos, mientras que el operador [[]]
está limitado a acceder a una única ranura o columna. Considere el caso de asignación de valor utilizando una segunda lista, bar()
:
bar <- list( mat=matrix(0,nrow=2,ncol=2), rand=rnorm(1) )
Digamos que queremos sobrescribir las dos últimas ranuras de Foo con los datos contenidos en la barra. Si intentamos usar el operador [[]]
, esto es lo que sucede:
foo[[ 2:3 ]] <- bar
Error in foo[[2:3]] <- bar :
more elements supplied than there are to replace
Esto se debe a que [[]]
está limitado a acceder a un solo elemento. Necesitamos usar []
:
foo[ 2:3 ] <- bar
print( foo )
$str
[1] "R"
$vec
[,1] [,2]
[1,] 0 0
[2,] 0 0
$bool
[1] -0.6291121
Tenga en cuenta que aunque la asignación fue exitosa, las ranuras en foo mantuvieron sus nombres originales.
Los corchetes dobles acceden a un elemento de la lista, mientras que un corchete sencillo le devuelve una lista con un solo elemento.
lst <- list(''one'',''two'',''three'')
a <- lst[1]
class(a)
## returns "list"
a <- lst[[1]]
class(a)
## returns "character"
Para ayudar a los novatos a navegar a través de la niebla manual, puede ser útil ver la [[ ... ]]
notación como una función de colapsado ; en otras palabras, es cuando solo desea "obtener los datos" de un vector con nombre, lista o marco de datos. Es bueno hacer esto si desea usar datos de estos objetos para cálculos. Estos ejemplos simples ilustrarán.
(x <- c(x=1, y=2)); x[1]; x[[1]]
(x <- list(x=1, y=2, z=3)); x[1]; x[[1]]
(x <- data.frame(x=1, y=2, z=3)); x[1]; x[[1]]
Así que desde el tercer ejemplo:
> 2 * x[1]
x
1 2
> 2 * x[[1]]
[1] 2
Para otro caso de uso concreto, use corchetes dobles cuando desee seleccionar un marco de datos creado por la función split()
. Si no lo sabe, split()
agrupa una lista / marco de datos en subconjuntos según un campo clave. Es útil si desea operar en varios grupos, trazarlos, etc.
> class(data)
[1] "data.frame"
> dsplit<-split(data, data$id)
> class(dsplit)
[1] "list"
> class(dsplit[''ID-1''])
[1] "list"
> class(dsplit[[''ID-1'']])
[1] "data.frame"
Por favor, consulte la explicación detallada a continuación.
He usado el marco de datos incorporado en R, llamado mtcars.
> mtcars
mpg cyl disp hp drat wt ...
Mazda RX4 21.0 6 160 110 3.90 2.62 ...
Mazda RX4 Wag 21.0 6 160 110 3.90 2.88 ...
Datsun 710 22.8 4 108 93 3.85 2.32 ...
............
La línea superior de la tabla se llama el encabezado que contiene los nombres de columna. Cada línea horizontal después denota una fila de datos, que comienza con el nombre de la fila y luego sigue con los datos reales. Cada miembro de datos de una fila se llama celda.
Operador de corchete simple "[]"
Para recuperar datos en una celda, deberíamos ingresar sus coordenadas de fila y columna en el operador "[]" de corchete simple. Las dos coordenadas están separadas por una coma. En otras palabras, las coordenadas comienzan con la posición de la fila, luego siguen con una coma y terminan con la posición de la columna. El orden es importante.
Ej. 1: - Aquí está el valor de celda de la primera fila, la segunda columna de mtcars.
> mtcars[1, 2]
[1] 6
Ej. 2: - Además, podemos usar los nombres de fila y columna en lugar de las coordenadas numéricas.
> mtcars["Mazda RX4", "cyl"]
[1] 6
Doble corchete "[[]]" operador
Hacemos referencia a una columna de marco de datos con el operador de corchete doble "[[]]".
Ej .: 1: para recuperar el noveno vector de columna del conjunto de datos integrado mtcars, escribimos mtcars [[9]].
mtcars [[9]] [1] 1 1 1 0 0 0 0 0 0 0 0 ...
Ej. 2: - Podemos recuperar el mismo vector de columna por su nombre.
mtcars [["am"]] [1] 1 1 1 0 0 0 0 0 0 0 0 ...
Siendo terminológico, [[
operador extrae el elemento de una lista mientras que [
operador toma un subconjunto de una lista.
Solo agregando aquí que [[
también está equipado para indexación recursiva .
Esto fue insinuado en la respuesta por @JijoMatthew pero no fue explorado.
Como se indica en ?"[["
, La sintaxis como x[[y]]
, donde length(y) > 1
, se interpreta como:
x[[ y[1] ]][[ y[2] ]][[ y[3] ]] ... [[ y[length(y)] ]]
Tenga en cuenta que esto no cambia lo que debería ser su principal conclusión sobre la diferencia entre [
y [[
saber, que el primero se usa para subconjuntos y el último para extraer elementos de una sola lista.
Por ejemplo,
x <- list(list(list(1), 2), list(list(list(3), 4), 5), 6)
x
# [[1]]
# [[1]][[1]]
# [[1]][[1]][[1]]
# [1] 1
#
# [[1]][[2]]
# [1] 2
#
# [[2]]
# [[2]][[1]]
# [[2]][[1]][[1]]
# [[2]][[1]][[1]][[1]]
# [1] 3
#
# [[2]][[1]][[2]]
# [1] 4
#
# [[2]][[2]]
# [1] 5
#
# [[3]]
# [1] 6
Para obtener el valor 3, podemos hacer:
x[[c(2, 1, 1, 1)]]
# [1] 3
Volviendo a la respuesta de @JijoMatthew anterior, recuerde r
:
r <- list(1:10, foo=1, far=2)
En particular, esto explica los errores que tendemos a obtener cuando se usa mal [[
, a saber:
r[[1:3]]
Error en
r[[1:3]]
: la indexación recursiva falló en el nivel 2
Dado que este código realmente intentó evaluar r[[1]][[2]][[3]]
, y el anidamiento de r
detiene en el nivel uno, el intento de extracción mediante indexación recursiva falló en [[2]]
, es decir , en el nivel 2.
Error en
r[[c("foo", "far")]]
: subíndice fuera de límites
Aquí, R estaba buscando r[["foo"]][["far"]]
, que no existe, por lo que obtenemos el error del subíndice fuera de límites.
Probablemente sería un poco más útil / coherente si ambos errores dieran el mismo mensaje.
[]
extrae una lista, [[]]
extrae elementos dentro de la lista
alist <- list(c("a", "b", "c"), c(1,2,3,4), c(8e6, 5.2e9, -9.3e7))
str(alist[[1]])
chr [1:3] "a" "b" "c"
str(alist[1])
List of 1
$ : chr [1:3] "a" "b" "c"
str(alist[[1]][1])
chr "a"