Saltar al contenido

¿Cómo importar varios archivos .csv a la vez?

Luego de de esta extensa compilación de datos dimos con la respuesta este enigma que presentan ciertos los lectores. Te compartimos la respuesta y nuestro deseo es serte de gran ayuda.

Solución:

Algo como lo siguiente debería resultar en cada marco de datos como un elemento separado en una sola lista:

temp = list.files(pattern="*.csv")
myfiles = lapply(temp, read.delim)

Esto supone que tiene esos CSV en un solo directorio, su directorio de trabajo actual, y que todos tienen la extensión en minúsculas .csv.

Si luego desea combinar esos marcos de datos en un solo marco de datos, vea las soluciones en otras respuestas usando cosas como do.call(rbind,...), dplyr::bind_rows() o data.table::rbindlist().

Si realmente desea cada marco de datos en un objeto separado, aunque a menudo no es aconsejable, puede hacer lo siguiente con assign:

temp = list.files(pattern="*.csv")
for (i in 1:length(temp)) assign(temp[i], read.csv(temp[i]))

O sin assign, y para demostrar (1) cómo se puede limpiar el nombre del archivo y (2) mostrar cómo usar list2env, puedes probar lo siguiente:

temp = list.files(pattern="*.csv")
list2env(
  lapply(setNames(temp, make.names(gsub("*.csv$", "", temp))), 
         read.csv), envir = .GlobalEnv)

Pero, de nuevo, a menudo es mejor dejarlos en una sola lista.

Un rápido y conciso tidyverse solución: (más del doble de rápido que Base Rread.csv)

tbl <-
    list.files(pattern = "*.csv") %>% 
    map_df(~read_csv(.))

y tabla de datos‘s fread() incluso puede reducir esos tiempos de carga a la mitad nuevamente. (para 1/4 de Base R veces)

library(data.table)

tbl_fread <- 
    list.files(pattern = "*.csv") %>% 
    map_df(~fread(.))

los stringsAsFactors = FALSE El argumento mantiene el factor de marco de datos libre (y como señala Marbel, es la configuración predeterminada para fread)

Si el encasillado es descarado, puede forzar que todas las columnas sean como personajes con el col_types argumento.

tbl <-
    list.files(pattern = "*.csv") %>% 
    map_df(~read_csv(., col_types = cols(.default = "c")))

Si desea sumergirse en subdirectorios para construir su lista de archivos que eventualmente enlazar, asegúrese de incluir el nombre de la ruta, así como de registrar los archivos con sus nombres completos en su lista. Esto permitirá que el trabajo de vinculación continúe fuera del directorio actual. (Pensar que los nombres de ruta completos funcionan como pasaportes para permitir el movimiento de regreso a través de las ‘fronteras’ del directorio).

tbl <-
    list.files(path = "./subdirectory/",
               pattern = "*.csv", 
               full.names = T) %>% 
    map_df(~read_csv(., col_types = cols(.default = "c"))) 

Como Hadley describe aquí (aproximadamente a la mitad):

map_df(x, f) es efectivamente lo mismo que do.call("rbind", lapply(x, f))….

Característica de bonificaciónagregando nombres de archivo a los registros por solicitud de función de Niks en los comentarios a continuación:

* Agregar original filename a cada registro.

Explicación del código: cree una función para agregar el nombre del archivo a cada registro durante la lectura inicial de las tablas. Luego usa esa función en lugar de la simple read_csv() función.

read_plus <- function(flnm) 
    read_csv(flnm) %>% 
        mutate(filename = flnm)


tbl_with_sources <-
    list.files(pattern = "*.csv", 
               full.names = T) %>% 
    map_df(~read_plus(.))

(Los enfoques de encasillamiento y manejo de subdirectorios también se pueden manejar dentro del read_plus() funcionan de la misma manera que se ilustra en la segunda y tercera variantes sugeridas anteriormente).

### Benchmark Code & Results 
library(tidyverse)
library(data.table)
library(microbenchmark)

### Base R Approaches
#### Instead of a dataframe, this approach creates a list of lists
#### removed from analysis as this alone doubled analysis time reqd
# lapply_read.delim <- function(path, pattern = "*.csv") 
#     temp = list.files(path, pattern, full.names = TRUE)
#     myfiles = lapply(temp, read.delim)
# 

#### `read.csv()`
do.call_rbind_read.csv <- function(path, pattern = "*.csv") 
    files = list.files(path, pattern, full.names = TRUE)
    do.call(rbind, lapply(files, function(x) read.csv(x, stringsAsFactors = FALSE)))


map_df_read.csv <- function(path, pattern = "*.csv") 
    list.files(path, pattern, full.names = TRUE) %>% 
    map_df(~read.csv(., stringsAsFactors = FALSE))



### *dplyr()*
#### `read_csv()`
lapply_read_csv_bind_rows <- function(path, pattern = "*.csv") 
    files = list.files(path, pattern, full.names = TRUE)
    lapply(files, read_csv) %>% bind_rows()


map_df_read_csv <- function(path, pattern = "*.csv") 
    list.files(path, pattern, full.names = TRUE) %>% 
    map_df(~read_csv(., col_types = cols(.default = "c")))


### *data.table* / *purrr* hybrid
map_df_fread <- function(path, pattern = "*.csv") 
    list.files(path, pattern, full.names = TRUE) %>% 
    map_df(~fread(.))


### *data.table*
rbindlist_fread <- function(path, pattern = "*.csv") 
    files = list.files(path, pattern, full.names = TRUE)
    rbindlist(lapply(files, function(x) fread(x)))


do.call_rbind_fread <- function(path, pattern = "*.csv") 
    files = list.files(path, pattern, full.names = TRUE)
    do.call(rbind, lapply(files, function(x) fread(x, stringsAsFactors = FALSE)))



read_results <- function(dir_size)
    microbenchmark(
        # lapply_read.delim = lapply_read.delim(dir_size), # too slow to include in benchmarks
        do.call_rbind_read.csv = do.call_rbind_read.csv(dir_size),
        map_df_read.csv = map_df_read.csv(dir_size),
        lapply_read_csv_bind_rows = lapply_read_csv_bind_rows(dir_size),
        map_df_read_csv = map_df_read_csv(dir_size),
        rbindlist_fread = rbindlist_fread(dir_size),
        do.call_rbind_fread = do.call_rbind_fread(dir_size),
        map_df_fread = map_df_fread(dir_size),
        times = 10L) 


read_results_lrg_mid_mid <- read_results('./testFolder/500MB_12.5MB_40files')
print(read_results_lrg_mid_mid, digits = 3)

read_results_sml_mic_mny <- read_results('./testFolder/5MB_5KB_1000files/')
read_results_sml_tny_mod <- read_results('./testFolder/5MB_50KB_100files/')
read_results_sml_sml_few <- read_results('./testFolder/5MB_500KB_10files/')

read_results_med_sml_mny <- read_results('./testFolder/50MB_5OKB_1000files')
read_results_med_sml_mod <- read_results('./testFolder/50MB_5OOKB_100files')
read_results_med_med_few <- read_results('./testFolder/50MB_5MB_10files')

read_results_lrg_sml_mny <- read_results('./testFolder/500MB_500KB_1000files')
read_results_lrg_med_mod <- read_results('./testFolder/500MB_5MB_100files')
read_results_lrg_lrg_few <- read_results('./testFolder/500MB_50MB_10files')

read_results_xlg_lrg_mod <- read_results('./testFolder/5000MB_50MB_100files')


print(read_results_sml_mic_mny, digits = 3)
print(read_results_sml_tny_mod, digits = 3)
print(read_results_sml_sml_few, digits = 3)

print(read_results_med_sml_mny, digits = 3)
print(read_results_med_sml_mod, digits = 3)
print(read_results_med_med_few, digits = 3)

print(read_results_lrg_sml_mny, digits = 3)
print(read_results_lrg_med_mod, digits = 3)
print(read_results_lrg_lrg_few, digits = 3)

print(read_results_xlg_lrg_mod, digits = 3)

# display boxplot of my typical use case results & basic machine max load
par(oma = c(0,0,0,0)) # remove overall margins if present
par(mfcol = c(1,1)) # remove grid if present
par(mar = c(12,5,1,1) + 0.1) # to display just a single boxplot with its complete labels
boxplot(read_results_lrg_mid_mid, las = 2, xlab = "", ylab = "Duration (seconds)", main = "40 files @ 12.5MB (500MB)")
boxplot(read_results_xlg_lrg_mod, las = 2, xlab = "", ylab = "Duration (seconds)", main = "100 files @ 50MB (5GB)")

# generate 3x3 grid boxplots
par(oma = c(12,1,1,1)) # margins for the whole 3 x 3 grid plot
par(mfcol = c(3,3)) # create grid (filling down each column)
par(mar = c(1,4,2,1)) # margins for the individual plots in 3 x 3 grid
boxplot(read_results_sml_mic_mny, las = 2, xlab = "", ylab = "Duration (seconds)", main = "1000 files @ 5KB (5MB)", xaxt = 'n')
boxplot(read_results_sml_tny_mod, las = 2, xlab = "", ylab = "Duration (milliseconds)", main = "100 files @ 50KB (5MB)", xaxt = 'n')
boxplot(read_results_sml_sml_few, las = 2, xlab = "", ylab = "Duration (milliseconds)", main = "10 files @ 500KB (5MB)",)

boxplot(read_results_med_sml_mny, las = 2, xlab = "", ylab = "Duration (microseconds)        ", main = "1000 files @ 50KB (50MB)", xaxt = 'n')
boxplot(read_results_med_sml_mod, las = 2, xlab = "", ylab = "Duration (microseconds)", main = "100 files @ 500KB (50MB)", xaxt = 'n')
boxplot(read_results_med_med_few, las = 2, xlab = "", ylab = "Duration (seconds)", main = "10 files @ 5MB (50MB)")

boxplot(read_results_lrg_sml_mny, las = 2, xlab = "", ylab = "Duration (seconds)", main = "1000 files @ 500KB (500MB)", xaxt = 'n')
boxplot(read_results_lrg_med_mod, las = 2, xlab = "", ylab = "Duration (seconds)", main = "100 files @ 5MB (500MB)", xaxt = 'n')
boxplot(read_results_lrg_lrg_few, las = 2, xlab = "", ylab = "Duration (seconds)", main = "10 files @ 50MB (500MB)")

Caso de uso medio

Comparación de diagrama de caja del tiempo transcurrido, mi caso de uso típico

Caso de uso más grande

Comparación de diagrama de caja del tiempo transcurrido para una carga extragrande

Variedad de casos de uso

Filas: recuentos de archivos (1000, 100, 10)
Columnas: tamaño del marco de datos final (5 MB, 50 MB, 500 MB)
(haga clic en la imagen para ver el tamaño original)Comparación de diagrama de caja de las variaciones del tamaño del directorio

Los resultados de la base R son mejores para los casos de uso más pequeños en los que la sobrecarga de llevar las bibliotecas C de purrr y dplyr superan las ganancias de rendimiento que se observan al realizar tareas de procesamiento a mayor escala.

si desea ejecutar sus propias pruebas, puede encontrar útil este script bash.

for ((i=1; i<=$2; i++)); do 
  cp "$1" "$1:0:8_$i.csv";
done

bash what_you_name_this_script.sh "fileName_you_want_copied" 100 creará 100 copias de su archivo numeradas secuencialmente (después de los 8 caracteres iniciales del nombre del archivo y un guión bajo).

Atribuciones y agradecimientos

Con agradecimiento especial a:

  • Tyler Rinker y Akrun por demostrar el microbenchmark.
  • Jake Kaupp por presentarme a map_df() aquí.
  • David McLaughlin por sus útiles comentarios sobre cómo mejorar las visualizaciones y discutir / confirmar las inversiones de rendimiento observadas en los resultados del análisis de pequeños archivos y marcos de datos pequeños.
  • marbel por señalar el comportamiento predeterminado para fread(). (Necesito estudiar data.table.)

Aquí hay algunas opciones para convertir los archivos .csv en un data.frame usando R base y algunos de los paquetes disponibles para leer archivos en R.

Esto es más lento que las opciones siguientes.

# Get the files names
files = list.files(pattern="*.csv")
# First apply read.csv, then rbind
myfiles = do.call(rbind, lapply(files, function(x) read.csv(x, stringsAsFactors = FALSE)))

Editar: - Algunas opciones adicionales usando data.table y readr

A fread() versión, que es una función de la data.table paquete. Esta es, con mucho, la opción más rápida en R.

library(data.table)
DT = do.call(rbind, lapply(files, fread))
# The same using `rbindlist`
DT = rbindlist(lapply(files, fread))

Usando readr, que es otro paquete para leer archivos csv. Es mas lento que fread, más rápido que la base R pero tiene diferentes funcionalidades.

library(readr)
library(dplyr)
tbl = lapply(files, read_csv) %>% bind_rows()

Reseñas y valoraciones del tutorial

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *