data.table
Usando columnas de lista para almacenar datos
Buscar..
Introducción
list
de R.
Observaciones
En caso de que parezca extraño que estemos hablando de listas sin usar esa palabra en el código, tenga en cuenta que .()
Es un alias para la list()
cuando se usa dentro de una llamada DT[...]
.
Leyendo en muchos archivos relacionados
Supongamos que queremos leer y apilar un montón de archivos con formato similar. La solución rápida es:
rbindlist(lapply(list.files(patt="csv$"), fread), id=TRUE)
Puede que no estemos satisfechos con esto por un par de razones:
- Es posible que se
fread
errores al leer confread
o al apilar conrbindlist
debido a un formato de datos inconsistente orbindlist
. - Es posible que queramos realizar un seguimiento de los metadatos de cada archivo, tomados del nombre del archivo o quizás de algunas filas de encabezado dentro de los archivos (no del todo tabulares).
Una forma de manejar esto es hacer una "tabla de archivos" y almacenar el contenido de cada archivo como una entrada de columna de lista en la fila asociada a él.
Ejemplo de datos
Antes de crear los datos de ejemplo a continuación, asegúrese de estar en una carpeta vacía en la que pueda escribir. Ejecute getwd()
y lea ?setwd
si necesita cambiar las carpetas.
# 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))
Identificar archivos y metadatos de archivos.
Esta parte es bastante sencilla:
# 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
Leer en archivos
Lea en los archivos como una columna de la lista:
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>
Si hay un obstáculo en la lectura de uno de los archivos o si necesita cambiar los argumentos a fread
según los atributos del archivo, este paso puede extenderse fácilmente, con el siguiente aspecto:
fileDT[, contents := {
cat(fn, "\n")
dat = if (year %in% 2011:2012){
fread(fn, some_args)
} else {
fread(fn)
}
.(.(dat))
}, by=fn]
Para obtener detalles sobre las opciones de lectura en CSV y archivos similares, consulte ?fread
.
Apilar datos
A partir de aquí, queremos apilar los datos:
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 ocurre algún problema en el apilamiento (como nombres de columnas o clases que no coinciden), podemos regresar a las tablas individuales en fileDT
para inspeccionar dónde se originó el problema. Por ejemplo,
fileDT[id == "2", contents[[1]]]
# id v
# 1: 1 o
# 2: 2 w
Extensiones
Si los archivos no están en su directorio de trabajo actual, use
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))))]