data.table
Utilisation de colonnes de liste pour stocker des données
Recherche…
Introduction
list
de R.
Remarques
Dans le cas où il semble étrange que nous parlions de listes sans utiliser ce mot dans le code, notez que .()
Est un alias pour list()
lorsqu'il est utilisé dans un appel DT[...]
.
Lecture dans de nombreux fichiers liés
Supposons que nous voulions lire et empiler un tas de fichiers de format similaire. La solution rapide est la suivante:
rbindlist(lapply(list.files(patt="csv$"), fread), id=TRUE)
Nous pourrions ne pas être satisfaits de cela pour deux raisons:
- Il peut se
rbindlist
à des erreurs lors de la lecture avecfread
ou lors de l'empilement avecrbindlist
raison d'un formatage de données incohérent ourbindlist
. - Nous pouvons vouloir garder une trace des métadonnées pour chaque fichier, extraites du nom du fichier ou peut-être de certaines lignes d'en-tête dans les fichiers (pas tout à fait tabulaires).
Une façon de gérer cela consiste à créer une "table de fichiers" et à stocker le contenu de chaque fichier en tant qu'entrée de colonne de liste sur la ligne qui lui est associée.
Exemple de données
Avant de créer l'exemple de données ci-dessous, assurez-vous que vous êtes dans un dossier vide dans lequel vous pouvez écrire. Exécutez getwd()
et lisez ?setwd
si vous devez changer de dossier.
# example data
set.seed(1)
for (i in 1:3)
fwrite(data.table(id = 1:2, v = sample(letters, 2)), file = sprintf("file201%s.csv", i))
Identifier les fichiers et les métadonnées de fichier
Cette partie est assez simple:
# First, identify the files you want:
fileDT = data.table(fn = list.files(pattern="csv$"))
# Next, optionally parse the names for metadata using regex:
fileDT[, year := type.convert(sub(".*([0-9]{4}).*", "\\1", fn))]
# Finally construct a string file-ID column:
fileDT[, id := as.character(.I)]
# fn year id
# 1: file2011.csv 2011 1
# 2: file2012.csv 2012 2
# 3: file2013.csv 2013 3
Lire dans les fichiers
Lire dans les fichiers en tant que colonne de liste:
fileDT[, contents := .(lapply(fn, fread))]
# fn year id contents
# 1: file2011.csv 2011 1 <data.table>
# 2: file2012.csv 2012 2 <data.table>
# 3: file2013.csv 2013 3 <data.table>
S'il y a un accroc dans la lecture de l'un des fichiers ou si vous devez changer les arguments en fread
fonction des attributs du fichier, cette étape peut facilement être étendue, ressemblant à:
fileDT[, contents := {
cat(fn, "\n")
dat = if (year %in% 2011:2012){
fread(fn, some_args)
} else {
fread(fn)
}
.(.(dat))
}, by=fn]
Pour plus de détails sur les options de lecture dans les fichiers CSV et les fichiers similaires, voir ?fread
.
Empiler les données
De là, nous voulons empiler les données:
fileDT[, rbindlist(setNames(contents, id), idcol="file_id")]
# file_id id v
# 1: 1 1 g
# 2: 1 2 j
# 3: 2 1 o
# 4: 2 2 w
# 5: 3 1 f
# 6: 3 2 w
Si un problème survient lors de l'empilement (comme les noms de colonne ou les classes non correspondantes), nous pouvons revenir aux tables individuelles dans fileDT
pour inspecter l'origine du problème. Par exemple,
fileDT[id == "2", contents[[1]]]
# id v
# 1: 1 o
# 2: 2 w
Les extensions
Si les fichiers ne sont pas dans votre répertoire de travail actuel, utilisez
my_dir = "whatever"
fileDT = data.table(fn = list.files(my_dir, pattern="*.csv"))
# and when reading
fileDT[, contents := .(lapply(fn, function(n) fread(file.path(my_dir, n))))]