Las otras respuestas le muestran cómo hacer una lista de data.frames cuando ya tiene un montón de data.frames, p. Ej d1
. d2
, ... Tener cuadros de datos con nombre secuencial es un problema, y ponerlos en una lista es un buena solución, pero la mejor práctica es evitar tener un montón de data.frames que no están 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. También cubriremos eso un poco aquí, pero el punto principal es decir que no espere hasta que tenga un montón de data.frames
para agregarlos a una lista. Comience con la lista.
El resto 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 eres nuevo en las listas en R, es posible que también quieras leer ¿Cuál es la diferencia entre [[
y [
al acceder a los elementos de una lista? .
Listas desde el principio
Nunca crees d1
d2
d3
, ..., dn
en primer lugar. Crea una lista d
con n
elementos.
Leer múltiples archivos en una lista de marcos de datos
Esto se hace con bastante facilidad al leer en archivos. Tal vez tienes archivos data1.csv, data2.csv, ...
en un directorio. Su objetivo es una lista de data.frames llamados mydata
. Lo primero que necesita es un vector con todos los nombres de archivo. Puede construir este con pasta (por ejemplo, my_files = paste0("data", 1:5, ".csv")
), pero es probable que sea más fácil de usar list.files
para agarrar todos los archivos correspondientes: my_files <- list.files(pattern = "\\.csv$")
. Puede usar expresiones regulares para hacer coincidir los archivos, leer más sobre expresiones regulares en otras preguntas si necesita ayuda allí. De esta manera, puede tomar todos los archivos CSV, incluso si no siguen un buen esquema de nombres. O puede usar un patrón de expresiones regulares más sofisticado si necesita seleccionar ciertos archivos CSV de entre muchos de ellos.
En este punto, la mayoría de los principiantes de R usarán un for
bucle, 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 forma más similar a R es hacerlo con lapply
, que es un atajo para lo anterior
my_data <- lapply(my_files, read.csv)
Por supuesto, sustituya otra función de importación de datos read.csv
según corresponda. readr::read_csv
o data.table::fread
será más rápido, o también puede necesitar una función diferente para un tipo de archivo diferente.
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 = "")
División de un marco de datos en una lista de marcos de datos
Esto es súper fácil, la función base lo 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 también es una buena manera de dividir un marco de datos en partes para la validación cruzada. Tal vez quieras dividirte mtcars
en piezas de 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!
Simulando 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 una sola simulación? ¡Quieres hacer esto 100 veces, 1000 veces, más! Pero no desea 10,000 marcos de datos en su espacio de trabajo. Úselos replicate
y póngalos en una lista:
sim_list = replicate(n = 10,
expr = {data.frame(x = rnorm(50), y = rnorm(50))},
simplify = F)
En este caso especialmente, también debe considerar si realmente necesita marcos de datos separados, o si un solo marco de datos con una columna de "grupo" funcionaría igual de bien. Usar data.table
o dplyr
es bastante fácil hacer cosas "por grupo" en un marco de datos.
No puse mis datos en una lista :( Lo haré la próxima vez, pero ¿qué puedo hacer ahora?
Si son una variedad extraña (lo cual es inusual), simplemente puede asignarlos:
mylist <- list()
mylist[[1]] <- mtcars
mylist[[2]] <- data.frame(a = rnorm(50), b = runif(50))
...
Si usted tiene marcos de datos con nombre en un patrón, por ejemplo, df1
, df2
, df3
, y usted los quiere en una lista, puede get
que si se puede escribir una expresión regular para coincidir 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.
En general, mget
se usa para obtener varios objetos y devolverlos en una lista con nombre. Su contraparte get
se usa para obtener un solo objeto y devolverlo (no en una lista).
Combinando una lista de marcos de datos en un solo marco de datos
Una tarea común es combinar una lista de marcos de datos en un gran marco de datos. Si desea apilarlos uno encima del otro, los 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 that
# - are much faster
# - add id columns to identify the source
# - fill in missing values if some data frames have more columns than others
# see their help pages for details
big_data = data.table::rbindlist(df_list)
big_data = dplyr::bind_rows(df_list)
(Del mismo modo usando cbind
o dplyr::bind_cols
para columnas).
Para fusionar (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?
Poner los datos similares en las listas porque quiere hacer cosas similares a cada trama de datos, y funciones como lapply
, sapply
do.call
, el purrr
paquete , y las antiguas plyr
l*ply
funciones hacen que sea fácil para hacer eso. Ejemplos de personas que hacen cosas fácilmente con listas están en todo SO.
Incluso si usa un bucle for bajo, es mucho más fácil recorrer los elementos de una lista que construir nombres de variables paste
y acceder a los objetos con ellos get
. Más fácil de depurar, también.
Piensa en la escalabilidad . Si realmente necesita solamente tres variables, está bien para su uso d1
, d2
, d3
. Pero si resulta que realmente necesitas 6, eso es mucho más escribir. Y la próxima vez, cuando se necesita 10 o 20, usted se encuentra copiar y pegar líneas de código, tal vez el uso de buscar / reemplazar al cambio d14
a d15
, y que está pensando que esto no es la forma en la programación debe ser . Si usa una lista, la diferencia entre 3 casos, 30 casos y 300 casos es, como máximo, una línea de código, sin ningún cambio si su número de casos se detecta automáticamente, por ejemplo, cuántos .csv
archivos hay en su directorio.
Puede nombrar los elementos de una lista, en caso de que quiera usar algo más que índices numéricos para acceder a sus marcos de datos (y puede usar ambos, esta 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.
=
no lo uses<-
dentrodata.frame()
. Al usar<-
creay1
yy2
en su entorno global y su marco de datos no es lo que quiere que sea.