varias tablas listas leer infinito graficas filtrar filas eliminar datos columna agregar r list data-structures language-features abstract-data-type

listas - tablas en r



¿Cómo utilizar correctamente las listas en R? (11)

¿por qué estos dos operadores diferentes, [ ] y [[ ]] , devuelven el mismo resultado?

x = list(1, 2, 3, 4)

  1. [ ] proporciona sub operación de ajuste. En general, el subconjunto de cualquier objeto tendrá el mismo tipo que el objeto original. Por lo tanto, x[1] proporciona una lista. De manera similar, x[1:2] es un subconjunto de la lista original, por lo tanto, es una lista. Ex.

    x[1:2] [[1]] [1] 1 [[2]] [1] 2

  2. [[ ]] es para extraer un elemento de la lista. x[[1]] es válido y extrae el primer elemento de la lista. x[[1:2]] no es válido ya que [[ ]] no proporciona una configuración secundaria como [ ] .

    x[[2]] [1] 2 > x[[2:3]] Error in x[[2:3]] : subscript out of bounds

Breve resumen: muchos (la mayoría?) Lenguajes de programación contemporáneos de uso generalizado tienen al menos un puñado de ADT [tipos de datos abstractos] en común,

  • cadena (una secuencia compuesta de caracteres)

  • lista (una colección ordenada de valores), y

  • tipo basado en mapas (una matriz desordenada que asigna claves a valores)

En el lenguaje de programación R, los dos primeros se implementan como character y vector , respectivamente.

Cuando comencé a aprender R, dos cosas eran obvias casi desde el principio: list es el tipo de datos más importante en R (porque es la clase principal para el data.frame R), y segundo, simplemente no pude entender cómo Funcionó, al menos no lo suficiente como para usarlos correctamente en mi código.

Por un lado, me pareció que el tipo de datos de la list de R era una implementación directa del mapa ADT ( dictionary en Python, NSMutableDictionary en Objective C, hash en Perl y Ruby, object literal en Javascript, etc.).

Por ejemplo, los creas como lo harías con un diccionario de Python, al pasar pares clave-valor a un constructor (que en Python no está en la list dict ):

x = list("ev1"=10, "ev2"=15, "rv"="Group 1")

Y accede a los elementos de una Lista R como lo haría con los de un diccionario de Python, por ejemplo, x[''ev1''] . Del mismo modo, puede recuperar solo las ''claves'' o solo los ''valores'' mediante:

names(x) # fetch just the ''keys'' of an R list # [1] "ev1" "ev2" "rv" unlist(x) # fetch just the ''values'' of an R list # ev1 ev2 rv # "10" "15" "Group 1" x = list("a"=6, "b"=9, "c"=3) sum(unlist(x)) # [1] 18

pero las R list s también son diferentes a otras ADT de tipo mapa (de entre los idiomas que he aprendido de todos modos). Mi conjetura es que esto es una consecuencia de la especificación inicial para S, es decir, la intención de diseñar un DSL de datos / estadísticas [lenguaje específico del dominio] desde el principio.

tres diferencias significativas entre las list R y los tipos de mapeo en otros idiomas de uso generalizado (por ejemplo, Python, Perl, JavaScript):

Primero , la list s en R es una colección ordenada , al igual que los vectores, aunque los valores están marcados (es decir, las claves pueden ser cualquier valor de hashable, no solo enteros secuenciales). Casi siempre, el tipo de datos de mapeo en otros idiomas no está ordenado .

en segundo lugar , las list pueden devolverse desde las funciones aunque nunca haya pasado en una list cuando llamó a la función, y aunque la función que devolvió la list no contiene un constructor de list (explícito) (Por supuesto, puede tratar con esto en la práctica envolviendo el resultado devuelto en una llamada para unlist )

x = strsplit(LETTERS[1:10], "") # passing in an object of type ''character'' class(x) # returns ''list'', not a vector of length 2 # [1] list

Una tercera característica peculiar de las listas de R: no parece que puedan ser miembros de otro ADT, y si intentas hacerlo, el contenedor primario se convierte en una list . P.ej,

x = c(0.5, 0.8, 0.23, list(0.5, 0.2, 0.9), recursive=TRUE) class(x) # [1] list

mi intención aquí no es criticar el lenguaje o cómo está documentado; Del mismo modo, no estoy sugiriendo que haya algún problema con la estructura de datos de la list o cómo se comporta. Todo lo que busco es corregir mi comprensión de cómo funcionan para poder usarlos correctamente en mi código.

Aquí están los tipos de cosas que me gustaría entender mejor:

  • ¿Cuáles son las reglas que determinan cuándo una llamada de función devolverá una list (por ejemplo, la expresión strsplit recitada anteriormente)?

  • Si no asigno explícitamente nombres a una list (p. Ej., list(10,20,30,40) ), ¿son los nombres predeterminados solo enteros secuenciales que comienzan con 1? (Supongo, pero no estoy seguro de que la respuesta sea sí, de lo contrario, no podríamos forzar este tipo de list a un vector con una llamada para unlist ).

  • ¿Por qué estos dos operadores diferentes, [] y [[]] , devuelven el mismo resultado?

    x = list(1, 2, 3, 4)

    ambas expresiones devuelven "1":

    x[1]

    x[[1]]

  • ¿Por qué estas dos expresiones no devuelven el mismo resultado?

    x = list(1, 2, 3, 4)

    x2 = list(1:4)

Por favor, no me apunte a la Documentación R ( ?list , R-intro ). Lo leí con cuidado y no me ayuda a responder el tipo de preguntas que recité anteriormente.

(por último, hace poco aprendí y comencé a usar un Paquete R (disponible en CRAN) llamado hash que implementa el comportamiento de tipo de mapa convencional a través de una clase S4; ciertamente puedo recomendar este Paquete).


Aunque esta es una pregunta bastante antigua, debo decir que está tocando exactamente el conocimiento que me faltaba durante mis primeros pasos en R, es decir, cómo expresar los datos en mi mano como objeto en R o cómo seleccionar objetos existentes. No es fácil para un principiante de R pensar "en una caja de R" desde el principio.

Entonces, yo mismo comencé a usar muletas a continuación, lo que me ayudó mucho a descubrir qué objeto usar para qué datos y, básicamente, a imaginar el uso del mundo real.

Aunque no ofrezco respuestas exactas a la pregunta, el breve texto a continuación puede ayudar al lector que acaba de comenzar con R y está haciendo preguntas similares.

  • Vector atómico ... Llamé a esa "secuencia" para mí, sin dirección, solo secuencia de los mismos tipos. [ subconjuntos.
  • Vector ... secuencia con una dirección desde 2D, [ subconjuntos.
  • Matriz ... conjunto de vectores con la misma longitud formando filas o columnas, [ subconjuntos por filas y columnas, o por secuencia.
  • Matrices ... matrices en capas formando 3D
  • Dataframe ... una tabla 2D como en Excel, donde puedo ordenar, agregar o eliminar filas o columnas o hacer arit. Operaciones con ellos, solo después de algún tiempo realmente reconocí que el marco de datos es una implementación inteligente de la list en la que puedo crear subconjuntos usando [ por filas y columnas, pero incluso usando [[ .
  • Lista ... para ayudarme a mí mismo, pensé en la lista a partir de tree structure de tree structure donde [i] selecciona y devuelve ramas completas y [[i]] devuelve un elemento de la rama. Y debido a que es una tree like structure forma de tree like structure , incluso puede usar una index sequence para tratar cada hoja en una list muy compleja usando su [[index_vector]] . Las listas pueden ser simples o muy complejas y pueden combinar varios tipos de objetos en uno solo.

Entonces, para las lists , puede terminar con más formas de seleccionar una leaf dependiendo de la situación, como en el siguiente ejemplo.

l <- list("aaa",5,list(1:3),LETTERS[1:4],matrix(1:9,3,3)) l[[c(5,4)]] # selects 4 from matrix using [[index_vector]] in list l[[5]][4] # selects 4 from matrix using sequential index in matrix l[[5]][1,2] # selects 4 from matrix using row and column in matrix

Esta forma de pensar me ayudó mucho.


Con respecto a los vectores y el concepto hash / array de otros lenguajes:

  1. Los vectores son los átomos de R. Por ejemplo, rpois(1e4,5) (5 números aleatorios), numeric(55) (longitud-55 vector cero sobre dobles), y character(12) (12 cadenas vacías), son todos "básicos ".

  2. Cualquiera de las listas o vectores pueden tener names .

    > n = numeric(10) > n [1] 0 0 0 0 0 0 0 0 0 0 > names(n) NULL > names(n) = LETTERS[1:10] > n A B C D E F G H I J 0 0 0 0 0 0 0 0 0 0

  3. Los vectores requieren que todo sea del mismo tipo de datos. Ver este:

    > i = integer(5) > v = c(n,i) > v A B C D E F G H I J 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 > class(v) [1] "numeric" > i = complex(5) > v = c(n,i) > class(v) [1] "complex" > v A B C D E F G H I J 0+0i 0+0i 0+0i 0+0i 0+0i 0+0i 0+0i 0+0i 0+0i 0+0i 0+0i 0+0i 0+0i 0+0i 0+0i

  4. Las listas pueden contener diferentes tipos de datos, como se ve en otras respuestas y la pregunta del OP en sí.

He visto idiomas (ruby, javascript) en los que los "arreglos" pueden contener tipos de datos variables, pero, por ejemplo, en C ++, los "arreglos" deben ser todos del mismo tipo de datos. Creo que esto es una numeric(1e6) velocidad / eficiencia: si tiene un número numeric(1e6) sabe su tamaño y la ubicación de cada elemento a priori ; Si la cosa puede contener "Flying Purple People Eaters" en una porción desconocida, entonces realmente tienes que analizar cosas para saber hechos básicos sobre ello.

Ciertas operaciones R estándar también tienen más sentido cuando se garantiza el tipo. Por ejemplo, cumsum(1:9) tiene sentido, mientras que cumsum(list(1,2,3,4,5,''a'',6,7,8,9)) no lo tiene, sin que se garantice que el tipo sea el doble.

En cuanto a su segunda pregunta:

Las listas pueden devolverse desde las funciones aunque nunca haya pasado una Lista cuando llamó a la función

Las funciones devuelven diferentes tipos de datos de los que se ingresan todo el tiempo. plot devuelve un plot a pesar de que no toma un plot como entrada. Arg devuelve un valor numeric a pesar de que acepta un complex . Etc.

(Y en cuanto a strsplit : el código fuente está here .)


Con respecto a sus preguntas, permítanme abordarlas en orden y dar algunos ejemplos:

1 ) Se devuelve una lista siempre y cuando la declaración de retorno agregue una. Considerar

R> retList <- function() return(list(1,2,3,4)); class(retList()) [1] "list" R> notList <- function() return(c(1,2,3,4)); class(notList()) [1] "numeric" R>

2 ) Los nombres simplemente no están establecidos:

R> retList <- function() return(list(1,2,3,4)); names(retList()) NULL R>

3 ) No devuelven lo mismo. Tu ejemplo da

R> x <- list(1,2,3,4) R> x[1] [[1]] [1] 1 R> x[[1]] [1] 1

donde x[1] devuelve el primer elemento de x , que es lo mismo que x . Cada escalar es un vector de longitud uno. Por otro lado, x[[1]] devuelve el primer elemento de la lista.

4 ) Por último, los dos son diferentes entre ellos crean, respectivamente, una lista que contiene cuatro escalares y una lista con un solo elemento (que es un vector de cuatro elementos).


Si ayuda, tiendo a concebir las "listas" en R como "registros" en otros idiomas pre-OO:

  • no hacen ninguna suposición sobre un tipo general (o más bien está disponible el tipo de todos los registros posibles de cualquier aridad y nombres de campo).
  • sus campos pueden ser anónimos (luego se accede a ellos por orden de definición estricto).

El nombre "registro" entraría en conflicto con el significado estándar de "registros" (también conocido como filas) en el lenguaje de la base de datos, y puede ser por eso que su nombre se sugirió: como listas (de campos).


Solo para abordar la última parte de su pregunta, ya que realmente señala la diferencia entre una list y un vector en R:

¿Por qué estas dos expresiones no devuelven el mismo resultado?

x = lista (1, 2, 3, 4); x2 = lista (1: 4)

Una lista puede contener cualquier otra clase como cada elemento. Por lo tanto, puede tener una lista donde el primer elemento es un vector de caracteres, el segundo es un marco de datos, etc. En este caso, ha creado dos listas diferentes. x tiene cuatro vectores, cada uno de longitud 1. x2 tiene 1 vector de longitud 4:

> length(x[[1]]) [1] 1 > length(x2[[1]]) [1] 4

Así que estas son listas completamente diferentes.

Las listas R son muy parecidas a una estructura de datos de mapa hash en que cada valor de índice puede asociarse con cualquier objeto. Aquí hay un ejemplo simple de una lista que contiene 3 clases diferentes (incluyendo una función):

> complicated.list <- list("a"=1:4, "b"=1:3, "c"=matrix(1:4, nrow=2), "d"=search) > lapply(complicated.list, class) $a [1] "integer" $b [1] "integer" $c [1] "matrix" $d [1] "function"

Dado que el último elemento es la función de búsqueda, puedo llamarlo así:

> complicated.list[["d"]]() [1] ".GlobalEnv" ...

Como comentario final sobre esto: se debe tener en cuenta que un data.frame es realmente una lista (de la documentación de data.frame ):

Un marco de datos es una lista de variables del mismo número de filas con nombres de fila únicos, dada la clase ''"data.frame"''

Es por eso que las columnas en un data.frame pueden tener diferentes tipos de datos, mientras que las columnas en una matriz no pueden. A modo de ejemplo, aquí intento crear una matriz con números y caracteres:

> a <- 1:4 > class(a) [1] "integer" > b <- c("a","b","c","d") > d <- cbind(a, b) > d a b [1,] "1" "a" [2,] "2" "b" [3,] "3" "c" [4,] "4" "d" > class(d[,1]) [1] "character"

Observe cómo no puedo cambiar el tipo de datos en la primera columna a numérico porque la segunda columna tiene caracteres:

> d[,1] <- as.numeric(d[,1]) > class(d[,1]) [1] "character"


Solo para agregar un punto más a esto:

R tiene una estructura de datos equivalente al dictado de Python en el paquete hash . Puedes leer sobre esto en esta publicación de blog del Open Data Group . Aquí hay un ejemplo simple:

> library(hash) > h <- hash( keys=c(''foo'',''bar'',''baz''), values=1:3 ) > h[c(''foo'',''bar'')] <hash> containing 2 key-value pairs. bar : 2 foo : 1

En términos de usabilidad, la clase hash es muy similar a una lista. Pero el rendimiento es mejor para grandes conjuntos de datos.


Solo para tomar un subconjunto de sus preguntas:

Este artículo sobre indexación aborda la cuestión de la diferencia entre [] y [[]] .

En resumen, [[]] selecciona un solo elemento de una lista y [] devuelve una lista de los elementos seleccionados. En su ejemplo, x = list(1, 2, 3, 4)'' elemento 1 es un solo entero, pero x[[1]] devuelve un solo 1 x[1] devuelve una lista con solo un valor.

> x = list(1, 2, 3, 4) > x[1] [[1]] [1] 1 > x[[1]] [1] 1


Tu dices:

Por otro lado, las listas pueden devolverse desde las funciones aunque nunca haya pasado en una Lista cuando llamó a la función, y aunque la función no contiene un constructor de Lista, por ejemplo,

x = strsplit(LETTERS[1:10], "") # passing in an object of type ''character'' class(x) # => ''list''

Y supongo que sugieres que esto es un problema (?). Estoy aquí para decirte por qué no es un problema :-). Su ejemplo es un poco simple, ya que cuando hace la división de cadenas, tiene una lista con elementos que tienen 1 elemento de longitud, por lo que sabe que x[[1]] es lo mismo que unlist(x)[1] . Pero, ¿y si el resultado de strsplit resultados de diferente longitud en cada bin? Simplemente devolver un vector (vs. una lista) no funcionará en absoluto.

Por ejemplo:

stuff <- c("You, me, and dupree", "You me, and dupree", "He ran away, but not very far, and not very fast") x <- strsplit(stuff, ",") xx <- unlist(strsplit(stuff, ","))

En el primer caso ( x : que devuelve una lista), puede decir cuál fue la segunda "parte" de la tercera cadena, por ejemplo: x[[3]][2] . ¿Cómo podrías hacer lo mismo usando xx ahora que los resultados se han "desenredado" (no unlist )?


Una de las razones por las que las listas funcionan como lo hacen (ordenadas) es para satisfacer la necesidad de un contenedor ordenado que pueda contener cualquier tipo en cualquier nodo, lo que no hacen los vectores. Las listas se reutilizan para una variedad de propósitos en R, incluida la formación de la base de un data.frame , que es una lista de vectores de tipo arbitrario (pero de la misma longitud).

¿Por qué estas dos expresiones no devuelven el mismo resultado?

x = list(1, 2, 3, 4); x2 = list(1:4)

Para agregar a la respuesta de @Shane, si desea obtener el mismo resultado, intente:

x3 = as.list(1:4)

Lo que convierte al vector 1:4 en una lista.


x = list(1, 2, 3, 4) x2 = list(1:4) all.equal(x,x2)

no es lo mismo porque 1: 4 es lo mismo que c (1,2,3,4). Si quieres que sean iguales entonces:

x = list(c(1,2,3,4)) x2 = list(1:4) all.equal(x,x2)