No se puede guardar DataFrame en HDF5 (“el mensaje del encabezado del objeto es demasiado grande”)

Tengo un DataFrame en Pandas:

In [7]: my_df Out[7]:  Int64Index: 34 entries, 0 to 0 Columns: 2661 entries, airplane to zoo dtypes: float64(2659), object(2) 

Cuando bash guardar esto en el disco:

 store = pd.HDFStore(p_full_h5) store.append('my_df', my_df) 

Yo obtengo:

  File "H5A.c", line 254, in H5Acreate2 unable to create attribute File "H5A.c", line 503, in H5A_create unable to create attribute in object header File "H5Oattribute.c", line 347, in H5O_attr_create unable to create new attribute in header File "H5Omessage.c", line 224, in H5O_msg_append_real unable to create new message File "H5Omessage.c", line 1945, in H5O_msg_alloc unable to allocate space for message File "H5Oalloc.c", line 1142, in H5O_alloc object header message is too large End of HDF5 error back trace Can't set attribute 'non_index_axes' in node: /my_df(Group) u''. 

¿Por qué?

Nota: En caso de que sea importante, los nombres de las columnas de DataFrame son simples cadenas pequeñas:

 In[12]: max([len(x) for x in list(my_df.columns)]) Out{12]: 47 

Esto es todo con Pandas 0.11 y la última versión estable de IPython, Python y HDF5.

HDF5 tiene un límite de encabezado de 64kb para todos los metadatos de las columnas. Esto incluye nombre, tipos, etc. Cuando recorra aproximadamente 2000 columnas, se quedará sin espacio para almacenar todos los metadatos. Esta es una limitación fundamental de pytables. No creo que vayan a hacer soluciones alternativas de su lado en el corto plazo. Tendrá que dividir la tabla o elegir otro formato de almacenamiento.

Aunque este hilo tiene más de 5 años, el problema sigue siendo relevante. Todavía no es posible guardar un DataFrame con más de 2000 columnas como una tabla en un HDFStore. Usar format='fixed' no es una opción si uno quiere elegir qué columnas leer del HDFStore más adelante.

Aquí hay una función que divide el DataFrame en otros más pequeños y los almacena como tablas separadas. Además, se pandas.Series una pandas.Series en el almacén HDF que contiene la información a la que pertenece la columna.

 def wideDf_to_hdf(filename, data, columns=None, maxColSize=2000, **kwargs): """Write a `pandas.DataFrame` with a large number of columns to one HDFStore. Parameters ----------- filename : str name of the HDFStore data : pandas.DataFrame data to save in the HDFStore columns: list a list of columns for storing. If set to `None`, all columns are saved. maxColSize : int (default=2000) this number defines the maximum possible column size of a table in the HDFStore. """ import numpy as np from collections import ChainMap store = pd.HDFStore(filename, **kwargs) if columns is None: columns = data.columns colSize = columns.shape[0] if colSize > maxColSize: numOfSplits = np.ceil(colSize / maxColSize).astype(int) colsSplit = [ columns[i * maxColSize:(i + 1) * maxColSize] for i in range(numOfSplits) ] _colsTabNum = ChainMap(*[ dict(zip(columns, ['data{}'.format(num)] * colSize)) for num, columns in enumerate(colsSplit) ]) colsTabNum = pd.Series(dict(_colsTabNum)).sort_index() for num, cols in enumerate(colsSplit): store.put('data{}'.format(num), data[cols], format='table') store.put('colsTabNum', colsTabNum, format='fixed') else: store.put('data', data[columns], format='table') store.close() 

Los cuadros de datos almacenados en un HDFStore con la función anterior se pueden leer con la siguiente función.

 def read_hdf_wideDf(filename, columns=None, **kwargs): """Read a `pandas.DataFrame` from a HDFStore. Parameter --------- filename : str name of the HDFStore columns : list the columns in this list are loaded. Load all columns, if set to `None`. Returns ------- data : pandas.DataFrame loaded data. """ store = pd.HDFStore(filename) data = [] colsTabNum = store.select('colsTabNum') if colsTabNum is not None: if columns is not None: tabNums = pd.Series( index=colsTabNum[columns].values, data=colsTabNum[columns].data).sort_index() for table in tabNums.unique(): data.append( store.select(table, columns=tabsNum[table], **kwargs)) else: for table in colsTabNum.unique(): data.append(store.select(table, **kwargs)) data = pd.concat(data, axis=1).sort_index(axis=1) else: data = store.select('data', columns=columns) store.close() return data 

A partir de 2014, el hdf está actualizado.

 Si está utilizando HDF5 1.8.0 o versiones anteriores, hay un límite en el número 
 de campos que puede tener en un tipo de datos compuesto. 
 Esto se debe al límite de 64 K en los mensajes del encabezado del objeto, en el que se codifican los tipos de datos.  (Sin embargo, puede crear muchos campos antes de que falle.
 Un usuario pudo crear hasta 1260 campos en un tipo de datos compuesto antes de que fallara.)

En cuanto a los pandas , puede guardar el Dataframe con un número arbitrario de columnas con format='fixed' opción format='fixed' fix format='fixed' , el formato ‘table’ todavía genera el mismo error que en el tema. También probé h5py y obtuve el error de ‘encabezado demasiado grande’ (aunque tenía una versión> 1.8.0).

 ###USE get_weights AND set_weights TO SAVE AND LOAD MODEL, RESPECTIVELY. ############################################################################## #Assuming that this is your model architecture. However, you may use #whatever architecture, you want to (big or small; any). def mymodel(): inputShape= (28, 28, 3); model= Sequential() model.add(Conv2D(20, 5, padding="same", input_shape=inputShape)) model.add(Activation('relu')) model.add(Flatten()) model.add(Dense(500)) model.add(Activation('relu')) model.add(Dense(2, activation= "softmax")) return model model.fit(....) #patwigters to start training your model ################################################################################ ################################################################################ #once your model has been trained, you want to save your model in your PC #use get_weights() command to get your model weights weigh= model.get_weights() #now, use pickle to save your model weights, instead of .h5 #for heavy model architectures, .h5 file is unsupported. pklfile= "D:/modelweights.pkl" try: fpkl= open(pklfile, 'wb') #Python 3 pickle.dump(weigh, fpkl, protocol= pickle.HIGHEST_PROTOCOL) fpkl.close() except: fpkl= open(pklfile, 'w') #Python 2 pickle.dump(weigh, fpkl, protocol= pickle.HIGHEST_PROTOCOL) fpkl.close() ################################################################################ ################################################################################ #in future, you may want to load your model back #use pickle to load model weights pklfile= "D:/modelweights.pkl" try: f= open(pklfile) #Python 2 weigh= pickle.load(f); f.close(); except: f= open(pklfile, 'rb') #Python 3 weigh= pickle.load(f); f.close(); restredmodel= mymodel() #use set_weights to load the modelweights into the model architecture restredmodel.set_weights(weigh) ################################################################################ ################################################################################ #now, you can do your testing and evaluation- predictions y_pred= restredmodel.predict(X)