DataFrame grande y persistente en pandas
Estoy explorando cambiar a Python y Pandas como usuario de SAS desde hace mucho tiempo.
Sin embargo, al ejecutar algunas pruebas hoy, me sorprendió que Python se quedara sin memoria al intentar crear pandas.read_csv()
un archivo csv de 128 MB. Tenía alrededor de 200.000 filas y 200 columnas de datos en su mayoría numéricos.
Con SAS, puedo importar un archivo csv a un conjunto de datos SAS y puede ser tan grande como mi disco duro.
¿ Hay algo análogo en pandas
?
Trabajo habitualmente con archivos grandes y no tengo acceso a una red informática distribuida.
¡Wes, por supuesto, tiene razón! Solo estoy interviniendo para proporcionar un código de ejemplo un poco más completo. Tuve el mismo problema con un archivo de 129 Mb, que se resolvió mediante:
import pandas as pd
# Returns a TextFileReader, which is iterable with chunks of 1000 rows.
csv_iterator = pd.read_csv('large_dataset.csv', iterator=True, chunksize=1000)
# Iterate through the dataframe chunks and print one row/record at a time
for chunk in csv_iterator:
for index, row in chunk.iterrows():
print(row)
# df is DataFrame. If errors, use `list(csv_iterator)` instead
df = pd.concat(tp, ignore_index=True)
En principio, no debería quedarse sin memoria, pero actualmente hay problemas de memoria con read_csv
archivos grandes causados por algunos problemas internos complejos de Python (esto es vago pero se sabe desde hace mucho tiempo: http://github.com/pydata /pandas/issues/407 ).
Por el momento no existe una solución perfecta (aquí hay una tediosa: puede transcribir el archivo fila por fila en una matriz NumPy preasignada o en un archivo mapeado en memoria np.mmap
), pero es una en la que estaré trabajando. en un futuro próximo. Otra solución es leer el archivo en partes más pequeñas (use iterator=True, chunksize=1000
) y luego concatenarlo con pd.concat
. El problema surge cuando guardas todo el archivo de texto en la memoria de un solo gran sorbo.
Este es un hilo antiguo, pero solo quería dejar mi solución alternativa aquí. Inicialmente probé el chunksize
parámetro (incluso con valores bastante pequeños como 10000), pero no ayudó mucho; Todavía tenía problemas técnicos con el tamaño de la memoria (mi CSV era ~ 7,5 Gb).
En este momento, simplemente leo fragmentos de archivos CSV en un enfoque de bucle for y los agrego, por ejemplo, a una base de datos SQLite paso a paso:
import pandas as pd
import sqlite3
from pandas.io import sql
import subprocess
# In and output file paths
in_csv = '../data/my_large.csv'
out_sqlite = '../data/my.sqlite'
table_name = 'my_table' # name for the SQLite database table
chunksize = 100000 # number of lines to process at each iteration
# columns that should be read from the CSV file
columns = ['molecule_id','charge','db','drugsnow','hba','hbd','loc','nrb','smiles']
# Get number of lines in the CSV file
nlines = subprocess.check_output('wc -l %s' % in_csv, shell=True)
nlines = int(nlines.split()[0])
# connect to database
cnx = sqlite3.connect(out_sqlite)
# Iteratively read CSV and dump lines into the SQLite table
for i in range(0, nlines, chunksize):
df = pd.read_csv(in_csv,
header=None, # no header, define column header manually later
nrows=chunksize, # number of rows to read at each iteration
skiprows=i) # skip rows that were already read
# columns to read
df.columns = columns
sql.to_sql(df,
name=table_name,
con=cnx,
index=False, # don't use CSV file index
index_label='molecule_id', # use a unique column from DataFrame as index
if_exists='append')
cnx.close()