La diferencia entre corchete [ ] y doble corchete [[ ]] para acceder a los elementos de una lista o marco de datos

StackOverflow https://stackoverflow.com/questions/1169456

Pregunta

R proporciona dos métodos diferentes para acceder a los elementos de una lista o marco de datos: el [] y [[]] operadores.

¿Cuál es la diferencia entre los dos?¿En qué situaciones debo utilizar uno sobre el otro?

¿Fue útil?

Solución

La definición R Idioma es útil para responder a este tipo de preguntas:

R tiene tres operadores básicos de indexación, la sintaxis que se muestra en los siguientes ejemplos

    x[i]
    x[i, j]
    x[[i]]
    x[[i, j]]
    x$a
    x$"a"

Para los vectores y matrices las formas [[ rara vez se utilizan, aunque tienen algunas ligeras diferencias semánticas de la forma [ (por ejemplo, se cae ningún nombre o atributo dimnames, y que la igualación parcial se utiliza para los índices de caracteres). Al indexar estructuras multidimensionales con un índice único, x[[i]] o x[i] devolverá el elemento secuencial ith de x.

Para listas, uno generalmente utiliza [[ para seleccionar un solo elemento, mientras que [ devuelve una lista de los elementos seleccionados.

La forma [[ permite que sólo un único elemento para ser seleccionado usando índices enteros o de caracteres, mientras que [ permite la indexación por vectores. Nótese, sin embargo que, para una lista, el índice puede ser un vector y cada elemento del vector se aplica a su vez a la lista, el componente seleccionado, el componente seleccionado de ese componente, y así sucesivamente. El resultado es aún un solo elemento.

Otros consejos

Las diferencias significativas entre los dos métodos son la clase de los objetos regresan cuando se usan para la extracción y si pueden aceptar un intervalo de valores, o simplemente un único valor durante la asignación.

Considere el caso de la extracción de datos en la lista siguiente:

foo <- list( str='R', vec=c(1,2,3), bool=TRUE )

Digamos que nos gustaría para extraer el valor almacenado por bool de foo y utilizarlo 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 lista de clase (o data.frame si foo era un data.frame) mientras que el método [[]] devuelve objetos cuya clase se determina por el tipo de sus valores.

Por lo tanto, el uso de los resultados del método [] en 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 [] devuelve una lista y una lista no es objeto válido para pasar directamente a una declaración if(). En este caso tenemos que utilizar [[]] porque va a devolver el objeto "desnuda" 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 gama de ranuras en una lista o columnas de una trama de datos mientras que el operador [[]] se limita a acceder a un solo 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) )

decir que queremos sobrescribir los últimos dos ranuras de foo con los datos contenidos en la barra. Si tratamos de utilizar 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 es porque [[]] se limita a acceder a un solo elemento. Tenemos que utilizar []:

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 mientras que la asignación ha sido correcta, las ranuras de foo mantienen sus nombres originales.

Los soportes dobles accede a una lista elemento , mientras que un solo soporte 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"

[] 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"

A partir de Hadley Wickham:

 De Hadley Wickham

Mi modificación (en busca de mierda) para mostrar el uso de tidyverse / purrr:

 introducir descripción de la imagen aquí

Simplemente añadiendo que aquí [[ también está equipado para indexación recursiva .

Esto se insinúa en la respuesta por @JijoMatthew pero no explorado.

Como se señaló en ?"[[", 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 este no cambiar lo que debería ser su principal comida para llevar en la diferencia entre [ y [[ - a saber, que el primero se utiliza para subsetting , y Este último se utiliza para extracción elementos de la lista única.

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 @ de JijoMatthew respuesta anterior, r recuerdo:

r <- list(1:10, foo=1, far=2)

En particular, esto explica los errores que tienden a conseguir cuando mis-utilizando [[, a saber:

r[[1:3]]
  

Error en r[[1:3]]: la indexación no recursivo en el nivel 2

Desde este código en realidad trató de evaluar r[[1]][[2]][[3]], y el anidamiento de r se detiene en el nivel uno, el intento de extraer a través de la indexación recursiva fallidos de [[2]], es decir, en el nivel 2.

  

Error en r[[c("foo", "far")]]: Subíndice fuera de los límites

A continuación, R buscaba r[["foo"]][["far"]], que no existe, por lo que tenemos el subíndice error de falta de límites.

Probablemente sería un poco más útil / consistente si ambos de estos errores dieron el mismo mensaje.

Los dos son formas de creación de subconjuntos. El único soporte devolverá un subconjunto de la lista, que en sí mismo será una lista. es decir: Se puede o no puede contener más de un elementos. Por otro lado, un soporte doble devolverá un solo elemento de la lista.

soporte de -Single nos dará una lista. También podemos utilizar brazo simple si se quiere devolver varios elementos de la lista. considerar la siguiente lista: -

>r<-list(c(1:10),foo=1,far=2);

Ahora, tenga en cuenta la forma en que la lista se devuelve cuando trato de mostrarlo. I tipo R y pulse enter

>r

#the result is:-

[[1]]

 [1]  1  2  3  4  5  6  7  8  9 10

$foo

[1] 1

$far

[1] 2

Ahora vamos a ver la magia de un solo soporte: -

>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 tratamos de mostrar el valor de r en la pantalla, lo que significa el uso de un solo soporte ha vuelto una lista, donde en el índice 1 tenemos un vector de 10 elementos, entonces tenemos dos elementos más con los nombres foo y de lejos. También podemos optar por dar un solo índice o nombre del elemento como entrada para el único soporte. por ejemplo:

> r[1]

[[1]]

 [1]  1  2  3  4  5  6  7  8  9 10

En este ejemplo nos dio un índice "1" y, a cambio dieron una lista con un elemento (que es una matriz de 10 números)

> r[2]

$foo

[1] 1

En el ejemplo anterior nos dimos un índice "2" y en cambio tenemos una lista con un elemento

> r["foo"];

$foo

[1] 1

En este ejemplo hemos pasado el nombre de un elemento y, a cambio de una lista fue devuelto con un elemento.

También puede 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 los elementos "foo" y "lejos"

A cambio tenemos una lista con dos elementos.

En brazo simple corta siempre te volver otra lista con el número de elementos igual al número de elementos o número de índices que pase en el único soporte.

En contraste, un soporte doble siempre devolverá sólo un elemento. Antes de trasladarse a doble soporte de una nota a 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.

Lo haré sitio algunos ejemplos. Por favor, mantenga una nota de las palabras en negrita y volver a ella después de que haya terminado con los ejemplos siguientes:

abrazadera doble que devolverá el valor real en el índice. (Se no devolverá una lista)

  > r[[1]]

     [1]  1  2  3  4  5  6  7  8  9 10


  >r[["foo"]]

    [1] 1

para los soportes dobles si tratamos de ver más de los elementos por los que pasa un vector que dará lugar a un error sólo porque no fue construido para atender a esa necesidad, pero sólo para devolver un solo elemento.

Considere el 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

Para ayudar a los novatos navegar a través de la niebla manual, que podría ser útil para ver la notación [[ ... ]] como un colapso función - en otras palabras, es cuando lo que desea es 'obtener los datos' de un vector, o lista denominada trama de datos. Es bueno hacer esto si desea utilizar los datos de estos objetos para los 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

Ser terminológica, operador [[ extractos el elemento de una lista mientras operador [ toma subconjunto de una lista.

Para otro caso de uso concreto, utilice corchetes dobles cuando desee seleccionar un marco de datos creado por el split() función.Si no lo sabes, split() agrupa una lista/marco de datos en subconjuntos basados ​​en 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"

Además:

Tras la ENLACE de la RESPUESTA aquí.

Este es un pequeño ejemplo abordar el punto siguiente:

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])

Consulte la explicación detallada a continuación.

He utilizado un marco de datos integrado 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 encabezado y contiene los nombres de las columnas.Cada línea horizontal posterior denota una fila de datos, que comienza con el nombre de la fila y luego sigue por los datos reales.Cada miembro de datos de una fila se llama celda.

operador "[]" de corchete único

Para recuperar datos en una celda, ingresaríamos sus coordenadas de fila y columna en el operador "[]" de corchete único.Las dos coordenadas están separadas por una coma.En otras palabras, las coordenadas comienzan con la posición de la fila, luego van seguidas de una coma y terminan con la posición de la columna.El orden es importante.

Ejemplo 1: - Aquí está el valor de la celda de la primera fila, segunda columna de mtcars.

> mtcars[1, 2] 
[1] 6

Ejemplo 2: - Además, podemos usar los nombres de filas y columnas en lugar de las coordenadas numéricas.

> mtcars["Mazda RX4", "cyl"] 
[1] 6 

Operador de doble corchete "[[]]"

Hacemos referencia a una columna de marco de datos con el operador "[[]]" de doble corchete.

Ejemplo 1: - Para recuperar el vector de la novena columna del conjunto de datos integrado mtcars, escribimos mtcars[[9]].

mtcars [[9]] [1] 1 1 1 0 0 0 0 0 0 0 0 0 ...

Ejemplo 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 ...

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top