2012-03-23 17 views
8

Tengo 15 millones de archivos CSV, cada uno con dos columnas (entero y flotante), y entre 5 y 500 filas. Cada archivo se ve algo como:¿La forma más rápida de importar millones de archivos en R?

3453,0.034 
31,0.031 
567,0.456 
... 

Actualmente, estoy interactuando sobre todos los archivos, y el uso de read.csv() importar cada archivo en una lista grande. Aquí hay una versión simplificada:

allFileNames = Sys.glob(sprintf("%s/*/*/results/*/*", dir)) 

s$scores = list() 

for (i in 1:length(allFileNames)){ 
     if ((i %% 1000) == 0){ 
      cat(sprintf("%d of %d\n", i, length(allFileNames))) 
     } 

     fileName = allFileNames[i] 
     approachID = getApproachID(fileName) 
     bugID = getBugID(fileName) 

     size = file.info(fileName)$size 
     if (!is.na(size) && size > 0){ # make sure file exists and is not empty 
      tmp = read.csv(fileName, header=F, colClasses=c("integer", "numeric")) 
      colnames(tmp) = c("fileCode", "score") 
      s$scores[[approachID]][[bugID]] = tmp 
     } else { 
      # File does not exist, or is empty. 
      s$scores[[approachID]][[bugID]] = matrix(-1, ncol=2, nrow=1) 
     } 
    } 

tmp = read.csv(fileName, header=F, colClasses=c("integer", "numeric") 

Más adelante en mi código, volver a través de cada matriz en la lista, y calcular algunas métricas.

Después de iniciar este proceso de importación, parece que tomará del orden de 3 a 5 días para completarse. ¿Hay una manera más rápida de hacer esto?

EDIT: He agregado más detalles sobre mi código.

+1

posible duplicado de [leer rápidamente tablas muy grandes como tramas de datos en R] (http://stackoverflow.com/questions/1727772/quickly-reading-very-large-tables-as-dataframes-in-r) – joran

+1

¿Qué estás tratando de hacer? ¿Construyó una matriz única con todos los datos, o leyó y procesó cada matriz por separado? –

+0

Esto es relevante para cargar muchos archivos a la vez: http://stackoverflow.com/questions/3764292/ – Ben

Respuesta

6

Usando scan (como el estado de Joshua en el comentario) podría ser más rápido (3-4 veces):

scan(fileName, what=list(0L,0.0), sep=",", dec=".", quiet=TRUE) 

principal diferencia es que la lista scan regresa con dos elementos y read.csv vuelve data.frame.

+0

Estaba pensando algo así como: 'List [[1]] <- matrix (scan (fileName, what = 0, sep =", "), ncol = 2, byrow = TRUE)'. –

+1

Gracias chicos. Como mencioné en otro comentario, al cambiar a '' tmp <- matrix (scan (fileName, what = 0, sep = ",", quiet = T), ncol = 2, byrow = TRUE) '', mi código es corriendo aproximadamente el doble de rápido. Después de hacer un '' system.time() '', parece que la mayoría del tiempo requerido es en IO, así que supongo que tendré que esperar un poco. – stepthom

7

No me queda claro en su objetivo, pero si usted está tratando de leer todos estos archivos en una única estructura de datos R, luego veo dos grandes problemas de rendimiento: los tiempos de acceso

  1. Archivo - desde el momento en que solicita read.csv, se inicia una gran cantidad de procesos complejos en su máquina que implican ver si ese archivo existe, encontrar la ubicación de ese archivo en la memoria o en el disco (y leer los datos en la memoria, si es necesario), luego interpretando los datos dentro de R. Esperaría que esto sea una desaceleración casi constante a medida que lea en millones de archivos.
  2. Creciendo su única estructura de datos con cada nuevo archivo leído. Cada vez que quiera agregar algunas filas a su matriz, es probable que necesite reasignar un trozo de memoria de tamaño similar para almacenar la matriz más grande. Si está aumentando su matriz 15 millones de veces, seguramente notará una disminución del rendimiento aquí. Con este problema, el rendimiento empeorará progresivamente a medida que lea en más archivos.

Realice algunos perfiles rápidos y vea cuánto tiempo están tardando las lecturas. Si disminuyen progresivamente a medida que lee en más archivos, entonces centrémonos en el problema # 2. Si es constantemente lento, entonces nos preocupemos por el problema # 1.

soluciones relativas, yo diría que usted podría comenzar con dos cosas:

  1. combinar los archivos CSV en otro lenguaje de programación. Un simple script de shell probablemente haría el trabajo por usted si solo está pasando por encima de los archivos y concatenándolos en un solo archivo grande. Como mencionan Joshua y Richie a continuación, es posible que pueda optimizar esto sin tener que desviarse a otro idioma utilizando las funciones más eficaces scan() o readlines().
  2. Pre-dimensione su estructura de datos unificada. Si está utilizando una matriz, por ejemplo, establezca el número de filas en ~ 15 millones x 100. Esto asegurará que solo tenga que encontrar espacio en la memoria para este objeto una vez, y el resto de las operaciones simplemente insertarán datos en la matriz pre-dimensionada.

Agregue algunos más detalles de su código (¿cómo se ve la lista que está usando?) Y podremos ser más útiles.

+3

También tenga en cuenta que 'scan' es más apropiado que' read.csv' ya que los datos podrían almacenarse como numéricos. –

+0

O posiblemente incluso 'readLines' +' writeLines' si OP solo quiere combinar los archivos en uno solo. –

+0

@Jeff - Gracias por esta respuesta detallada. No creo que pueda combinar todos los archivos en uno grande, porque necesito que se separen para su posterior análisis. (Cada archivo representa una ejecución de mi experimento.) En cuanto a la preasignación de mi estructura de datos, ¿hay alguna manera de preasignar el tamaño de mi lista ('' s $ scores'')? Por cierto, no veo que la desaceleración sea cada vez peor, así que creo que el rendimiento está dominado por el disco IO. – stepthom

0

Como mencionó Jeff, hay varias cosas aquí que podrían llevar mucho tiempo. El problema podría ser el acceso a archivos, o leer en los archivos, o quedarse sin memoria cuando tienes 15 millones de marcos de datos en RAM.Para complicar el problema, el cuello puede variar según las especificaciones de su máquina (por ejemplo, un disco duro lento ralentizará la lectura en los archivos, la falta de memoria RAM será un problema con un alto conteo de archivos). Para resolver el problema, tendrá que hacer algunos perfiles.

Trry acaba de leer aproximadamente 10000 archivos para empezar, y llamando al system.time o, más sofisticado, usando rbenchmark para ver lo que lleva más tiempo.

Luego mirada en el acoplamiento de Joran

Quickly reading very large tables as dataframes in R

y ver si alguno de la técnica no le ayuda.

2

¿Qué tal este flujo de trabajo general? Sin embargo, no probado.

my.list.of.files <- list.files(pattern = ".txt") # char vector of filenames 
my.data <- sapply(my.list.of.files, FUN = function(x) { 
      # read file using scan, craft the output to two columns 
     }) # result is merged 

#or if you use simplify= FALSE 
my.data <- sapply(my.list.of.files, FUN = function(x) { 
      # read file using scan (or some other method), craft the output to two columns 
     }, simplify = FALSE) #you get a list 
my.data <- do.call("rbind", my.data) 
+0

Sé que esto es solo una plantilla, pero tenga en cuenta que si tuviera todos los 15 millones de archivos en un solo directorio, esa puede ser otra causa de sus problemas de rendimiento, también. –

+1

Tenga en cuenta que 'sapply' es un poco lento porque R tiene que hacer un trabajo extra para averiguar cómo simplificar la salida. De la familia '* apply',' lapply' es el más rápido, por lo tanto, tal vez más apropiado aquí. – flodel

+0

@Jeff, esto no es algo que podamos explicar. @flodel, incluso cuando especifica 'simplify = FALSE'? –

Cuestiones relacionadas