Les autres réponses vous montrer comment faire une liste de data.frames lorsque vous avez déjà un tas de data.frames, par exemple d1
, d2
.... Ayant successivement nommées trames de données est un problème, et de les mettre dans une liste est une bonne solution, mais la meilleure pratique est d' éviter d'avoir un tas de data.frames pas dans une liste en premier lieu.
Les autres réponses donnent beaucoup de détails sur la façon d'attribuer des trames de données à des éléments de liste, d'y accéder, etc. Nous aborderons cela un peu ici aussi, mais le point principal est de dire n'attendez pas d'avoir un tas de data.frames
pour les ajouter à une liste. Commencez par la liste.
Le reste de cette réponse couvrira certains cas courants où vous pourriez être tenté de créer des variables séquentielles et vous montrera comment accéder directement aux listes. Si vous êtes nouveau dans les listes de R, vous voudrez peut-être également lire Quelle est la différence entre [[
et [
dans l'accès aux éléments d'une liste? .
Listes depuis le début
Ne créez jamais d1
d2
d3
, ... dn
en premier lieu. Créez une liste d
avec des n
éléments.
Lecture de plusieurs fichiers dans une liste de blocs de données
Cela se fait assez facilement lors de la lecture de fichiers. Peut-être avez-vous des fichiers data1.csv, data2.csv, ...
dans un répertoire. Votre objectif est une liste de data.frames appelée mydata
. La première chose dont vous avez besoin est un vecteur avec tous les noms de fichiers. Vous pouvez le construire avec coller (par exemple, my_files = paste0("data", 1:5, ".csv")
), mais il est probablement plus facile à utiliser list.files
pour récupérer tous les fichiers appropriés:my_files <- list.files(pattern = "\\.csv$")
. Vous pouvez utiliser des expressions régulières pour faire correspondre les fichiers, en savoir plus sur les expressions régulières dans d'autres questions si vous avez besoin d'aide. De cette façon, vous pouvez récupérer tous les fichiers CSV même s'ils ne suivent pas un bon schéma de dénomination. Ou vous pouvez utiliser un modèle de regex plus sophistiqué si vous avez besoin de sélectionner certains fichiers CSV parmi plusieurs d'entre eux.
À ce stade, la plupart des débutants en R utiliseront une for
boucle, et il n'y a rien de mal à cela, cela fonctionne très bien.
my_data <- list()
for (i in seq_along(my_files)) {
my_data[[i]] <- read.csv(file = my_files[i])
}
Une façon plus R-like de le faire est avec lapply
, qui est un raccourci pour ce qui précède
my_data <- lapply(my_files, read.csv)
Bien sûr, remplacez par une autre fonction d'importation de données read.csv
le cas échéant. readr::read_csv
ou data.table::fread
sera plus rapide, ou vous pouvez également avoir besoin d'une fonction différente pour un type de fichier différent.
Dans tous les cas, il est pratique de nommer les éléments de la liste pour qu'ils correspondent aux fichiers
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 = "")
Fractionnement d'un bloc de données en une liste de blocs de données
C'est très simple, la fonction de base le split()
fait pour vous. Vous pouvez diviser par une colonne (ou des colonnes) des données, ou par tout ce que vous voulez
mt_list = split(mtcars, f = mtcars$cyl)
# This gives a list of three data frames, one for each value of cyl
C'est également un bon moyen de diviser une trame de données en morceaux pour une validation croisée. Vous souhaitez peut-être vous diviser mtcars
en éléments de formation, de test et de validation.
groups = sample(c("train", "test", "validate"),
size = nrow(mtcars), replace = TRUE)
mt_split = split(mtcars, f = groups)
# and mt_split has appropriate names already!
Simulation d'une liste de trames de données
Peut-être que vous simulez des données, quelque chose comme ceci:
my_sim_data = data.frame(x = rnorm(50), y = rnorm(50))
Mais qui fait une seule simulation? Vous voulez faire cela 100 fois, 1000 fois, plus! Mais vous ne voulez pas 10 000 blocs de données dans votre espace de travail. Utilisez-les replicate
et mettez-les dans une liste:
sim_list = replicate(n = 10,
expr = {data.frame(x = rnorm(50), y = rnorm(50))},
simplify = F)
Dans ce cas en particulier, vous devez également vous demander si vous avez vraiment besoin de trames de données séparées ou si une seule trame de données avec une colonne "groupe" fonctionnerait tout aussi bien? En utilisant data.table
ou, dplyr
il est assez facile de faire des choses "par groupe" dans un bloc de données.
Je n'ai pas mis mes données dans une liste: (Je le ferai la prochaine fois, mais que puis-je faire maintenant?
S'il s'agit d'un assortiment étrange (ce qui est inhabituel), vous pouvez simplement les attribuer:
mylist <- list()
mylist[[1]] <- mtcars
mylist[[2]] <- data.frame(a = rnorm(50), b = runif(50))
...
Si vous avez des trames de données nommées dans un modèle, par exemple, df1
, df2
, df3
et vous les voulez dans une liste, vous pouvez get
les si vous pouvez écrire une expression régulière pour correspondre aux noms. Quelque chose comme
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.
Généralement, mget
est utilisé pour obtenir plusieurs objets et les renvoyer dans une liste nommée. Son équivalent get
est utilisé pour obtenir un seul objet et le renvoyer (pas dans une liste).
Combinaison d'une liste de trames de données en une seule trame de données
Une tâche courante consiste à combiner une liste de trames de données en une seule trame Big Data. Si vous souhaitez les empiler les uns sur les autres, vous les utiliserez rbind
pour une paire d'entre eux, mais pour une liste de blocs de données, voici trois bons choix:
# 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)
(De même en utilisant cbind
ou dplyr::bind_cols
pour les colonnes.)
Pour fusionner (joindre) une liste de blocs de données, vous pouvez voir ces réponses . Souvent, l'idée est d'utiliser Reduce
avecmerge
(ou une autre fonction de jonction) pour les réunir.
Pourquoi mettre les données dans une liste?
Mettez des données similaires dans les listes parce que vous voulez faire des choses semblables à chaque trame de données et des fonctions telles que lapply
, sapply
do.call
, l' purrr
emballage , et les anciennes plyr
l*ply
fonctions , il est facile de le faire. Des exemples de personnes faisant facilement des choses avec des listes sont partout SO.
Même si vous utilisez une boucle for modeste, il est beaucoup plus facile de boucler sur les éléments d'une liste que de construire des noms de variables avec paste
et d'accéder aux objets avec get
. Plus facile à déboguer également.
Pensez à l' évolutivité . Si vous avez vraiment besoin de trois variables, il est bon d'utiliser d1
, d2
, d3
. Mais s'il s'avère que vous avez vraiment besoin de 6, c'est beaucoup plus de frappe. Et la prochaine fois, quand vous avez besoin de 10 ou 20, vous vous surprenez à copier et coller des lignes de code, peut-être en utilisant find / replace pour passer d14
à d15
, et vous pensez que ce n'est pas comme ça que la programmation devrait être . Si vous utilisez une liste, la différence entre 3 cas, 30 cas et 300 cas est au plus une ligne de code --- aucun changement si votre nombre de cas est automatiquement détecté par, par exemple, combien.csv
fichiers dans votre annuaire.
Vous pouvez nommer les éléments d'une liste, au cas où vous voudriez utiliser autre chose que des index numériques pour accéder à vos blocs de données (et vous pouvez utiliser les deux, ce n'est pas un choix XOR).
Dans l'ensemble, l'utilisation de listes vous amènera à écrire un code plus propre et plus facile à lire, ce qui entraînera moins de bogues et moins de confusion.
=
pas à l'<-
intérieurdata.frame()
. En utilisant<-
vous créezy1
ety2
dans votre environnement global et votre bloc de données n'est pas ce que vous voulez qu'il soit.