Tengo un archivo CSV de 10 gb que contiene información que necesito usar.
Como tengo memoria limitada en mi PC, no puedo leer todo el archivo en la memoria en un solo lote. En cambio, me gustaría leer iterativamente solo algunas filas de este archivo.
Digamos que en la primera iteración quiero leer los primeros 100, en la segunda los que van del 101 al 200 y así sucesivamente.
¿Existe una manera eficiente de realizar esta tarea en Python? ¿Pueden los pandas proporcionar algo útil para esto? ¿O hay métodos mejores (en términos de memoria y velocidad)?
Aquí está la respuesta corta.
chunksize = 10 ** 6 for chunk in pd.read_csv(filename, chunksize=chunksize): process(chunk)
Aquí está la respuesta muy larga.
Para comenzar, deberá importar pandas y sqlalchemy. Los siguientes comandos harán eso.
import pandas as pd from sqlalchemy import create_engine
A continuación, configure una variable que apunte a su archivo csv. Esto no es necesario, pero ayuda en la reutilización.
file = '/path/to/csv/file'
Con estas tres líneas de código, estamos listos para comenzar a analizar nuestros datos. Echemos un vistazo a la 'cabeza' del archivo csv para ver cómo se vería el contenido.
print pd.read_csv(file, nrows=5)
Este comando utiliza el comando "read_csv" de pandas para leer solo 5 filas (nrows=5) y luego imprimir esas filas en la pantalla. Esto le permite comprender la estructura del archivo csv y asegurarse de que los datos tengan el formato adecuado para su trabajo.
Antes de que podamos trabajar con los datos, debemos hacer algo con ellos para poder comenzar a filtrarlos para que funcionen con subconjuntos de datos. Por lo general, esto es para lo que usaría el marco de datos de pandas, pero con archivos de datos grandes, necesitamos almacenar los datos en otro lugar. En este caso, configuraremos una base de datos sqllite local, leeremos el archivo csv en fragmentos y luego escribiremos esos fragmentos en sqllite.
Para hacer esto, primero necesitaremos crear la base de datos sqllite usando el siguiente comando.
csv_database = create_engine('sqlite:///csv_database.db')
A continuación, debemos iterar a través del archivo CSV en fragmentos y almacenar los datos en sqllite.
chunksize = 100000 i = 0 j = 1 for df in pd.read_csv(file, chunksize=chunksize, iterator=True): df = df.rename(columns={c: c.replace(' ', '') for c in df.columns}) df.index += j i+=1 df.to_sql('table', csv_database, if_exists='append') j = df.index[-1] + 1
Con este código, estamos configurando el tamaño de fragmento en 100 000 para mantener el tamaño de los fragmentos manejable, inicializando un par de iteradores (i=0, j=0) y luego ejecutando un bucle for. El bucle for lee una parte de los datos del archivo CSV, elimina el espacio de cualquiera de los nombres de las columnas y luego almacena la parte en la base de datos sqllite (df.to_sql(…)).
Esto puede llevar un tiempo si su archivo CSV es lo suficientemente grande, pero el tiempo de espera vale la pena porque ahora puede usar las herramientas 'sql' de pandas para extraer datos de la base de datos sin preocuparse por las limitaciones de memoria.
Para acceder a los datos ahora, puede ejecutar comandos como los siguientes:
df = pd.read_sql_query('SELECT * FROM table', csv_database)
Por supuesto, usar 'select *…' cargará todos los datos en la memoria, que es el problema del que estamos tratando de escapar, por lo que debe incluir filtros en sus declaraciones de selección para filtrar los datos. Por ejemplo:
df = pd.read_sql_query('SELECT COl1, COL2 FROM table where COL1 = SOMEVALUE', csv_database)
Puede usar pandas.read_csv()
con el parámetro chuncksize
:
http://pandas.pydata.org/pandas-docs/stable/generated/pandas.read_csv.html#pandas.read_csv
for chunck_df in pd.read_csv('yourfile.csv', chunksize=100): # each chunck_df contains a part of the whole CSV
Este código puede ayudarte en esta tarea. Navega a través de un gran archivo .csv y no consume mucha memoria para que pueda realizar esto en una computadora portátil estándar.
import pandas as pd import os
chunksize2 = 2000 path = './' data2 = pd.read_csv('ukb35190.csv', chunksize=chunksize2, encoding = "ISO-8859-1") df2 = data2.get_chunk(chunksize2) headers = list(df2.keys()) del data2 start_chunk = 0 data2 = pd.read_csv('ukb35190.csv', chunksize=chunksize2, encoding = "ISO-8859-1", skiprows=chunksize2*start_chunk)
for i, df2 in enumerate(data2): try: print('reading cvs....') print(df2) print('header: ', list(df2.keys())) print('our header: ', headers) # Access chunks within data # for chunk in data: # You can now export all outcomes in new csv files file_name = 'export_csv_' + str(start_chunk+i) + '.csv' save_path = os.path.abspath( os.path.join( path, file_name ) ) print('saving ...') except Exception: print('reach the end') break