326 votos

Cómo usar correctamente las listas de R?

Breve resumen de la experiencia: Muchos (la mayoría?) contemporáneo de los lenguajes de programación de uso generalizado tiene al menos un puñado de Tdas [tipos de datos abstractos] en común, en particular,

  • cadena (un (secuencia compuesta de caracteres)

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

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

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

Cuando empecé a aprender el R, dos cosas eran evidentes, casi desde el inicio: Lista es el más importante tipo de datos en R (porque es la clase padre de la R Marco de Datos), y segundo, yo no podía entender cómo funcionan, al menos no lo suficientemente bien como para utilizarlas correctamente en mi código.

Por un lado, me parecía que la R de la Lista tipo de datos de una aplicación sencilla del mapa ADT (diccionario en Python, NSMutableDictionary en Objective C, hash en Perl y Ruby, literal de objeto en Javascript, y así sucesivamente).

Por ejemplo, puedes crear tal como lo haría un diccionario de Python, pasando por pares clave-valor a un constructor (que en Python se dict no lista):

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

Y tener acceso a los elementos de un R Lista igual que los de un diccionario de Python, por ejemplo, x['ev1']. Del mismo modo, usted puede recuperar sólo las " llaves " o sólo a los 'valores':

>>> names(x)    # fetch just the 'keys' of an R list
      "ev1" "ev2" "rv"

>>> unlist(x)   # fetch just the 'values' of an R list
      10 15 "Group1"

>>> x = list("a"=6, "b"=9, "c"=3)  

>>> sum(unlist(x))
      18

pero R Listas también a diferencia de otras de tipo mapa de Tdas (de entre los idiomas que he aprendido de todos modos). Mi conjetura es que esto es una consecuencia de la inicial de especificaciones de S, es decir, la intención de diseñar un data/statistics ADSL [de dominio-lengua] desde el suelo -.

tres diferencias significativas entre R y Listas de asignación de tipos en otros idiomas de uso generalizado (por ejemplo,. Python, Perl, JavaScript):

primero, en las Listas de R son una ordenada colección, igual que los vectores, incluso a pesar de que los valores están codificados (es decir, las claves pueden ser de cualquier hashable valor no sólo secuencial de números enteros). Casi siempre, la asignación de tipo de datos en otros idiomas es desordenada.

segundo, las Listas pueden ser devueltos a partir de funciones aunque nunca pasó en una Lista cuando se llama a la función, y aunque la función que devuelve la lista no contiene un (explícita) de la Lista de constructor (por supuesto, usted puede lidiar con esto, en la práctica, envolviendo el resultado devuelto por una llamada a unlist):

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

>>> class(x)                            # returns 'list', not a vector of length 2
      list

Un tercer rasgo peculiar de R Listas: parece que no se puede ser miembros de otra ADT, y si tratamos de hacer eso, entonces el contenedor primario es obligada a una lista. Por ej.,

>>> x = c(0.5, 0.8, 0.23, list(0.5, 0.2, 0.9), recursive=T)

>>> class(x)
      list

mi intención aquí no es criticar el lenguaje o cómo está documentado; asimismo, no estoy sugiriendo que no hay nada malo con la Lista estructura de datos o cómo se comporta. Todos lo que busco es correcto, es mi entendimiento de cómo funcionan, de modo que puedo usar correctamente en mi código.

Aquí son el tipo de cosas que me gustaría entender mejor:

  • ¿Cuáles son las reglas que determinan cuando una llamada a la función devolverá una Lista (p. ej., strsplit expresión citadas anteriormente)?

  • Si yo no se especifican los nombres de una lista (por ej., lista(10,20,30,40)) son los nombres por defecto sólo enteros secuenciales que empieza con el 1? (Supongo, pero estoy muy lejos de la certeza de que la respuesta es sí, de lo contrario no sería capaz de obligar a este tipo de Lista a un vector w/ una llamada a unlist.

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

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

    ambas expresiones de retorno "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 apunto a la R de la Documentación--he leído atentamente y no me ayudan a contestar el tipo de preguntas que me recitó justo encima.

(por último, recientemente se enteró y comenzó a usar un Paquete de R (disponible en CRAN) llamado hash que implementa convencional de tipo mapa de comportamiento a través de un S4 clase; ciertamente puedo recomendar este Paquete.)

152voto

Shane Puntos 40885

Sólo para afrontar la última parte de su pregunta, ya que realmente señala la diferencia entre un list y 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 de cada elemento. Así que usted puede tener una lista donde el primer elemento es un personaje de vectores, la segunda es una estructura de datos, etc. En este caso, se han 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 estos son completamente diferentes listas.

R listas son muy similares a las de un hash del mapa de estructura de datos en la que cada valor del índice puede ser asociado con cualquier objeto. He aquí un simple ejemplo 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, la llamo así:

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

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

Una estructura de datos es una lista de variables con el mismo número de filas con una única fila de nombres, dado la clase"data.frame"'

Es por eso que las columnas en un data.frame puede tener diferentes tipos de datos, mientras que las columnas de una matriz no. Como ejemplo, aquí trato de 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"

Nota cómo puedo cambiar el tipo de datos en la primera columna numérica debido a la segunda columna tiene caracteres:

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

64voto

Dirk Eddelbuettel Puntos 134700

Con respecto a tus preguntas, permítanme hablar de ellos en el orden y dar algunos ejemplos:

1) Una lista que se devuelve si y cuando la instrucción return, añade. Considere la posibilidad de

 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) Nombres son simplemente no se establece:

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

3) no devolver la misma cosa. Su ejemplo se da a

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 el mismo que x. Cada escalar es un vector de longitud uno. En el otro lado, x[[1]] devuelve el primer elemento de la lista.

4) por último, los dos son diferentes entre los que se crean, respectivamente, en una lista que contiene cuatro escalares y una lista con un solo elemento (que pasa a ser un vector de cuatro elementos).

35voto

JD Long Puntos 20477

Sólo para tomar un subconjunto de sus preguntas:

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

En breve [[]] selecciona un elemento de una lista y [] devuelve una lista de los elementos seleccionados. En tu ejemplo, x = list(1, 2, 3, 4)' elemento 1 es un número entero, pero x[[1]] devuelve un 1 y x[1] devuelve una lista con un único valor.

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

> x[[1]]
[1] 1

13voto

Alex Brown Puntos 15776

Una de las razones listas de trabajo como lo hacen (ordenadas) frente a la necesidad de un orden de contenedor que puede contener cualquier tipo en cualquier nodo, que los vectores no hacer. Las listas son re-utilizados para una variedad de propósitos en R, incluyendo 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)

Añadir a @Shane respuesta, si quería obtener el mismo resultado, pruebe:

x3 = as.list(1:4)

Que coacciona el vector 1:4 en una lista.

11voto

Shane Puntos 40885

Acaba de agregar un punto más a esto:

R tiene una estructura de datos equivalente a la de Python dict en la hash paquete. Usted puede leer sobre él en este blog a partir de los Datos Abiertos de Grupo. He aquí 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 facilidad de uso, la hash de la clase es muy similar a una lista. Pero el rendimiento es mejor para grandes conjuntos de datos.

Iteramos.com

Iteramos es una comunidad de desarrolladores que busca expandir el conocimiento de la programación mas allá del inglés.
Tenemos una gran cantidad de contenido, y también puedes hacer tus propias preguntas o resolver las de los demás.

Powered by:

X