Al leer un gran archivo HDF5 con “pandas.read_hdf ()”, ¿por qué sigo teniendo MemoryError aunque leo en trozos especificando chunksize?

Descripción del problema:

Utilizo los pandas de Python para leer algunos archivos CSV grandes y almacenarlos en un archivo HDF5, el archivo HDF5 resultante es de aproximadamente 10 GB. El problema pasa al leerlo de nuevo. A pesar de que traté de leerlo de nuevo en trozos, todavía tengo MemoryError.

Aquí es cómo creo el archivo HDF5:

import glob, os import pandas as pd hdf = pd.HDFStore('raw_sample_storage2.h5') os.chdir("C:/RawDataCollection/raw_samples/PLB_Gate") for filename in glob.glob("RD_*.txt"): raw_df = pd.read_csv(filename, sep=' ', header=None, names=['time', 'GW_time', 'node_id', 'X', 'Y', 'Z', 'status', 'seq', 'rssi', 'lqi'], dtype={'GW_time': uint32, 'node_id': uint8, 'X': uint16, 'Y': uint16, 'Z':uint16, 'status': uint8, 'seq': uint8, 'rssi': int8, 'lqi': uint8}, parse_dates=['time'], date_parser=dateparse, chunksize=50000, skip_blank_lines=True) for chunk in raw_df: hdf.append('raw_sample_all', chunk, format='table', data_columns = True, index = True, compression='blosc', complevel=9) 

Aquí está cómo trato de leerlo de nuevo en trozos:

 for df in pd.read_hdf('raw_sample_storage2.h5','raw_sample_all', chunksize=300000): print(df.head(1)) 

Aquí está el mensaje de error que recibí:

 --------------------------------------------------------------------------- MemoryError Traceback (most recent call last)  in () ----> 1 for df in pd.read_hdf('raw_sample_storage2.h5','raw_sample_all', chunksize=300000): 2 print(df.head(1)) C:\Anaconda\lib\site-packages\pandas\io\pytables.pyc in read_hdf(path_or_buf, key, **kwargs) 321 store = HDFStore(path_or_buf, **kwargs) 322 try: --> 323 return f(store, True) 324 except: 325 C:\Anaconda\lib\site-packages\pandas\io\pytables.pyc in (store, auto_close) 303 304 f = lambda store, auto_close: store.select( --> 305 key, auto_close=auto_close, **kwargs) 306 307 if isinstance(path_or_buf, string_types): C:\Anaconda\lib\site-packages\pandas\io\pytables.pyc in select(self, key, where, start, stop, columns, iterator, chunksize, auto_close, **kwargs) 663 auto_close=auto_close) 664 --> 665 return it.get_result() 666 667 def select_as_coordinates( C:\Anaconda\lib\site-packages\pandas\io\pytables.pyc in get_result(self, coordinates) 1346 "can only use an iterator or chunksize on a table") 1347 -> 1348 self.coordinates = self.s.read_coordinates(where=self.where) 1349 1350 return self C:\Anaconda\lib\site-packages\pandas\io\pytables.pyc in read_coordinates(self, where, start, stop, **kwargs) 3545 self.selection = Selection( 3546 self, where=where, start=start, stop=stop, **kwargs) -> 3547 coords = self.selection.select_coords() 3548 if self.selection.filter is not None: 3549 for field, op, filt in self.selection.filter.format(): C:\Anaconda\lib\site-packages\pandas\io\pytables.pyc in select_coords(self) 4507 return self.coordinates 4508 -> 4509 return np.arange(start, stop) 4510 4511 # utilities ### MemoryError: 

Mi entorno python:

 INSTALLED VERSIONS ------------------ commit: None python: 2.7.3.final.0 python-bits: 32 OS: Windows OS-release: 7 machine: x86 processor: x86 Family 6 Model 42 Stepping 7, GenuineIntel byteorder: little LC_ALL: None LANG: None pandas: 0.15.2 nose: 1.3.4 Cython: 0.22 numpy: 1.9.2 scipy: 0.15.1 statsmodels: 0.6.1 IPython: 3.0.0 sphinx: 1.2.3 patsy: 0.3.0 dateutil: 2.4.1 pytz: 2015.2 bottleneck: None tables: 3.1.1 numexpr: 2.3.1 matplotlib: 1.4.3 openpyxl: 1.8.5 xlrd: 0.9.3 xlwt: 0.7.5 xlsxwriter: 0.6.7 lxml: 3.4.2 bs4: 4.3.2 html5lib: None httplib2: None apiclient: None rpy2: None sqlalchemy: 0.9.9 pymysql: None psycopg2: None 

Edición 1:

Pasó aproximadamente media hora para que el MemoryError pasara después de ejecutar read_hdf (), y mientras tanto revisé taskmgr, y hay poca actividad de la CPU y la memoria total utilizada nunca superó los 2.2G. Fue alrededor de 2.1 GB antes de ejecutar el código. Por lo tanto, los pandas read_hdf () cargados en la RAM tienen menos de 100 MB (tengo 4G de RAM y mi sistema de Windows de 32 bits solo puede usar 2.7G, y el rest lo utilicé para el disco RAM)

Aquí está la información del archivo hdf:

 In [2]: hdf = pd.HDFStore('raw_sample_storage2.h5') hdf Out[2]:  File path: C:/RawDataCollection/raw_samples/PLB_Gate/raw_sample_storage2.h5 /raw_sample_all frame_table (typ->appendable,nrows->308581091,ncols->10,indexers->[index],dc->[time,GW_time,node_id,X,Y,Z,status,seq,rssi,lqi]) 

Además, puedo leer una parte del archivo hdf indicando “inicio” y “detener” en lugar de “tamaño de bloque”:

 %%time df = pd.read_hdf('raw_sample_storage2.h5','raw_sample_all', start=0,stop=300000) print df.info() print(df.head(5)) 

La ejecución solo tomó 4 segundos, y la salida es:

  Int64Index: 300000 entries, 0 to 49999 Data columns (total 10 columns): time 300000 non-null datetime64[ns] GW_time 300000 non-null uint32 node_id 300000 non-null uint8 X 300000 non-null uint16 Y 300000 non-null uint16 Z 300000 non-null uint16 status 300000 non-null uint8 seq 300000 non-null uint8 rssi 300000 non-null int8 lqi 300000 non-null uint8 dtypes: datetime64[ns](1), int8(1), uint16(3), uint32(1), uint8(4) memory usage: 8.9 MB None time GW_time node_id XYZ status seq \ 0 2013-10-22 17:20:58 39821761 3 20010 21716 22668 0 33 1 2013-10-22 17:20:58 39821824 4 19654 19647 19241 0 33 2 2013-10-22 17:20:58 39821888 1 16927 21438 22722 0 34 3 2013-10-22 17:20:58 39821952 2 17420 22882 20440 0 34 4 2013-10-22 17:20:58 39822017 3 20010 21716 22668 0 34 rssi lqi 0 -43 49 1 -72 47 2 -46 48 3 -57 46 4 -42 50 Wall time: 4.26 s 

Al darme cuenta de que 300000 filas solo tomaban 8,9 MB de RAM, intenté usar chunksize junto con iniciar y detener:

 for df in pd.read_hdf('raw_sample_storage2.h5','raw_sample_all', start=0,stop=300000,chunksize = 3000): print df.info() print(df.head(5)) 

Sucede el mismo error de memoria.

No entiendo lo que está sucediendo aquí, si el mecanismo interno ignora de alguna manera el tamaño de chunks / start / stop y trata de cargarlo todo en la RAM, ¿por qué no hay un aumento en el uso de la RAM (solo 100 MB) cuando ocurre MemoryError? ¿Y por qué la ejecución tarda media hora en llegar al error al comienzo del proceso sin un uso notable de la CPU?

Así que el iterador está construido principalmente para tratar con una cláusula where . PyTables devuelve una lista de los indicios donde la cláusula es verdadera. Estos son los números de fila. En este caso, no hay una cláusula where, pero aún utilizamos el indexador, que en este caso es simplemente np.arange en la lista de filas.

Las filas de 300MM toman 2.2GB. que es demasiado para Windows de 32 bits (en general, máximo alrededor de 1 GB). En 64 bits esto no sería un problema.

 In [1]: np.arange(0,300000000).nbytes/(1024*1024*1024.0) Out[1]: 2.2351741790771484 

Por lo tanto, esto debería manejarse mediante el corte de la semántica, lo que haría que esto tomara solo una cantidad trivial de memoria. Número abierto aquí .

Así que sugiero esto. Aquí el indexador se calcula directamente y esto proporciona una semántica de iterador.

 In [1]: df = DataFrame(np.random.randn(1000,2),columns=list('AB')) In [2]: df.to_hdf('test.h5','df',mode='w',format='table',data_columns=True) In [3]: store = pd.HDFStore('test.h5') In [4]: nrows = store.get_storer('df').nrows In [6]: chunksize = 100 In [7]: for i in xrange(nrows//chunksize + 1): chunk = store.select('df', start=i*chunksize, stop=(i+1)*chunksize) # work on the chunk In [8]: store.close()