2012-01-30 8 views
8

La lectura de ~ 5x10^6 valores R en R desde un archivo de texto es relativamente lenta en mi máquina (unos segundos, y leo varios de esos archivos), incluso con scan(..., what="numeric", nmax=5000) o trucos similares. ¿Valdría la pena intentar un contenedor Rcpp para este tipo de tarea (por ejemplo, Armadillo tiene algunas utilidades para leer archivos de texto)? ¿O es probable que esté perdiendo el tiempo por poco o nada de rendimiento debido a una sobrecarga de interfaz esperada? No estoy seguro de lo que actualmente limita la velocidad (rendimiento intrínseco de la máquina, ¿o sí?) Es una tarea que repito muchas veces al día, generalmente, y el formato de archivo siempre es el mismo, 1000 columnas, alrededor de 5000 filas.más rápido que escanear() con Rcpp?

Aquí hay un archivo de muestra para jugar, si es necesario.

nr <- 5000 
nc <- 1000 

m <- matrix(round(rnorm(nr*nc),3),nr=nr) 

cat(m[1, -1], "\n", file = "test.txt") # first line is shorter 
write.table(m[-1, ], file = "test.txt", append=TRUE, 
      row.names = FALSE, col.names = FALSE) 

actualización: Probé read.csv.sql y también load("test.txt", arma::raw_ascii) usando Armadillo y ambos eran más lenta que la solución scan.

+3

Pruebe 'read.csv.sql' en sqldf y vea si es más rápido. Es solo una línea de código. http://sqldf.googlecode.com –

+0

Intenté 'system.time (b <- read.csv.sql (" test.txt ", header = FALSE, sep =" "))' y fue más lento que 'system .time (a <- scan ("test.txt", what = "numérico")) '. Además, creo que almacenar los datos en una matriz debería ser más eficiente que en un 'data.frame' – baptiste

Respuesta

8

Recomiendo retirar fread en la última versión de data.table. La versión en CRAN (1.8.6) aún no tiene fread (en el momento de esta publicación) por lo que debería poder obtenerla si la instala desde la última fuente en R-forge. Ver here.

+0

que es de hecho mucho más rápido, ¡gracias! – baptiste

5

Tenga en cuenta que no soy un experto en R pero quizás el concepto se aplica también aquí: generalmente leer cosas binarias es mucho más rápido que leer archivos de texto. Si sus archivos fuente no cambian con frecuencia (por ejemplo, está ejecutando versiones variadas de su script/programa en los mismos datos), intente leerlos a través de scan() una vez y guárdelos en un formato binario (el manual tiene un capítulo sobre exportando archivos binarios). A partir de ahí, puede modificar su programa para leer la entrada binaria.

@Rcpp: scan() & es probable que los amigos invoquen una implementación nativa (como fscanf()) para que escribir sus propias funciones de lectura de archivos mediante Rcpp no ​​proporcione una gran ganancia de rendimiento. Aún así puede intentarlo (y optimizar para sus datos particulares).

+0

re Rcpp, sí, esa es mi preocupación: impleméntala solo para ver que realiza lo mismo que' scan() '. Esperaba que alguien ya se lo haya imaginado. – baptiste

+0

Espero que sea mucho más rápido, pero por supuesto menos general. –

3

Sí, es casi seguro que pueda crear algo que vaya más rápido que read.csv/scan. Sin embargo, para la lectura de archivos de alto rendimiento, existen algunos trucos que ya te permiten ir mucho más rápido, por lo que cualquier cosa que hagas competiría contra ellos.

Como mencionó Mathias, si sus archivos no cambian muy a menudo, puede almacenarlos en caché llamando al save, y luego restaurarlos con load. (Asegúrese de usar ascii = FALSE, ya que leer los archivos binarios será más rápido.)

En segundo lugar, como mencionó Gabor, a menudo puede obtener un aumento sustancial de rendimiento leyendo su archivo en una base de datos y luego desde esa base de datos en R.

En tercer lugar, puede usar el paquete HadoopStreaming para usar las capacidades de lectura de archivos de Hadoop.

Para obtener más ideas sobre estas técnicas, consulte Quickly reading very large tables as dataframes in R.

+0

gracias. Creo que he usado todos los consejos de ese hilo SO, y no, guardar los datos como '.rda' o de lo contrario no es realmente una opción, ya que es la primera importación que me molesta. Comprobaré 'sqldf', que brevemente consideré pero la sintaxis me confundió. – baptiste

4

Salut Baptiste,

de entrada/salida de datos es un tema enorme, tan grande que R viene con su propio manual on data input/output.

Las funciones básicas de R pueden ser lentas porque son muy genéricas. Si conoce su formato, puede escribir fácilmente un adaptador de importación más rápido. Si conoce sus dimensiones también, es aún más fácil ya que solo necesita una asignación de memoria.

Edit: Como primera aproximación, escribiría un trazador de líneas de C++.Abra un archivo, lea una línea, divídalo en tokens, asigne un vector<vector<double> > o algo así. Incluso si usa push_back() en elementos vectoriales individuales, debe ser competitivo con scan(), esto es, creo.

Una vez tuve una buena clase de csv reader en C++ basada en el código del propio Brian Kernighan. Bastante genérico (para archivos csv), bastante poderoso.

A continuación, puede exprimir el rendimiento como mejor le parezca.

Además de edición: Este SO question tiene una serie de indicadores para el caso de lectura csv, y las referencias al libro de Kernighan y Plauger.

+0

no sé la dimensión exacta (bueno, alguna herramienta de Unix podría averiguarlo), pero 5000 es una buena estimación aproximada aproximada – baptiste

Cuestiones relacionadas