python csv python-2.7

python - Lectura de un enorme archivo.csv



python-2.7 (7)

Actualmente estoy tratando de leer datos de archivos .csv en Python 2.7 con hasta 1 millón de filas y 200 columnas (los archivos van desde 100 mb a 1.6 gb). Puedo hacer esto (muy lentamente) para los archivos con menos de 300,000 filas, pero una vez que voy más arriba obtengo errores de memoria. Mi código se ve así:

def getdata(filename, criteria): data=[] for criterion in criteria: data.append(getstuff(filename, criteron)) return data def getstuff(filename, criterion): import csv data=[] with open(filename, "rb") as csvfile: datareader=csv.reader(csvfile) for row in datareader: if row[3]=="column header": data.append(row) elif len(data)<2 and row[3]!=criterion: pass elif row[3]==criterion: data.append(row) else: return data

El motivo de la cláusula else en la función getstuff es que todos los elementos que se ajustan al criterio se enumerarán juntos en el archivo csv, de modo que dejo el ciclo cuando los paso para ahorrar tiempo.

Mis preguntas son:

  1. ¿Cómo puedo lograr que esto funcione con los archivos más grandes?

  2. ¿Hay alguna manera de que pueda hacerlo más rápido?

Mi computadora tiene 8 GB de RAM, con Windows 7 de 64 bits, y el procesador es de 3,40 GHz (no estoy seguro de qué información necesita).

¡Muchas gracias por la ayuda!


Aunque la respuesta de Martijin es probablemente la mejor. Esta es una forma más intuitiva de procesar grandes archivos csv para principiantes. Esto le permite procesar grupos de filas o fragmentos a la vez.

import pandas as pd chunksize = 10 ** 8 for chunk in pd.read_csv(filename, chunksize=chunksize): process(chunk)


Está leyendo todas las filas en una lista y luego procesando esa lista. No hagas eso .

Procese sus filas a medida que las produce. Si necesita filtrar los datos primero, use una función de generador:

import csv def getstuff(filename, criterion): with open(filename, "rb") as csvfile: datareader = csv.reader(csvfile) yield next(datareader) # yield the header row count = 0 for row in datareader: if row[3] == criterion: yield row count += 1 elif count: # done when having read a consecutive series of rows return

También simplifiqué tu prueba de filtro; la lógica es la misma pero más concisa.

Como solo está haciendo coincidir una secuencia de filas que coincida con el criterio, también puede usar:

import csv from itertools import dropwhile, takewhile def getstuff(filename, criterion): with open(filename, "rb") as csvfile: datareader = csv.reader(csvfile) yield next(datareader) # yield the header row # first row, plus any subsequent rows that match, then stop # reading altogether # Python 2: use `for row in takewhile(...): yield row` instead # instead of `yield from takewhile(...)`. yield from takewhile( lambda r: r[3] == criterion, dropwhile(lambda r: r[3] != criterion, datareader)) return

Ahora puede pasar getstuff() encima de getstuff() directamente. Haz lo mismo en getdata() :

def getdata(filename, criteria): for criterion in criteria: for row in getstuff(filename, criterion): yield row

Ahora getdata() bucle directamente sobre getdata() en tu código:

for row in getdata(somefilename, sequence_of_criteria): # process row

Ahora solo tiene una fila en la memoria, en lugar de miles de líneas por criterio.

yield hace que una función sea una función de generador , lo que significa que no funcionará hasta que comiences a recorrerla.


Generator es una buena solución. Y en realidad, puede agregar un tiempo True: en el código (antes de abrir un csv), haciéndolo iterable para infinitos bucles.

Por ejemplo, en el conjunto de datos mnist:

import gzip import numpy as np BATCHSIZE = 100 DATASIZE = 1000 LOOP = DATASIZE//BATCHSIZE def mnist_generator_iterable(path, name=''train_data''): if name==''train_data'': while True: with gzip.open(path+''//train-images-idx3-ubyte.gz'') as bytestream: bytestream.read(16) for i in range(LOOP): buf = bytestream.read(28*28*BATCHSIZE*1) trainset = np.frombuffer(buf, dtype=np.uint8).astype(np.float32) yield trainset.reshape([-1,784])


Hace poco estuve tratando de resolver el mismo problema, pero encontré que el paquete python pandas era razonablemente eficiente.

Es posible que desee comprobar aquí, http://pandas.pydata.org/

Pandas es una biblioteca de análisis de datos de alto rendimiento para Big Data.


Hago una buena cantidad de análisis de vibración y veo grandes conjuntos de datos (decenas y cientos de millones de puntos). Mi prueba mostró que la función pandas.read_csv() es 20 veces más rápida que numpy.genfromtxt (). Y la función genfromtxt () es 3 veces más rápida que numpy.loadtxt (). Parece que necesitas pandas para grandes conjuntos de datos.

Publiqué el código y los conjuntos de datos que utilicé en esta prueba en un blog sobre MATLAB vs Python para el análisis de vibraciones .


aquí hay otra solución para Python3:

import csv with open(filename, "r") as csvfile: datareader = csv.reader(csvfile) count = 0 for row in datareader: if row[3] in ("column header", criterion): doSomething(row) count += 1 elif count > 2: break

aquí el datareader es una función de generador.


lo que funcionó para mí fue y es superrápido

import pandas as pd import dask.dataframe as dd import time t=time.clock() df_train = dd.read_csv(''../data/train.csv'', usecols=[col1, col2]) df_train=df_train.compute() print("load train: " , time.clock()-t)