2012-09-18 11 views
6

Ejecuto Matlab R2011b y R versión 2.13.1 en Linux Mint v12 con 16 GB de RAM.textscan en Matlab usa una RAM excesiva en comparación con un método similar en R

Tengo un archivo csv. Las primeras 5 filas (y encabezado) son:

#RIC,Date[G],Time[G],GMT Offset,Type,Price,Volume 
DAEG.OQ,07-JUL-2011,15:10:03.424,-4,Trade,1.68,1008 
DAEG.OQ,07-JUL-2011,15:10:03.424,-4,Trade,1.68,1008 
DAEG.OQ,07-JUL-2011,15:10:03.424,-4,Trade,1.66,300 
DAEG.OQ,07-JUL-2011,15:10:03.424,-4,Trade,1.65,1000 
DAEG.OQ,07-JUL-2011,15:10:03.464,-4,Trade,1.65,3180 

El archivo es grande (aproximadamente 900 MB). Dada la combinación de carácter y datos numéricos, se podría leer este archivo en Matlab de la siguiente manera:

fid1 = fopen('/home/MyUserName/Temp/X.csv'); 
D = textscan(fid1, '%s%s%s%f%s%f%f', 'Delimiter', ',', 'HeaderLines', 1); 
fclose(fid1); 

Aunque el archivo es 900MB, cuando se ejecuta el código anterior, monitor del sistema indica que mi uso de la RAM salta de cerca de 2 GB a 10 GB . Peor aún, si intento este mismo procedimiento con un archivo csv un poco más grande (alrededor de 1,2 GB), mi RAM alcanza un máximo de 16 GB y Matlab nunca logra terminar de leer en los datos (simplemente permanece bloqueado en el modo "ocupado").

Si quisiera leer el mismo archivo en R, puede ser que utilice:

D <- read.csv("/home/MyUserName/Temp/X.csv", stringsAsFactors=FALSE) 

Esto toma un poco más de Matlab, pero mi monitor del sistema indica el uso de RAM sólo se salta de 2 GB a 3.3GB (mucho más razonable dado el tamaño del archivo original).

Mi pregunta tiene dos partes:

1) ¿Por qué es textscan un cerdo como la memoria en este escenario?

2) ¿Hay otro enfoque que podría utilizar para obtener un archivo csv de 1,2 GB de este tipo en Matlab en mi sistema sin tener que maximizar la memoria RAM?

EDIT: Solo para aclarar, tengo curiosidad acerca de si existe una solución de solo matlab, es decir, no estoy interesado en una solución que implique utilizar un lenguaje diferente para dividir el archivo csv en más pequeño trozos (como esto es lo que ya estoy haciendo). Lo siento Trav1s, debería haber dejado esto en claro desde el principio.

Respuesta

2

El problema probablemente sea que esas cadenas "% s" se están leyendo en Matlab cellstrs, que son una estructura de datos ineficaz en la memoria para cadenas de baja cardinalidad. Los Cellstrs son pésimos para grandes datos tabulares como este. Cada cadena termina siendo almacenada en una matriz primitiva separada char, cada una con unos 400 bytes de problemas de sobrecarga y fragmentación. Con su archivo de 900MB, se ve como 18 millones de filas; 4 cadenas por fila, y eso es alrededor de 10-20 GB de cellstrs para mantener esas cadenas. Ugh.

Lo que quiere es convertir esas cadenas en tipos de datos primitivos compactos a medida que van entrando, en lugar de obtener las 18 millones de filas sorbidas en cadenas de celdas voluminosas a la vez. Las fechas y marcas de tiempo como datenums o cualquier representación numérica que esté usando, y las cadenas de baja cardinalidad como matrices 2-d char o algún equivalente de una variable categórica. (Dado el tamaño del conjunto de datos, probablemente desee que esas cadenas se representen como identificadores numéricos simples con una tabla de búsqueda, no caracteres.)

Una vez que haya decidido su estructura de datos compacta, hay un par de enfoques para cargarla. Podría simplemente dividir la lectura en fragmentos en Matlab puro: use textscan() llamadas en un ciclo para leer en 1000 líneas en una vez, analizar y convertir las celdas en ese trozo en sus formas compactas, almacenar todos los resultados, y cat juntos al final de la lectura. Eso mantendrá los requisitos de memoria pico más bajos.

Si va a hacer un montón de trabajo como este, y el rendimiento importa, puede bajar a Java y escribir su propio analizador que puede convertir las cadenas y las fechas a medida que entran, antes de entregarlos volver a Matlab como tipos de datos más compactos. No es difícil, y el método Java puede ser llamado directamente desde Matlab, por lo que esto solo puede contar como usar un idioma diferente.

+0

Gracias Andrew, parece una buena respuesta a la pregunta, pero no tendré oportunidad de leerla en detalle hasta mañana (estoy en el trabajo). Lamento la demora. –

+0

Andrew, buena respuesta +1, gracias. –

0

Para 2) puede intentar utilizar el comando csvread. No sé cómo se compara el rendimiento, pero al menos es una alternativa.

Otra alternativa es leer el archivo usando un lenguaje mucho más rápido como C o awk, y luego dividirlo en archivos más pequeños. Leer muchos pequeños archivos secuencialmente requerirá menos memoria que un archivo grande.

+0

Hola Trav1s, gracias por las sugerencias. Desafortunadamente, csvread (o dlmread para el caso) solo funciona con datos puramente numéricos. Entonces no son buenos en esta situación (ver mis datos de muestra en cuestión). Con respecto a su segunda sugerencia, eso es realmente lo que estoy haciendo en este momento, aunque estoy usando R, no C, ya que las funciones de importación de datos para R no son tan intensivas en datos. –

Cuestiones relacionadas