【问题标题】:Unable to save DataFrame to HDF5 ("object header message is too large")无法将 DataFrame 保存到 HDF5(“对象标头消息太大”)
【发布时间】:2013-05-14 10:04:33
【问题描述】:

我在 Pandas 中有一个 DataFrame:

In [7]: my_df
Out[7]: 
<class 'pandas.core.frame.DataFrame'>
Int64Index: 34 entries, 0 to 0
Columns: 2661 entries, airplane to zoo
dtypes: float64(2659), object(2)

当我尝试将其保存到磁盘时:

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

我明白了:

  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''.

为什么?

注意:如果重要,DataFrame 列名是简单的小字符串:

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

这一切都与 Pandas 0.11 和 IPython、Python 和 HDF5 的最新稳定版本有关。

【问题讨论】:

  • 问题是你的索引。他们都是0吗?这真的很奇怪。你能展示一下你的框架样本吗?
  • 一般来说,您希望行数多于列数; hdf5 是基于行的。尝试存储帧的转置

标签: python pandas hdf5 pytables


【解决方案1】:
###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(....)    #paramaters 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();

restoredmodel= mymodel()
#use set_weights to load the modelweights into the model architecture
restoredmodel.set_weights(weigh)




################################################################################
################################################################################
#now, you can do your testing and evaluation- predictions
y_pred= restoredmodel.predict(X)

【讨论】:

  • 这个答案会更好,如果你添加了它如何解决问题的简短描述!
  • 这个答案是题外话。欢迎提供关于如何将 pandas 数据帧保存/加载为 pickle 格式的简短、可运行的 sn-p,以及关于 pickle 和 HDF5 之间权衡的讨论。
【解决方案2】:

虽然这个话题已经超过 5 年了,但问题仍然存在。仍然无法将超过 2000 列的 DataFrame 作为一个表保存到 HDFStore 中。如果您想选择稍后从 HDFStore 中读取哪些列,则不能使用 format='fixed'

这是一个函数,它将 DataFrame 拆分为更小的部分并将它们存储为单独的表。此外,pandas.Series 被放入 HDFStore,其中包含列所属表的信息。

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()

使用上述函数存储到 HDFStore 中的 DataFrame 可以使用以下函数读取。

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

【讨论】:

    【解决方案3】:

    截至 2014 年,hdf 为 updated

    如果您使用的是 HDF5 1.8.0 或以前的版本,则数量有限制 您可以在复合数据类型中拥有的字段。 这是由于对象标头消息的 64K 限制,其中数据类型被编码。 (但是,您可以在它失败之前创建很多字段。 在失败之前,一位用户能够在复合数据类型中创建多达 1260 个字段。)

    对于pandas,它可以使用format='fixed' 选项保存具有任意列数的Dataframe,格式'table' 仍然会引发与主题相同的错误。 我也试过h5py,也得到了“标题太大”的错误(虽然我的版本> 1.8.0)。

    【讨论】:

      【解决方案4】:

      对于列的所有元数据,HDF5 的标头限制为 64kb。这包括名称、类型等。当您处理大约 2000 列时,您将用完存储所有元数据的空间。这是 pytables 的基本限制。我不认为他们会在短期内做出变通办法。您要么必须拆分表,要么选择另一种存储格式。

      【讨论】:

      • 感谢@BrianWang0。考虑到我的问题,您对 HDF5 的替代品有什么建议吗?
      • 您关心查询、可附加性或可压缩性吗?尝试致电my_df.to_hdf(output_name,'my_df',format='f')。我不是 PyTables 方面的专家,但是当我有大量列时,它对我有用。不知何故,fixed 格式没有像 table 格式那样的限制。这对我来说是最简单的解决方法。
      • 或者您可以拆分表格,例如从一个数据帧中创建多个数据帧。每个数据框都有所有列的子集。将每个数据帧保存到 HDF5store 中。如果您只想最简单的解决方案,或者只是将其写入纯文本 csv。再说一次,我不是专家。其他人可能会给出比我更好的建议。
      猜你喜欢
      • 1970-01-01
      • 2020-03-01
      • 2015-03-08
      • 1970-01-01
      • 2012-05-11
      • 2018-06-24
      • 1970-01-01
      • 2017-01-06
      • 2011-08-18
      相关资源
      最近更新 更多