python - read - genfromtxt
Python sin memoria en un archivo CSV grande(numpy) (3)
Tengo un archivo CSV de 3GB que trato de leer con Python, necesito la columna de la mediana.
from numpy import *
def data():
return genfromtxt(''All.csv'',delimiter='','')
data = data() # This is where it fails already.
med = zeros(len(data[0]))
data = data.T
for i in xrange(len(data)):
m = median(data[i])
med[i] = 1.0/float(m)
print med
El error que obtengo es esto:
Python(1545) malloc: *** mmap(size=16777216) failed (error code=12)
*** error: can''t allocate region
*** set a breakpoint in malloc_error_break to debug
Traceback (most recent call last):
File "Normalize.py", line 40, in <module>
data = data()
File "Normalize.py", line 39, in data
return genfromtxt(''All.csv'',delimiter='','')
File "/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-
packages/numpy/lib/npyio.py", line 1495, in genfromtxt
for (i, line) in enumerate(itertools.chain([first_line, ], fhd)):
MemoryError
Creo que es solo un error de memoria. Estoy ejecutando un MacOSX de 64 bits con 4 GB de RAM y ambos numpy y Python compilados en modo de 64 bits.
¿Cómo puedo solucionar esto? ¿Debo intentar un enfoque distribuido, solo para la gestión de la memoria?
Gracias
EDITAR: También intenté con esto, pero no tuve suerte ...
genfromtxt(''All.csv'',delimiter='','', dtype=float16)
¿Por qué no estás usando el módulo python csv ?
>> import csv
>> reader = csv.reader(open(''All.csv''))
>>> for row in reader:
... print row
Como otras personas han mencionado, para un archivo realmente grande, es mejor repetirlo.
Sin embargo, comúnmente quiere que todo esté en la memoria por varias razones.
genfromtxt
es mucho menos eficiente que loadtxt
(aunque maneja datos faltantes, mientras que loadtxt
es más "pobre y malo", por lo que las dos funciones coexisten).
Si sus datos son muy regulares (por ejemplo, solo filas delimitadas simples de todo el mismo tipo), también puede mejorar utilizando numpy.fromiter
.
Si tiene suficiente memoria RAM, considere usar np.loadtxt(''yourfile.txt'', delimiter='','')
(También puede necesitar especificar skiprows
si tiene un encabezado en el archivo).
Como una comparación rápida, cargar ~ 500MB de archivo de texto con loadtxt
usa ~ 900MB de ram en el uso máximo, mientras que cargar el mismo archivo con genfromtxt
usa ~ 2.5GB.
Loadtxt
Genfromtxt
Alternativamente, considere algo como lo siguiente. Solo funcionará para datos muy simples y regulares, pero es bastante rápido. ( loadtxt
y genfromtxt
hacen muchas conjeturas y verifican errores. Si sus datos son muy simples y regulares, puede mejorarlos mucho).
import numpy as np
def generate_text_file(length=1e6, ncols=20):
data = np.random.random((length, ncols))
np.savetxt(''large_text_file.csv'', data, delimiter='','')
def iter_loadtxt(filename, delimiter='','', skiprows=0, dtype=float):
def iter_func():
with open(filename, ''r'') as infile:
for _ in range(skiprows):
next(infile)
for line in infile:
line = line.rstrip().split(delimiter)
for item in line:
yield dtype(item)
iter_loadtxt.rowlength = len(line)
data = np.fromiter(iter_func(), dtype=dtype)
data = data.reshape((-1, iter_loadtxt.rowlength))
return data
#generate_text_file()
data = iter_loadtxt(''large_text_file.csv'')
Fromiter
El problema con el uso de genfromtxt () es que intenta cargar todo el archivo en la memoria, es decir, en una matriz numpy. Esto es ideal para archivos pequeños pero MALO para entradas de 3GB como la tuya. Como solo calcula las medianas de la columna, no es necesario leer todo el archivo. Una forma simple, pero no la manera más eficiente de hacerlo, sería leer todo el archivo línea por línea varias veces e iterar sobre las columnas.