Respuestas:
La definición del lenguaje R es útil para responder a este tipo de preguntas:
R tiene tres operadores de indexación básicos, con la sintaxis mostrada en los siguientes ejemplos
x[i] x[i, j] x[[i]] x[[i, j]] x$a x$"a"
Para los vectores y las matrices, las
[[
formas rara vez se usan, aunque tienen algunas diferencias semánticas leves de la[
forma (por ejemplo, elimina cualquier atributo de nombres o nombres oscuros, y esa coincidencia parcial se usa para los índices de caracteres). Al indexar estructuras multidimensionales con un solo índice,x[[i]]
ox[i]
devolverá eli
elemento secuencial dex
.Para las listas, generalmente se usa
[[
para seleccionar cualquier elemento individual, mientras que[
devuelve una lista de los elementos seleccionados.El
[[
formulario permite seleccionar un solo elemento utilizando índices enteros o de caracteres, mientras que[
permite la indexación por vectores. Sin embargo, tenga en cuenta 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, etc. El resultado sigue siendo un solo elemento.
[
siempre una lista significa que obtienes la misma clase de salida x[v]
independientemente de la longitud de v
. Por ejemplo, uno podría querer lapply
más de un subconjunto de una lista: lapply(x[v], fun)
. Si [
descartara la lista de vectores de longitud uno, devolvería un error siempre que v
tenga longitud uno.
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 solo valor durante la asignación.
Considere el caso de la 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 if()
declaración. Esto ilustrará las diferencias entre los valores de retorno de []
y [[]]
cuándo se usan 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 if()
declaración. En este caso, debemos usarlo [[]]
porque devolverá el objeto "desnudo" 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 puede usarse 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 sola 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 si bien la asignación fue exitosa, las máquinas tragamonedas en foo mantuvieron sus nombres originales.
Los paréntesis dobles acceden a un elemento de la lista , mientras que un paréntesis simple 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"
Simplemente agregue aquí que [[
también está equipado para indexación recursiva .
Esto fue insinuado en la respuesta por @JijoMatthew pero no fue explorado.
Como se señaló en ?"[["
, la sintaxis like x[[y]]
, where 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 conclusión principal sobre la diferencia entre [
y [[
, a saber, que el primero se usa para subconjuntos , y el segundo se usa para extraer elementos de 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 la respuesta de @ JijoMatthew anterior, recuerde r
:
r <- list(1:10, foo=1, far=2)
En particular, esto explica los errores que solemos tener cuando usamos mal [[
, a saber:
r[[1:3]]
Error en
r[[1:3]]
: error de indexación recursiva en el nivel 2
Dado que este código realmente trató de evaluar r[[1]][[2]][[3]]
, y la anidación de las r
paradas en el nivel uno, el intento de extraer a través de la indexación recursiva falló [[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"]]
, lo que no existe, por lo que obtenemos el error de subíndice fuera de los límites.
Probablemente sería un poco más útil / coherente si ambos errores transmitieran el mismo mensaje.
Ambos son formas de subconjuntos. El paréntesis simple devolverá un subconjunto de la lista, que en sí mismo será una lista. es decir: puede contener o no más de un elemento. Por otro lado, un paréntesis doble devolverá solo un elemento de la lista.
- Un solo soporte nos dará una lista. También podemos usar un solo paréntesis si deseamos devolver múltiples 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 corchete simple: -
>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 lo mismo que cuando intentamos mostrar el valor de r en la pantalla, lo que significa que el uso de un solo parche 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 paréntesis único. p.ej:
> r[1]
[[1]]
[1] 1 2 3 4 5 6 7 8 9 10
En este ejemplo le 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 le 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 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 elementos "foo" y "far"
A cambio tenemos una lista con dos elementos.
En resumen, el paréntesis simple siempre le devolverá otra lista con una cantidad de elementos igual a la cantidad de elementos o la cantidad de índices que pasa en la horquilla individual.
Por el contrario, un paréntesis doble siempre devolverá solo un elemento. Antes de pasar al doble paréntesis, 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.
Encontraré algunos ejemplos. Mantenga una nota de las palabras en negrita y vuelva a leerlas una vez que haya terminado con los ejemplos a continuación:
El paréntesis 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 corchetes dobles si intentamos ver más de un elemento pasando un vector, se producirá un error solo 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
[]
devuelva una clase de lista incluso si es un solo dígito es muy poco intuitivo. Deberían haber creado otra sintaxis como ([])
para la lista y [[]]
acceder al elemento real está bien. Prefiero pensar [[]]
en el valor bruto como en otros idiomas.
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 colapso ; en otras palabras, es cuando solo desea 'obtener los datos' de un vector, lista o marco de datos con nombre. Es bueno hacer esto si desea utilizar 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]]
Entonces, del tercer ejemplo:
> 2 * x[1]
x
1 2
> 2 * x[[1]]
[1] 2
iris[[1]]
devuelve un vector, mientras que iris[1]
devuelve un data.frame
Al ser terminológico, el [[
operador extrae el elemento de una lista, mientras que el [
operador toma un subconjunto de una lista.
Para otro caso de uso concreto, use corchetes dobles cuando desee seleccionar un marco de datos creado por la split()
función. Si no sabe, split()
agrupa un marco de lista / datos en subconjuntos basados en un campo clave. Es útil si cuando desea operar en múltiples 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"
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 encabezado que contiene los nombres de las columnas. Cada línea horizontal luego 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.
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, seguidas de una coma y terminan con la posición de la columna. El orden es importante.
Por ejemplo, 1: - Aquí está el valor de celda de la primera fila, segunda columna de mtcars.
> mtcars[1, 2]
[1] 6
Por ejemplo, 2: - Además, podemos usar los nombres de fila y columna en lugar de las coordenadas numéricas.
> mtcars["Mazda RX4", "cyl"]
[1] 6
Hacemos referencia a una columna de marco de datos con el operador de corchete doble "[[]]".
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 ...
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 ...