Breve reseña: 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, en particular,
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 charactery vector, respectivamente.
Cuando comencé a aprender R, dos cosas eran obvias casi desde el principio: listes el tipo de datos más importante en R (porque es la clase principal para R data.frame), y en segundo lugar, simplemente no podía entender cómo funcionaban, al menos no lo suficientemente bien como para usarlos correctamente en mi código.
Por un lado, me pareció que el listtipo de datos de R era una implementación directa del mapa ADT ( dictionaryen Python, NSMutableDictionaryen el Objetivo C, hashen Perl y Ruby, object literalen Javascript, etc.).
Por ejemplo, los crea como si fuera un diccionario de Python, pasando pares clave-valor a un constructor (que en Python dictno lo es list):
x = list("ev1"=10, "ev2"=15, "rv"="Group 1")
Y se accede a los elementos de una lista de R al igual que lo haría con las de un diccionario de Python, por ejemplo, x['ev1']. Del mismo modo, puede recuperar solo las 'claves' o solo los 'valores' al:
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 los R listtambién son diferentes a otros ADT de tipo mapa (de todos 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, una intención de diseñar un DSL de datos / estadísticas [lenguaje específico de dominio] desde cero.
tres diferencias significativas entre R listsy tipos de mapeo en otros idiomas en uso generalizado (p. ej., Python, Perl, JavaScript):
primero , lists en R son una colección ordenada , al igual que los vectores, a pesar de que los valores están codificados (es decir, las claves pueden ser cualquier valor hashable no solo enteros secuenciales). Casi siempre, el tipo de datos de mapeo en otros idiomas no está ordenado .
segundo , lists puede ser devuelto desde funciones aunque nunca haya pasado a listcuando llamó a la función, y aunque la función que devolvió el listno contiene un listconstructor ( explícito) (Por supuesto, puede tratar esto en la práctica mediante envolviendo el resultado devuelto en 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
# [1] list
Una tercera característica peculiar de las R list: no parece que puedan ser miembros de otro ADT, y si intenta hacerlo, el contenedor primario se convierte en a 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 algo mal con la listestructura de datos 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.
Estas son las cosas que me gustaría entender mejor:
¿Cuáles son las reglas que determinan cuándo una llamada de función devolverá un
list(p. Ej.,strsplitExpresión mencionada anteriormente)?Si no asigno explícitamente nombres a
list(p. Ej.list(10,20,30,40)) , ¿ Son los nombres predeterminados solo enteros secuenciales que comienzan con 1? (Asumo, pero no estoy seguro de que la respuesta sea sí, de lo contrario no podríamos obligar a este tipolista un vector con una llamada aunlist).¿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 señale la Documentación R ( ?list, R-intro): la he leído detenidamente y no me ayuda a responder el tipo de preguntas que recité anteriormente.
(por último, recientemente me enteré y comencé a usar un paquete R (disponible en CRAN) llamado hashque implementa el comportamiento de tipo de mapa convencional a través de una clase S4; ciertamente puedo recomendar este paquete).

x = list(1, 2, 3, 4), ambos NO devuelven el mismo resultado:x[1]yx[[1]]. El primero devuelve una lista y el segundo devuelve un vector numérico. Al desplazarme a continuación, me parece que Dirk fue el único encuestado que respondió esta pregunta correctamente.listen que R no es como un hash. Tengo uno más que creo que es digno de mención.listen R puede tener dos miembros con el mismo nombre de referencia. Considere queobj <- c(list(a=1),list(a=2))es válido y devuelve una lista con dos valores con nombre de 'a'. En este caso, una solicitudobj["a"]solo devolverá el primer elemento de la lista coincidente. Puede obtener un comportamiento similar (tal vez idéntico) a un hash con solo un elemento por cada nombre de referencia utilizando entornos en R. ej .x <- new.env(); x[["a"]] <- 1; x[["a"]] <- 2; x[["a"]]Respuestas:
Sólo para hacer frente a la última parte de su pregunta, ya que realmente señala la diferencia entre una
listyvectoren I:Una lista puede contener cualquier otra clase como cada elemento. Entonces 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.
xtiene cuatro vectores, cada uno de longitud 1.x2tiene 1 vector de longitud 4:Entonces 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 (incluida una función):
Dado que el último elemento es la función de búsqueda, puedo llamarlo así:
Como comentario final sobre esto: debe tenerse en cuenta que a
data.framees realmente una lista (de ladata.framedocumentación):Es por eso que las columnas en un
data.framepueden tener diferentes tipos de datos, mientras que las columnas en una matriz no pueden. Como ejemplo, aquí trato de crear una matriz con números y caracteres:Tenga en cuenta que no puedo cambiar el tipo de datos en la primera columna a numérico porque la segunda columna tiene caracteres:
fuente
switchfunción útil en R que se puede usar para ese propósito (verhelp(switch)).Con respecto a sus preguntas, permítame abordarlas en orden y dar algunos ejemplos:
1 ) Se devuelve una lista si y cuando la instrucción return agrega uno. Considerar
2 ) Los nombres simplemente no se establecen:
3 ) No devuelven lo mismo. Tu ejemplo da
donde
x[1]devuelve el primer elemento dex, que es lo mismo quex. 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 resulta ser un vector de cuatro elementos).
fuente
Value. Como en?strsplit: "Una lista de la misma longitud que x". Pero debe considerar que puede haber una función que devuelva diferentes valores dependiendo de los argumentos (por ejemplo, sapply puede devolver una lista o un vector).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, elx = list(1, 2, 3, 4)'elemento 1 es un entero único, perox[[1]]devuelve un solo 1 yx[1]devuelve una lista con un solo valor.fuente
A = array( 11:16, c(2,3) ); A[5]es 15, en la matriz plana ?!Una razón por la que las listas funcionan como lo hacen (ordenadas) es para abordar la necesidad de un contenedor ordenado que pueda contener cualquier tipo en cualquier nodo, que los vectores no hacen. Las listas se reutilizan para una variedad de propósitos en R, incluida la formación de la base de a
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?
Para agregar a la respuesta de @ Shane, si desea obtener el mismo resultado, intente:
Lo que obliga al vector a
1:4formar una lista.fuente
Solo para agregar un punto más a esto:
R tiene una estructura de datos equivalente al dict de Python en el
hashpaquete . Puede leer sobre esto en esta publicación de blog del Grupo de datos abiertos . Aquí hay un ejemplo simple:En términos de usabilidad, la
hashclase es muy similar a una lista. Pero el rendimiento es mejor para grandes conjuntos de datos.fuente
Tu dices:
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 realiza la división de cadenas, tiene una lista con elementos que tienen 1 elemento de largo, por lo que sabe que
x[[1]]es lo mismo queunlist(x)[1]. Pero, ¿y si el resultado destrsplitresultados devueltos de diferente longitud en cada bin. Simplemente devolver un vector (frente a una lista) no funcionará en absoluto.Por ejemplo:
En el primer caso (
x: que devuelve una lista), se puede decir lo que la segunda "parte" de la tercera cadena era, por ejemplo:x[[3]][2]. ¿Cómo podría hacer lo mismo usandoxxahora que los resultados han sido "desentrañados" (unlist-ed)?fuente
no es lo mismo porque 1: 4 es lo mismo que c (1,2,3,4). Si quieres que sean iguales, entonces:
fuente
Esta es una pregunta muy antigua, pero creo que una nueva respuesta podría agregar algo de valor ya que, en mi opinión, nadie abordó directamente algunas de las preocupaciones en el PO.
A pesar de lo que sugieren las respuestas aceptadas, los
listobjetos en R no son mapas hash. Si quiere hacer un paralelo con python,listes más, supongo, pythonlists (otuples en realidad).Es mejor describir cómo la mayoría de los objetos R se almacenan internamente (el tipo C de un objeto R es
SEXP). Se componen básicamente de tres partes:NULLsi el objeto no tiene atributos).Desde un punto de vista interno, hay poca diferencia entre a
listy unnumericvector, por ejemplo. Los valores que almacenan son simplemente diferentes. Dividamos dos objetos en el paradigma que describimos antes:Para
x:numeric(REALSXPen el lado C), la longitud es 10 y otras cosas.doublevalores.NULL, ya que el objeto no tiene ninguno.Para
y:list(VECSXPen el lado C), la longitud es 2 y otras cosas.runif(10)yrunif(3)respectivamente.NULL, como parax.Entonces, la única diferencia entre un
numericvector y un alistes que lanumericparte de datos está hecha dedoublevalores, mientras que para lalistparte de datos es una matriz de punteros a otros objetos R.¿Qué pasa con los nombres? Bueno, los nombres son solo algunos de los atributos que puede asignar a un objeto. Veamos el objeto a continuación:
list(VECSXPen el lado C), la longitud es 2 y otras cosas.1:3yLETTERSrespectivamente.namescomponente que es uncharacterobjeto R con valorc("a","b").Desde el nivel R, puede recuperar los atributos de un objeto con la
attributesfunción.El valor clave típico de un mapa hash en R es solo una ilusión. Cuando tu dices:
esto es lo que pasa:
[[función de subconjunto se llama;"a") es de tipocharacter, por lo que se le indica al método que busque dicho valor desde elnamesatributo (si está presente) del objetoz;namesatributo no está allí,NULLse devuelve;"a"se busca el valor en él. Si"a"no es un nombre del objeto,NULLse devuelve;z[[1]].La búsqueda de valor clave es bastante indirecta y siempre es posicional. Además, útil para tener en cuenta:
namesen R deben ser cadenas (charactervectores);en los mapas hash no puede tener dos claves idénticas. En R, puede asignar
namesa un objeto con valores repetidos. Por ejemplo:es perfectamente válido en R. Cuando intenta
y[["same"]], se recupera el primer valor. Deberías saber por qué en este punto.En conclusión, la capacidad de otorgar atributos arbitrarios a un objeto le da la apariencia de algo diferente desde un punto de vista externo. Pero las R
listno son mapas hash de ninguna manera.fuente
Con respecto a los vectores y el concepto hash / array de otros idiomas:
Los vectores son los átomos de R. Por ejemplo,
rpois(1e4,5)(5 números aleatorios),numeric(55)(longitud-55 cero vector sobre dobles) ycharacter(12)(12 cadenas vacías), son todos "básicos".Pueden tener listas o vectores
names.Los vectores requieren que todo sea del mismo tipo de datos. Ver este:
Las listas pueden contener diferentes tipos de datos, como se ve en otras respuestas y en la pregunta del OP en sí.
He visto lenguajes (ruby, javascript) en los que las "matrices" pueden contener tipos de datos variables, pero, por ejemplo, en C ++ las "matrices" deben ser del mismo tipo de datos. Creo que esto es una cuestión de velocidad / eficiencia: si tienes un
numeric(1e6), sabes su tamaño y la ubicación de cada elemento a priori ; si la cosa puede contener"Flying Purple People Eaters"una porción desconocida, entonces debes analizar cosas para conocer datos básicos sobre ella.Ciertas operaciones R estándar también tienen más sentido cuando el tipo está garantizado. Por ejemplo,
cumsum(1:9)tiene sentido mientrascumsum(list(1,2,3,4,5,'a',6,7,8,9))que no, sin que se garantice que el tipo sea doble.En cuanto a tu segunda pregunta:
Las funciones devuelven diferentes tipos de datos de los que se ingresan todo el tiempo.
plotdevuelve una trama aunque no tome una trama como entrada.Argdevuelve unnumerica pesar de que aceptó acomplex. Etc.(Y en cuanto a
strsplit: el código fuente está aquí ).fuente
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 datos en mi mano como objeto en R o cómo seleccionar de los objetos existentes. No es fácil para un novato R pensar "en una caja 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 en el mundo real.
Aunque no estoy dando respuestas exactas a la pregunta, el breve texto a continuación podría ayudar al lector que acaba de comenzar con R y hace preguntas similares.
[subconjuntos.[subconjuntos.[subconjuntos por filas y columnas, o por secuencia.listdonde puedo subconjunto usando[filas y columnas, pero incluso usando[[.tree structuredonde[i]selecciona y devuelve ramas enteras y[[i]]devuelve el artículo de la rama. Y debido a que es asítree like structure, incluso puede usar unindex sequencepara abordar cada hoja de un complejolistusando su[[index_vector]]. Las listas pueden ser simples o muy complejas y pueden mezclar varios tipos de objetos en uno.Entonces
lists, puede terminar con más formas de seleccionar unaleafsituación dependiendo de la situación, como en el siguiente ejemplo.Esta forma de pensar me ayudó mucho.
fuente
Si ayuda, tiendo a concebir las "listas" en R como "registros" en otros lenguajes pre-OO:
El nombre "registro" chocaría 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ó a sí mismo: como listas (de campos).
fuente
¿Por qué estos dos operadores diferentes
[ ], y[[ ]]devuelven el mismo resultado?[ ]proporciona una operación de configuración secundaria. En general, el subconjunto de cualquier objeto tendrá el mismo tipo que el objeto original. Por lo tanto,x[1]proporciona una lista. Del mismo modox[1:2]es un subconjunto de la lista original, por lo tanto, es una lista. Ex.[[ ]]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 subconfiguración como[ ].fuente