Le altre risposte ti mostrano come creare un elenco di data.frames quando si dispone già di un sacco di data.frames, ad es d1
. d2
, ... Avere frame di dati con nome sequenziale è un problema e inserirli in un elenco è un buona soluzione, ma la migliore pratica è quella di evitare di avere un sacco di data.frames non in un elenco in primo luogo.
Le altre risposte forniscono molti dettagli su come assegnare i frame di dati per elencare gli elementi, accedervi, ecc. Ne tratteremo anche qui un po ', ma il punto principale è dire che non aspettate di avere un gruppo di data.frames
per aggiungerli a un elenco. Inizia con l'elenco.
Il resto di questa risposta tratterà alcuni casi comuni in cui potresti essere tentato di creare variabili sequenziali e ti mostrerà come andare direttamente agli elenchi. Se non conosci gli elenchi in R, potresti voler leggere anche Qual è la differenza tra [[
e [
nell'accesso agli elementi di un elenco? .
Elenchi dall'inizio
Non creare mai d1
d2
d3
, ..., dn
in primo luogo. Crea un elenco d
con n
elementi.
Lettura di più file in un elenco di frame di dati
Questo viene fatto abbastanza facilmente durante la lettura di file. Forse hai i file data1.csv, data2.csv, ...
in una directory. Il tuo obiettivo è un elenco di data.frames chiamati mydata
. La prima cosa che ti serve è un vettore con tutti i nomi dei file. Puoi costruirlo con incolla (ad es.my_files = paste0("data", 1:5, ".csv")
), ma è probabilmente più facile da usare list.files
per afferrare tutti i file appropriati: my_files <- list.files(pattern = "\\.csv$")
. Puoi usare espressioni regolari per abbinare i file, leggere di più sulle espressioni regolari in altre domande se hai bisogno di aiuto lì. In questo modo puoi prendere tutti i file CSV anche se non seguono un buon schema di denominazione. Oppure puoi usare un modello regex più elaborato se devi scegliere alcuni file CSV da un gruppo di essi.
A questo punto, la maggior parte dei principianti R utilizzerà un for
ciclo, e non c'è niente di sbagliato in questo, funziona bene.
my_data <- list()
for (i in seq_along(my_files)) {
my_data[[i]] <- read.csv(file = my_files[i])
}
Un modo più simile a R per farlo è con lapply
, che è una scorciatoia per quanto sopra
my_data <- lapply(my_files, read.csv)
Ovviamente, sostituire le altre funzioni di importazione dei dati read.csv
come appropriato. readr::read_csv
o data.table::fread
sarà più veloce o potresti anche aver bisogno di una funzione diversa per un diverso tipo di file.
In entrambi i casi, è utile nominare gli elementi dell'elenco in modo che corrispondano ai file
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 = "")
Dividere un frame di dati in un elenco di frame di dati
È semplicissimo, la funzione base split()
lo fa per te. Puoi dividere per una colonna (o colonne) dei dati, o per qualsiasi altra cosa tu voglia
mt_list = split(mtcars, f = mtcars$cyl)
# This gives a list of three data frames, one for each value of cyl
Questo è anche un buon modo per suddividere un frame di dati in pezzi per la convalida incrociata. Forse vuoi dividere mtcars
in pezzi di addestramento, test e validazione.
groups = sample(c("train", "test", "validate"),
size = nrow(mtcars), replace = TRUE)
mt_split = split(mtcars, f = groups)
# and mt_split has appropriate names already!
Simulazione di un elenco di frame di dati
Forse stai simulando dati, qualcosa del genere:
my_sim_data = data.frame(x = rnorm(50), y = rnorm(50))
Ma chi esegue una sola simulazione? Vuoi farlo 100 volte, 1000 volte, di più! Ma non vuoi 10.000 frame di dati nell'area di lavoro. Usali replicate
e mettili in un elenco:
sim_list = replicate(n = 10,
expr = {data.frame(x = rnorm(50), y = rnorm(50))},
simplify = F)
In questo caso, in particolare, dovresti anche considerare se hai davvero bisogno di frame di dati separati o un singolo frame di dati con una colonna "gruppo" funziona altrettanto bene? Usare data.table
o dplyr
è abbastanza facile fare le cose "per gruppo" in un frame di dati.
Non ho inserito i miei dati in un elenco :( Lo farò la prossima volta, ma cosa posso fare ora?
Se sono un assortimento strano (il che è insolito), puoi semplicemente assegnarli:
mylist <- list()
mylist[[1]] <- mtcars
mylist[[2]] <- data.frame(a = rnorm(50), b = runif(50))
...
Se si dispone di frame di dati con nome in un modello, ad esempio, df1
, df2
, df3
, e li vuole in un elenco, si può get
loro se è possibile scrivere un'espressione regolare per corrispondere ai nomi. Qualcosa di simile a
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
viene utilizzato per ottenere più oggetti e restituirli in un elenco denominato. La sua controparte get
viene utilizzata per ottenere un singolo oggetto e restituirlo (non in un elenco).
Combinazione di un elenco di frame di dati in un singolo frame di dati
Un'attività comune è combinare un elenco di frame di dati in un frame di grandi dimensioni. Se vuoi impilarli uno sopra l'altro, li useresti rbind
per un paio di essi, ma per un elenco di frame di dati qui ci sono tre buone scelte:
# 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)
(Allo stesso modo usando cbind
o dplyr::bind_cols
per le colonne.)
Per unire (unire) un elenco di frame di dati, puoi vedere queste risposte . Spesso, l'idea è quella di utilizzare Reduce
conmerge
(o qualche altra funzione di unione) per metterli insieme.
Perché mettere i dati in un elenco?
Mettere dati simili negli elenchi perché si vuole fare cose simili a ogni frame di dati, e funzioni come lapply
, sapply
do.call
, il purrr
pacchetto , e le vecchie plyr
l*ply
funzioni lo rendono facile da fare. Esempi di persone che fanno facilmente cose con elenchi sono in tutto il SO.
Anche se usi un lowly per loop, è molto più facile eseguire il loop degli elementi di un elenco piuttosto che costruire nomi di variabili con paste
e accedere agli oggetti con get
. Anche più facile da eseguire il debug.
Pensa alla scalabilità . Se si ha realmente bisogno solo tre variabili, va bene per l'uso d1
, d2
, d3
. Ma poi se risulta che hai davvero bisogno di 6, è molto più digitando. E la prossima volta, quando hai bisogno di 10 o 20, ti ritrovi a copiare e incollare righe di codice, magari usando find / sostituisci per passare d14
a d15
, e stai pensando che non dovrebbe essere così la programmazione . Se usi un elenco, la differenza tra 3 casi, 30 casi e 300 casi è al massimo una riga di codice --- nessuna modifica se il tuo numero di casi viene rilevato automaticamente da, ad esempio, quanti .csv
file sono presenti nel tuo directory.
Puoi nominare gli elementi di un elenco, nel caso in cui desideri utilizzare qualcosa di diverso dagli indici numerici per accedere ai tuoi frame di dati (e puoi utilizzare entrambi, questa non è una scelta XOR).
Complessivamente, l'utilizzo degli elenchi ti porterà a scrivere codice più pulito e più facile da leggere, con conseguenti meno bug e meno confusione.
=
non<-
dentrodata.frame()
. Usando<-
tu creiy1
ey2
nel tuo ambiente globale e il tuo frame di dati non è quello che vuoi che sia.