Error de memoria al usar pandas read_csv

Estoy tratando de hacer algo bastante simple, leyendo un gran archivo csv en un dataframe de pandas.

data = pandas.read_csv(filepath, header = 0, sep = DELIMITER,skiprows = 2) 

El código falla con un MemoryError , o simplemente nunca termina.

El uso de Mem en el administrador de tareas se detuvo a 506 Mb y luego de 5 minutos sin cambios y sin actividad de la CPU en el proceso, lo detuve.

Estoy usando pandas versión 0.11.0.

Soy consciente de que solía haber un problema de memoria con el analizador de archivos, pero de acuerdo con http://wesmckinney.com/blog/?p=543 esto debería haberse solucionado.

El archivo que estoy tratando de leer es de 366 Mb, el código anterior funciona si corto el archivo a algo corto (25 Mb).

También ha ocurrido que aparece un mensaje emergente que me dice que no puede escribir en la dirección 0x1e0baf93 …

Stacktrace:

 Traceback (most recent call last): File "F:\QA ALM\Python\new WIM data\new WIM data\new_WIM_data.py", line 25, in  wimdata = pandas.read_csv(filepath, header = 0, sep = DELIMITER,skiprows = 2 ) File "C:\Program Files\Python\Anaconda\lib\site-packages\pandas\io\parsers.py" , line 401, in parser_f return _read(filepath_or_buffer, kwds) File "C:\Program Files\Python\Anaconda\lib\site-packages\pandas\io\parsers.py" , line 216, in _read return parser.read() File "C:\Program Files\Python\Anaconda\lib\site-packages\pandas\io\parsers.py" , line 643, in read df = DataFrame(col_dict, columns=columns, index=index) File "C:\Program Files\Python\Anaconda\lib\site-packages\pandas\core\frame.py" , line 394, in __init__ mgr = self._init_dict(data, index, columns, dtype=dtype) File "C:\Program Files\Python\Anaconda\lib\site-packages\pandas\core\frame.py" , line 525, in _init_dict dtype=dtype) File "C:\Program Files\Python\Anaconda\lib\site-packages\pandas\core\frame.py" , line 5338, in _arrays_to_mgr return create_block_manager_from_arrays(arrays, arr_names, axes) File "C:\Program Files\Python\Anaconda\lib\site-packages\pandas\core\internals .py", line 1820, in create_block_manager_from_arrays blocks = form_blocks(arrays, names, axes) File "C:\Program Files\Python\Anaconda\lib\site-packages\pandas\core\internals .py", line 1872, in form_blocks float_blocks = _multi_blockify(float_items, items) File "C:\Program Files\Python\Anaconda\lib\site-packages\pandas\core\internals .py", line 1930, in _multi_blockify block_items, values = _stack_arrays(list(tup_block), ref_items, dtype) File "C:\Program Files\Python\Anaconda\lib\site-packages\pandas\core\internals .py", line 1962, in _stack_arrays stacked = np.empty(shape, dtype=dtype) MemoryError Press any key to continue . . . 

Un poco de historia: estoy tratando de convencer a la gente de que Python puede hacer lo mismo que R. Para esto estoy tratando de replicar una secuencia de comandos R que lo hace

 data <- read.table(paste(INPUTDIR,config[i,]$TOEXTRACT,sep=""), HASHEADER, DELIMITER,skip=2,fill=TRUE) 

R no solo se las arregla para leer bien el archivo anterior, sino que incluso lee varios de estos archivos en un bucle for (y luego hace algunas cosas con los datos). Si Python tiene un problema con archivos de ese tamaño, podría estar luchando una batalla perdida …

Limitación de memoria de Windows

Los errores de memoria ocurren mucho con python cuando se usa la versión de 32 bits en Windows. Esto se debe a que los procesos de 32 bits solo obtienen 2 GB de memoria para jugar de forma predeterminada.

Trucos para bajar el uso de memoria

Si no está usando python de 32 bits en Windows pero está buscando mejorar la eficiencia de su memoria mientras lee archivos csv, hay un truco.

La función pandas.read_csv toma una opción llamada dtype . Esto permite a los pandas saber qué tipos existen dentro de sus datos csv.

Como funciona esto

De forma predeterminada, los pandas intentarán adivinar qué tipos de archivo tiene su archivo csv. Esta es una operación muy pesada porque mientras determina el tipo de dtype, debe mantener todos los datos sin procesar como objetos (cadenas) en la memoria.

Ejemplo

Digamos que su csv se ve así:

 name, age, birthday Alice, 30, 1985-01-01 Bob, 35, 1980-01-01 Charlie, 25, 1990-01-01 

Por supuesto, este ejemplo no es un problema para leer en la memoria, pero es solo un ejemplo.

Si los pandas leyeran el archivo csv anterior sin ninguna opción de tipo de dtype, la edad se almacenaría como cadenas en la memoria hasta que los pandas hayan leído suficientes líneas del archivo csv para hacer una conjetura calificada.

Creo que lo predeterminado en pandas es leer 1,000,000 de filas antes de adivinar el tipo de letra.

Solución

Al especificar dtype={'age':int} como una opción para .read_csv() , los pandas sabrán que la edad debe interpretarse como un número. Esto te ahorra mucha memoria.

Problema con datos corruptos

Sin embargo, si su archivo csv se corrompiera, de esta manera:

 name, age, birthday Alice, 30, 1985-01-01 Bob, 35, 1980-01-01 Charlie, 25, 1990-01-01 Dennis, 40+, None-Ur-Bz 

Luego, al especificar dtype={'age':int} se romperá el .read_csv() , porque no puede convertir "40+" en int. ¡Así que desinfecta tus datos con cuidado!

Aquí puede ver cómo el uso de memoria de un dataframe de pandas es mucho mayor cuando las flotaciones se mantienen como cadenas:

Inténtalo tú mismo

 df = pd.DataFrame(pd.np.random.choice(['1.0', '0.6666667', '150000.1'],(100000, 10))) resource.getrusage(resource.RUSAGE_SELF).ru_maxrss # 224544 (~224 MB) df = pd.DataFrame(pd.np.random.choice([1.0, 0.6666667, 150000.1],(100000, 10))) resource.getrusage(resource.RUSAGE_SELF).ru_maxrss # 79560 (~79 MB) 

Tuve el mismo problema de memoria con una simple lectura de un archivo de texto delimitado por tabulaciones de alrededor de 1 GB de tamaño (más de 5,5 millones de registros) y esto resolvió el problema de la memoria:

 df = pd.read_csv(myfile,sep='\t') # didn't work, memory error df = pd.read_csv(myfile,sep='\t',low_memory=False) # worked fine and in less than 30 seconds 

Spyder 3.2.3 Python 2.7.13 64bits

Utilizo Pandas en mi caja de Linux y enfrenté muchas memory leaks que solo se resolvieron después de actualizar Pandas a la última versión después de clonarla desde github.

No hay error para Pandas 0.12.0 y NumPy 1.8.0.

He logrado crear un gran DataFrame y guardarlo en un archivo csv y luego leerlo con éxito. Por favor vea el ejemplo aquí . El tamaño del archivo es de 554 Mb (incluso funcionó para archivos de 1.1 Gb, tomó más tiempo, para generar una frecuencia de uso de archivos de 1.1Gb de 30 segundos). Aunque tengo 4Gb de RAM disponible.

Mi sugerencia es intentar actualizar Pandas. Otra cosa que podría ser útil es intentar ejecutar su script desde la línea de comandos, porque para R no está usando Visual Studio (esto ya fue sugerido en los comentarios a su pregunta), por lo tanto, tiene más recursos disponibles.

También me encontré con este problema cuando estaba ejecutando en una máquina virtual, o en otro lugar donde la memoria está muy limitada. No tiene nada que ver con pandas o numpy o csv, pero siempre sucederá si intentas usar más memoria como se te permite, no solo en python.

La única posibilidad que tienes es lo que ya intentaste, intenta triturar el objeto grande en trozos más pequeños que encajen en la memoria.

Si alguna vez se preguntaba de qué se trata MapReduce, descubrió por sí mismo … MapReduce intentaría distribuir los trozos entre muchas máquinas, trataría de procesar el trozo en una máquina, una tras otra.

Lo que descubrió con la concatenación de los archivos de trozos podría ser un problema, tal vez haya alguna copia necesaria en esta operación … pero al final esto quizás lo ahorre en su situación actual, pero si su csv se hace un poco más grande podrías correr contra esa pared otra vez …

También podría ser, que los pandas son tan inteligentes, que en realidad solo cargan los fragmentos de datos individuales en la memoria si haces algo con ellos, como concatenar a un gran df?

Varias cosas que puedes probar:

  • No cargue todos los datos a la vez, sino que los divide en partes.
  • Que yo sepa, hdf5 es capaz de hacer estos trozos automáticamente y solo carga la parte en la que trabaja su progtwig actualmente.
  • Mira si los tipos están bien, una cadena ‘0.111111’ necesita más memoria que un flotador
  • ¿Qué necesita realmente? Si existe la dirección como una cadena, es posible que no la necesite para el análisis numérico …
  • Una base de datos puede ayudar a acceder y cargar solo las partes que realmente necesita (por ejemplo, solo el 1% de usuarios activos)

Aunque esta es una solución alternativa, no tanto como una solución, intentaría convertir ese CSV a JSON (debería ser trivial) y usar el método read_json lugar: he estado escribiendo y leyendo JSON / dataframes (100s de MB) en Pandas De esta manera sin ningún problema en absoluto.

chunksize mientras leía un gran archivo CSV

 reader = pd.read_csv(filePath,chunksize=1000000,low_memory=False,header=0) 

La lectura es ahora la lista. Podemos iterar al reader y escribir / agregar al nuevo csv o podemos realizar cualquier operación

 for chunk in reader: print(newChunk.columns) print("Chunk -> File process") with open(destination, 'a') as f: newChunk.to_csv(f, header=False,sep='\t',index=False) print("Chunk appended to the file")