two index data concatenate columns column python pandas memory memory-management

python - index - Cómo concatenar múltiples pandas.DataFrames sin ejecutarse en MemoryError



pandas join (9)

Dask podría ser una buena opción para probar el manejo de grandes marcos de datos. Revise Dask Docs.

Tengo tres DataFrames que estoy tratando de concatenar.

concat_df = pd.concat([df1, df2, df3])

Esto resulta en un error de memoria. ¿Cómo puedo resolver esto?

Tenga en cuenta que la mayoría de las preguntas similares existentes están relacionadas con las MemoryErrors que se producen al leer archivos grandes. No tengo ese problema He leído mis archivos en DataFrames. Simplemente no puedo concatenar esos datos.


De manera similar a lo que sugiere @glegoux, también pd.DataFrame.to_csv puede escribir en modo agregado, por lo que puede hacer algo como:

df1.to_csv(filename) df2.to_csv(filename, mode=''a'', columns=False) df3.to_csv(filename, mode=''a'', columns=False) del df1, df2, df3 df_concat = pd.read_csv(filename)


El problema es, como se ve en las otras respuestas, un problema de memoria. Y una solución es almacenar datos en el disco y luego construir un marco de datos único.

Con datos tan grandes, el rendimiento es un problema.

Las soluciones csv son muy lentas, ya que se produce la conversión en modo de texto. Las soluciones HDF5 son más cortas, más elegantes y más rápidas desde el uso del modo binario. Propongo una tercera vía en modo binario, con pickle , que parece ser incluso más rápido, pero más técnico y que necesita más espacio. Y un cuarto, a mano.

Aquí el código:

import numpy as np import pandas as pd # a DataFrame factory: dfs=[] for i in range(10): dfs.append(pd.DataFrame(np.empty((10**5,4)),columns=range(4))) # a csv solution def bycsv(dfs): md,hd=''w'',True for df in dfs: df.to_csv(''df_all.csv'',mode=md,header=hd,index=None) md,hd=''a'',False #del dfs df_all=pd.read_csv(''df_all.csv'',index_col=None) os.remove(''df_all.csv'') return df_all

Mejores soluciones:

def byHDF(dfs): store=pd.HDFStore(''df_all.h5'') for df in dfs: store.append(''df'',df,data_columns=list(''0123'')) #del dfs df=store.select(''df'') store.close() os.remove(''df_all.h5'') return df def bypickle(dfs): c=[] with open(''df_all.pkl'',''ab'') as f: for df in dfs: pickle.dump(df,f) c.append(len(df)) #del dfs with open(''df_all.pkl'',''rb'') as f: df_all=pickle.load(f) offset=len(df_all) df_all=df_all.append(pd.DataFrame(np.empty(sum(c[1:])*4).reshape(-1,4))) for size in c[1:]: df=pickle.load(f) df_all.iloc[offset:offset+size]=df.values offset+=size os.remove(''df_all.pkl'') return df_all

Para los marcos de datos homogéneos, podemos hacerlo aún mejor:

def byhand(dfs): mtot=0 with open(''df_all.bin'',''wb'') as f: for df in dfs: m,n =df.shape mtot += m f.write(df.values.tobytes()) typ=df.values.dtype #del dfs with open(''df_all.bin'',''rb'') as f: buffer=f.read() data=np.frombuffer(buffer,dtype=typ).reshape(mtot,n) df_all=pd.DataFrame(data=data,columns=list(range(n))) os.remove(''df_all.bin'') return df_all

Y algunas pruebas en (pequeños, 32 Mb) datos para comparar el rendimiento. Tienes que multiplicar por aproximadamente 128 para 4 Gb.

In [92]: %time w=bycsv(dfs) Wall time: 8.06 s In [93]: %time x=byHDF(dfs) Wall time: 547 ms In [94]: %time v=bypickle(dfs) Wall time: 219 ms In [95]: %time y=byhand(dfs) Wall time: 109 ms

Un cheque :

In [195]: (x.values==w.values).all() Out[195]: True In [196]: (x.values==v.values).all() Out[196]: True In [197]: (x.values==y.values).all() Out[196]: True

Por supuesto, todo eso debe mejorarse y ajustarse para adaptarse a su problema.

Por ejemplo, df3 se puede dividir en partes del tamaño ''total_memory_size - df_total_size'' para poder ejecutar bypickle .

Puedo editarlo si me da más información sobre su estructura de datos y tamaño si lo desea. Hermosa pregunta!


Estoy agradecido a la comunidad por sus respuestas. Sin embargo, en mi caso, descubrí que el problema se debía en realidad al hecho de que estaba usando Python de 32 bits.

Hay límites de memoria definidos para el sistema operativo Windows 32 y 64 bit. Para un proceso de 32 bits, es solo 2 GB. Entonces, incluso si su RAM tiene más de 2 GB, e incluso si está ejecutando el sistema operativo de 64 bits, pero está ejecutando un proceso de 32 bits, ese proceso se limitará a solo 2 GB de RAM; en mi caso, ese proceso era Python.

¡Actualicé a Python de 64 bits y no he tenido un error de memoria desde entonces!

Otras preguntas relevantes son: Límites de memoria de Python de 32 bits en ventanas de 64 bits . ¿Debo usar Python de 32 bits o Python de 64 bits? ¿Por qué esta matriz numpy es demasiado grande para cargar?


He tenido problemas de rendimiento similares al tratar de concatenar un gran número de DataFrames a un DataFrame ''en crecimiento''.

Mi solución fue anexar todos los sub marcos de datos a una lista, y luego concatenar la lista de marcos de datos una vez que se haya completado el procesamiento de los subfases de datos. Esto llevará el tiempo de ejecución a casi la mitad.


Le aconsejo que coloque sus marcos de datos en un solo archivo csv por concatenación. A continuación, para leer su archivo csv.

Ejecuta eso

# write df1 content in file.csv df1.to_csv(''file.csv'', index=False) # append df2 content to file.csv df2.to_csv(''file.csv'', mode=''a'', columns=False, index=False) # append df3 content to file.csv df3.to_csv(''file.csv'', mode=''a'', columns=False, index=False) # free memory del df1, df2, df3 # read all df1, df2, df3 contents df = pd.read_csv(''file.csv'')

Si esta solución no tiene un rendimiento suficiente, es necesario concatear archivos más grandes de lo habitual. Hacer:

df1.to_csv(''file.csv'', index=False) df2.to_csv(''file1.csv'', index=False) df3.to_csv(''file2.csv'', index=False) del df1, df2, df3

Luego ejecuta el comando bash:

cat file1.csv >> file.csv cat file2.csv >> file.csv cat file3.csv >> file.csv

O concat csv en python:

def concat(file1, file2): with open(file2, ''r'') as filename2: data = file2.read() with open(file1, ''a'') as filename1: file.write(data) concat(''file.csv'', ''file1.csv'') concat(''file.csv'', ''file2.csv'') concat(''file.csv'', ''file3.csv'')

Después de leer:

df = pd.read_csv(''file.csv'')


Otra opción:

1) Escriba df1 en el archivo .csv: df1.to_csv(''Big file.csv'')

2) Abra el archivo .csv, luego agregue df2 :

with open(''Big File.csv'',''a'') as f: df2.to_csv(f, header=False)

3) Repita el paso 2 con df3

with open(''Big File.csv'',''a'') as f: df3.to_csv(f, header=False)


Puede almacenar sus marcos de datos individuales en una Store HDF, y luego llamar a la tienda como si fuera un gran marco de datos.

# name of store fname = ''my_store'' with pd.get_store(fname) as store: # save individual dfs to store for df in [df1, df2, df3, df_foo]: store.append(''df'',df,data_columns=[''FOO'',''BAR'',''ETC'']) # data_columns = identify the column in the dfs you are appending # access the store as a single df df = store.select(''df'', where = [''A>2'']) # change where condition as required (see documentation for examples) # Do other stuff with df # # close the store when you''re done os.remove(fname)


Un poco adivinando aquí, pero tal vez:

df1 = pd.concat([df1,df2]) del df2 df1 = pd.concat([df1,df3]) del df3

Obviamente, podrías hacerlo más como un bucle, pero la clave es que deseas eliminar df2, df3, etc. a medida que avanzas. Mientras lo hace en la pregunta, nunca borra los marcos de datos antiguos, por lo que está utilizando aproximadamente el doble de memoria que necesita.

Más en general, si estás leyendo y concatenando, lo haría algo como esto (si tuvieras 3 CSV: foo0, foo1, foo2):

concat_df = pd.DataFrame() for i in range(3): temp_df = pd.read_csv(''foo''+str(i)+''.csv'') concat_df = pd.concat( [concat_df, temp_df] )

En otras palabras, mientras lee en archivos, solo guarda temporalmente los pequeños marcos de datos en la memoria, hasta que los concatene en la df combinada, concat_df. Como lo haces actualmente, mantienes alrededor de todos los marcos de datos más pequeños, incluso después de concatenarlos.