¿Cómo hago una lista de marcos de datos?

¿Cómo hago una lista de marcos de datos y cómo puedo acceder a cada uno de esos marcos de datos de la lista?

Por ejemplo, ¿cómo puedo poner estos marcos de datos en una lista?

d1 <- data.frame(y1 = c(1, 2, 3), y2 = c(4, 5, 6)) d2 <- data.frame(y1 = c(3, 2, 1), y2 = c(6, 5, 4)) 

Esto no está relacionado con su pregunta, pero desea usar = y no <- dentro de la llamada a la función. Si usa <- , terminará creando las variables y1 e y2 en cualquier entorno en el que esté trabajando:

 d1 <- data.frame(y1 <- c(1, 2, 3), y2 <- c(4, 5, 6)) y1 # [1] 1 2 3 y2 # [1] 4 5 6 

Esto no tendrá el efecto aparentemente deseado de crear nombres de columna en el dataframe:

 d1 # y1....c.1..2..3. y2....c.4..5..6. # 1 1 4 # 2 2 5 # 3 3 6 

El operador = , por otro lado, asociará sus vectores con argumentos a data.frame .

En cuanto a su pregunta, hacer una lista de marcos de datos es fácil:

 d1 <- data.frame(y1 = c(1, 2, 3), y2 = c(4, 5, 6)) d2 <- data.frame(y1 = c(3, 2, 1), y2 = c(6, 5, 4)) my.list <- list(d1, d2) 

Usted accede a los marcos de datos tal como lo haría con cualquier otro elemento de lista:

 my.list[[1]] # y1 y2 # 1 1 4 # 2 2 5 # 3 3 6 

Las otras respuestas le muestran cómo hacer una lista de marcos de datos cuando ya tiene un montón de marcos de datos, por ej., D1, d2 , …. Tener marcos de datos nombrados secuencialmente es un problema y ponerlos en una lista es una buena solución, pero la mejor práctica es evitar tener un montón de marcos de datos en una lista en primer lugar.

Las otras respuestas brindan muchos detalles sobre cómo asignar marcos de datos para enumerar elementos, acceder a ellos, etc. Aquí también lo abordaremos un poco, pero el Punto Principal es decir no espere hasta tener un montón de data.frames para agregarlos a una lista. Comience con la lista.

Si son un surtido extraño (lo cual es inusual), simplemente puede asignarlos:

 mylist <- list() mylist[[1]] <- mtcars mylist[[2]] <- data.frame(a = rnorm(50), b = runif(50)) ... 

El rest de esta respuesta cubrirá algunos casos comunes en los que podría verse tentado a crear variables secuenciales, y le mostrará cómo ir directamente a las listas. Si es nuevo en las listas en R, también puede leer ¿Cuál es la diferencia entre [[ y [ al acceder a los elementos de una lista? .


Listas desde el comienzo

Nunca d1 d2 d3 , ..., en primer lugar. Crea una lista d con 3 elementos.

Lectura de varios archivos en una lista de marcos de datos

Esto se hace bastante fácil cuando lee archivos. Tal vez tengas los archivos data1.csv, data2.csv, ... en un directorio. Tu objective es una lista de data.frames llamada mydata . Lo primero que necesita es un vector con todos los nombres de archivo. Puede construir esto con pegar (por ejemplo, my_files = paste0("data", 1:5, ".csv") ), pero probablemente sea más fácil usar list.files para capturar todos los archivos apropiados: my_files <- list.files(pattern = "\\.csv$") .

En este punto, la mayoría de los principiantes R usarán un bucle for , y no hay nada de malo en eso, funciona bien.

 my_data <- list() for (i in seq_along(my_files)) { my_data[[i]] <- read.csv(file = my_files[i]) } 

Una manera más parecida a R de hacerlo es con lapply

 my_data <- lapply(my_files, read.csv) 

De cualquier manera, es útil nombrar los elementos de la lista para que coincidan con los archivos

 names(my_data) <- gsub("\\.csv$", "", my_files) # or, if you prefer the consistent syntax of stringr names(my_data) <- stringr::str_replace(my_files, pattern = ".csv", replacement = "") 

Dividir un dataframe en una lista de marcos de datos

Esto es súper fácil, la función base split() hace por usted. Puede dividir por una columna (o columnas) de los datos, o por cualquier otra cosa que desee

 mt_list = split(mtcars, f = mtcars$cyl) # This gives a list of three data frames, one for each value of cyl 

Esta es también una buena forma de dividir un dataframe en partes para la validación cruzada. Tal vez quiera dividir mtcars en mtcars entrenamiento, prueba y validación.

 groups = sample(c("train", "test", "validate"), size = nrow(mtcars), replace = TRUE) mt_split = split(mtcars, f = groups) # and mt_split has appropriate names already! 

Simular una lista de marcos de datos

Tal vez estás simulando datos, algo como esto:

 my_sim_data = data.frame(x = rnorm(50), y = rnorm(50)) 

¿Pero quién hace solo una simulación? ¡Quieres hacer esto 100 veces, 1000 veces, más! Pero no quiere 10.000 marcos de datos en su espacio de trabajo. Use replicate y ponerlos en una lista:

 sim_list = replicate(n = 10, expr = {data.frame(x = rnorm(50), y = rnorm(50))}, simplify = F) 

Especialmente en este caso, también debe considerar si realmente necesita marcos de datos separados, o si un solo dataframe con una columna de "grupo" funcionaría igual de bien? Usando data.table o dplyr es bastante fácil hacer cosas "por grupo" a un dataframe.

No puse mis datos en una lista 🙁 Lo haré la próxima vez, pero ¿qué puedo hacer ahora?

Si tiene marcos de datos nombrados en un patrón, por ejemplo, df1 , df2 , df3 , y los quiere en una lista, puede obtenerlos si puede escribir una expresión regular para que coincida con los nombres. Algo como

 df_list = mget(ls(pattern = "df[0-9]")) # this would match any object with "df" followed by a digit in its name # you can test what objects will be got by just running the ls(pattern = "df[0-9]") # part and adjusting the pattern until it gets the right objects. 

Generalmente, mget se usa para obtener múltiples objetos y devolverlos en una lista con nombre. Su contraparte get se usa para obtener un solo objeto y devolverlo no en una lista.

Combinar una lista de marcos de datos en un único dataframe

Una tarea común es combinar una lista de marcos de datos en un dataframe grande. Si desea rbind uno encima del otro, usaría rbind para un par de ellos, pero para una lista de marcos de datos, aquí hay tres buenas opciones:

 # base option - slower but not extra dependencies big_data = do.call(what = rbind, args = df_list) # data table and dplyr have nice functions for this # they will be faster and can also add id columns to identify # which list item they came from. They can also fill in # missing values if some data frames have more columns than others big_data = data.table::rbindlist(df_list) big_data = dplyr::bind_rows(df_list) 

(De manera similar, usando cbind o dplyr::bind_cols para columnas).

Para combinar (unir) una lista de marcos de datos, puede ver estas respuestas . A menudo, la idea es usar Reduce con merge (o alguna otra función de unión) para unirlos.

¿Por qué poner los datos en una lista?

Coloque datos similares en las listas porque desea hacer cosas similares a cada dataframe, y funciones como lapply , sapply do.call , el paquete purrr y las antiguas plyr l*ply hacen que sea más fácil hacerlo. Los ejemplos de gente que hace cosas fácilmente con las listas han terminado.

Incluso si utiliza un bucle for low, es mucho más fácil recorrer los elementos de una lista que construir nombres de variables con paste y acceder a los objetos con get . Más fácil de depurar, también.

Piense en la escalabilidad . Si realmente solo necesita tres variables, está bien usar d1 , d2 , d3 . Pero si resulta que realmente necesitas 6, eso es mucho más tipeo. Y la próxima vez, cuando necesite 10 o 20, se encontrará copiando y pegando líneas de código, tal vez usando find / replace para cambiar d14 a d15 , y está pensando que así no debería ser la progtwigción . Si utiliza una lista, la diferencia entre 3 casos, 30 casos y 300 casos es, como máximo, una línea de código, sin cambios si el número de casos se detecta automáticamente, por ejemplo, cuántos archivos .csv encuentran. en tu directorio.

Puede asignar un nombre a los elementos de una lista, en caso de que desee usar algo que no sean índices numéricos para acceder a sus marcos de datos (y puede usar ambos, esto no es una opción XOR).

En general, el uso de listas lo llevará a escribir un código más limpio y fácil de leer, lo que dará como resultado menos errores y menos confusión.

También puede acceder a columnas y valores específicos en cada elemento de lista con [ y [[ . Aquí hay un par de ejemplos. Primero, podemos acceder solo a la primera columna de cada dataframe en la lista con lapply(ldf, "[", 1) , donde 1 significa el número de columna.

 ldf <- list(d1 = d1, d2 = d2) ## create a named list of your data frames lapply(ldf, "[", 1) # $d1 # y1 # 1 1 # 2 2 # 3 3 # # $d2 # y1 # 1 3 # 2 2 # 3 1 

Del mismo modo, podemos acceder al primer valor en la segunda columna con

 lapply(ldf, "[", 1, 2) # $d1 # [1] 4 # # $d2 # [1] 6 

Entonces también podemos acceder a los valores de la columna directamente, como un vector, con [[

 lapply(ldf, "[[", 1) # $d1 # [1] 1 2 3 # # $d2 # [1] 3 2 1 

Si tiene una gran cantidad de marcos de datos con nombre secuencial, puede crear una lista del subconjunto deseado de marcos de datos como este:

 d1 <- data.frame(y1=c(1,2,3), y2=c(4,5,6)) d2 <- data.frame(y1=c(3,2,1), y2=c(6,5,4)) d3 <- data.frame(y1=c(6,5,4), y2=c(3,2,1)) d4 <- data.frame(y1=c(9,9,9), y2=c(8,8,8)) my.list <- list(d1, d2, d3, d4) my.list my.list2 <- lapply(paste('d', seq(2,4,1), sep=''), get) my.list2 

donde my.list2 devuelve una lista que contiene los marcos de datos 2º, 3º y 4º.

 [[1]] y1 y2 1 3 6 2 2 5 3 1 4 [[2]] y1 y2 1 6 3 2 5 2 3 4 1 [[3]] y1 y2 1 9 8 2 9 8 3 9 8 

Sin embargo, tenga en cuenta que los marcos de datos en la lista anterior ya no tienen nombre. Si desea crear una lista que contenga un subconjunto de marcos de datos y desea conservar sus nombres, puede intentar esto:

 list.function <- function() { d1 <- data.frame(y1=c(1,2,3), y2=c(4,5,6)) d2 <- data.frame(y1=c(3,2,1), y2=c(6,5,4)) d3 <- data.frame(y1=c(6,5,4), y2=c(3,2,1)) d4 <- data.frame(y1=c(9,9,9), y2=c(8,8,8)) sapply(paste('d', seq(2,4,1), sep=''), get, environment(), simplify = FALSE) } my.list3 <- list.function() my.list3 

que devuelve:

 > my.list3 $d2 y1 y2 1 3 6 2 2 5 3 1 4 $d3 y1 y2 1 6 3 2 5 2 3 4 1 $d4 y1 y2 1 9 8 2 9 8 3 9 8 > str(my.list3) List of 3 $ d2:'data.frame': 3 obs. of 2 variables: ..$ y1: num [1:3] 3 2 1 ..$ y2: num [1:3] 6 5 4 $ d3:'data.frame': 3 obs. of 2 variables: ..$ y1: num [1:3] 6 5 4 ..$ y2: num [1:3] 3 2 1 $ d4:'data.frame': 3 obs. of 2 variables: ..$ y1: num [1:3] 9 9 9 ..$ y2: num [1:3] 8 8 8 > my.list3[[1]] y1 y2 1 3 6 2 2 5 3 1 4 > my.list3$d4 y1 y2 1 9 8 2 9 8 3 9 8 

Tomando como un dado, usted tiene un número “grande” de marcos de datos con nombres similares (aquí d # donde # es un entero positivo), la siguiente es una ligera mejora del método de @ mark-miller, ya que automáticamente devuelve una lista con nombre de data.frames y es más escueto.

La clave es usar mget junto con ls . Si los marcos de datos d1 y d2 proporcionados en la pregunta eran los únicos objetos con nombres d # en el entorno, entonces

 my.list <- mget(ls(pattern="^d[0-9]+")) 

que regresaría

 my.list $d1 y1 y2 1 1 4 2 2 5 3 3 6 $d2 y1 y2 1 3 6 2 2 5 3 1 4 

Este método aprovecha el argumento de patrón en ls , que nos permite usar expresiones regulares para hacer un análisis más detallado de los nombres de los objetos en el entorno.

Como señala @gregor, en general es mejor configurar su proceso de construcción de datos para que los data.frames se incluyan en listas nombradas al inicio.

datos

 d1<-data.frame(y1 = c(1,2,3),y2 = c(4,5,6)) d2<-data.frame(y1 = c(3,2,1),y2 = c(6,5,4)) 

Esto puede ser un poco tarde pero volviendo a tu ejemplo, pensé que extendería la respuesta solo un poco.

  D1 <- data.frame(Y1=c(1,2,3), Y2=c(4,5,6)) D2 <- data.frame(Y1=c(3,2,1), Y2=c(6,5,4)) D3 <- data.frame(Y1=c(6,5,4), Y2=c(3,2,1)) D4 <- data.frame(Y1=c(9,9,9), Y2=c(8,8,8)) 

Luego haces tu lista fácilmente:

 mylist <- list(D1,D2,D3,D4) 

Ahora tiene una lista, pero en lugar de acceder a la lista de la manera antigua, como

 mylist[[1]] # to access 'd1' 

puede usar esta función para obtener y asignar el dataframe de su elección.

 GETDF_FROMLIST <- function(DF_LIST, ITEM_LOC){ DF_SELECTED <- DF_LIST[[ITEM_LOC]] return(DF_SELECTED) } 

Ahora consigue el que quieras.

 D1 <- GETDF_FROMLIST(mylist, 1) D2 <- GETDF_FROMLIST(mylist, 2) D3 <- GETDF_FROMLIST(mylist, 3) D4 <- GETDF_FROMLIST(mylist, 4) 

Espero que un poco más ayuda.

¡Aclamaciones!

Muy simple ! Aquí está mi sugerencia:

Si desea seleccionar marcos de datos en su área de trabajo, intente esto:

 Filter(function(x) is.data.frame(get(x)) , ls()) 

o

 ls()[sapply(ls(), function(x) is.data.frame(get(x)))] 

todos estos darán el mismo resultado.

Puede cambiar is.data.frame para verificar otros tipos de variables como is.function