无法将DataFrame保存到HDF5("对象标头消息太大")

Ame*_*ina 7 python hdf5 pytables pandas

我在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)
Run Code Online (Sandbox Code Playgroud)

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

store = pd.HDFStore(p_full_h5)
store.append('my_df', my_df)
Run Code Online (Sandbox Code Playgroud)

我明白了:

  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''.
Run Code Online (Sandbox Code Playgroud)

为什么?

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

In[12]: max([len(x) for x in list(my_df.columns)])
Out{12]: 47
Run Code Online (Sandbox Code Playgroud)

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

BW0*_*BW0 12

对于列的所有元数据,HDF5的标头限制为64kb.这包括名称,类型等.当您大约2000列时,您将用尽空间来存储所有元数据.这是pytables的一个基本限制.我认为他们不会很快就会在他们身边制定变通方法.您将需要拆分表或选择其他存储格式.


All*_*leo 5

截至 2014 年,hdf 已更新

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

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


小智 5

虽然这个线程超过5年,但问题仍然存在.仍然无法将具有超过2000列的DataFrame作为一个表保存到HDFStore中.format='fixed'如果想要选择稍后从HDFStore读取哪些列,则使用不是选项.

这是一个将DataFrame拆分为较小的函数并将它们存储为单独表的函数.另外,a将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()
Run Code Online (Sandbox Code Playgroud)

使用上述功能存储到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
Run Code Online (Sandbox Code Playgroud)