Pandas 熊猫中的HDF5字符串序列化详细信息?

Pandas 熊猫中的HDF5字符串序列化详细信息?,pandas,saddle,Pandas,Saddle,我是Saddle(Saddle.github.io)的作者,它提供了与pandas类似的功能(但在JVM上是Scala)。我正在努力确保pandas数据帧的HDF5序列化格式与Saddle的可互操作性。我目前正在马鞍中实现字符串数组序列化。所以我的问题是熊猫数据帧如何序列化字符串。如果我在pandas中创建HDF5文件,如下所示: from pandas import * h = HDFStore('tmp.h5') f = DataFrame({0: [1,2,3], 1: ["a", "b"

我是Saddle(Saddle.github.io)的作者,它提供了与pandas类似的功能(但在JVM上是Scala)。我正在努力确保pandas数据帧的HDF5序列化格式与Saddle的可互操作性。我目前正在马鞍中实现字符串数组序列化。所以我的问题是熊猫数据帧如何序列化字符串。如果我在pandas中创建HDF5文件,如下所示:

from pandas import *
h = HDFStore('tmp.h5')
f = DataFrame({0: [1,2,3], 1: ["a", "b", "c"], 2: [1.5, 2.5, 3.5]})
h.put("f1", f)
h.close()
在得到的tmp.h5文件中,我看到字符串块(block2_值)存储为数据类型H5T_VLEN和属性

 ATTRIBUTE "CLASS" {
    DATATYPE  H5T_STRING {
          STRSIZE 8;
          STRPAD H5T_STR_NULLTERM;
          CSET H5T_CSET_ASCII;
          CTYPE H5T_C_S1;
       }
    DATASPACE  SCALAR
    DATA {
    (0): "VLARRAY"
    }
 }

这暗示了一个ASCII字符集;然而,我看到的编码字节似乎并不对应于ASCII(即“a”、“b”、“c”)。另外,我很好奇STRSIZE 8是从哪里来的。任何人都可以通过pandas->pytables->hdf5了解字符串序列化的实现细节吗?(我也很高兴有任何指向pandas/pytables中代码的指针,在那里我可以自己开始更深入地挖掘:)

您选择了一个表面上看起来非常简单,但实际上在幕后相当复杂的示例。这将最终存储3个不同的数据块(每个数据类型1个),每个数据块存储和索引以及数据

您存储的对象是我所称的
Storer
格式,这意味着numpy数组是一次写入的,因此一旦写入,它们就不可更改。请参见此处的文档:

PyTables文档如下:

不幸的是,这些字符串以这种特殊的存储格式存储为python pickle,所以我不知道您是否可以跨平台解码它们

您可以更轻松地读取
对象,该对象使用更基本的类型存储,并且易于导出(例如,文档中有一个关于导出到R的部分)

尝试阅读以下格式:

In [2]: df = DataFrame({0: [1,2,3], 1: ["a", "b", "c"], 2: [1.5, 2.5, 3.5]})

In [4]: h = pd.HDFStore('tmp.h5')

In [6]: h.put('df',df, table=True)

In [7]: h.close()
使用PyTables
ptdump-avdtmp.h5
实用程序,这将产生以下结果。如果您正在阅读
/ (RootGroup) ''
  /._v_attrs (AttributeSet), 4 attributes:
   [CLASS := 'GROUP',
    PYTABLES_FORMAT_VERSION := '2.0',
    TITLE := '',
    VERSION := '1.0']
/df (Group) ''
  /df._v_attrs (AttributeSet), 12 attributes:
   [CLASS := 'GROUP',
    TITLE := '',
    VERSION := '1.0',
    data_columns := [],
    index_cols := [(0, 'index')],
    levels := 1,
    nan_rep := b'nan',
    non_index_axes := b"(lp1\n(I1\n(lp2\ncnumpy.core.multiarray\nscalar\np3\n(cnumpy\ndtype\np4\n(S'i8'\nI0\nI1\ntRp5\n(I3\nS'<'\nNNNI-1\nI-1\nI0\ntbS'\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00'\ntRp6\nag3\n(g5\nS'\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00'\ntRp7\nag3\n(g5\nS'\\x02\\x00\\x00\\x00\\x00\\x00\\x00\\x00'\ntRp8\natp9\na.",
    pandas_type := b'frame_table',
    pandas_version := b'0.10.1',
    table_type := b'appendable_frame',
    values_cols := ['values_block_0', 'values_block_1', 'values_block_2']]
/df/table (Table(3,)) ''
  description := {
  "index": Int64Col(shape=(), dflt=0, pos=0),
  "values_block_0": Float64Col(shape=(1,), dflt=0.0, pos=1),
  "values_block_1": Int64Col(shape=(1,), dflt=0, pos=2),
  "values_block_2": StringCol(itemsize=1, shape=(1,), dflt=b'', pos=3)}
  byteorder := 'little'
  chunkshape := (2621,)
  autoindex := True
  colindexes := {
    "index": Index(6, medium, shuffle, zlib(1)).is_csi=False}
  /df/table._v_attrs (AttributeSet), 19 attributes:
   [CLASS := 'TABLE',
    FIELD_0_FILL := 0,
    FIELD_0_NAME := 'index',
    FIELD_1_FILL := 0.0,
    FIELD_1_NAME := 'values_block_0',
    FIELD_2_FILL := 0,
    FIELD_2_NAME := 'values_block_1',
    FIELD_3_FILL := b'',
    FIELD_3_NAME := 'values_block_2',
    NROWS := 3,
    TITLE := '',
    VERSION := '2.6',
    index_kind := b'integer',
    values_block_0_dtype := b'float64',
    values_block_0_kind := b"(lp1\ncnumpy.core.multiarray\nscalar\np2\n(cnumpy\ndtype\np3\n(S'i8'\nI0\nI1\ntRp4\n(I3\nS'<'\nNNNI-1\nI-1\nI0\ntbS'\\x02\\x00\\x00\\x00\\x00\\x00\\x00\\x00'\ntRp5\na.",
    values_block_1_dtype := b'int64',
    values_block_1_kind := b"(lp1\ncnumpy.core.multiarray\nscalar\np2\n(cnumpy\ndtype\np3\n(S'i8'\nI0\nI1\ntRp4\n(I3\nS'<'\nNNNI-1\nI-1\nI0\ntbS'\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00'\ntRp5\na.",
    values_block_2_dtype := b'string8',
    values_block_2_kind := b"(lp1\ncnumpy.core.multiarray\nscalar\np2\n(cnumpy\ndtype\np3\n(S'i8'\nI0\nI1\ntRp4\n(I3\nS'<'\nNNNI-1\nI-1\nI0\ntbS'\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00'\ntRp5\na."]
  Data dump:
[0] (0, [1.5], [1], [b'a'])
[1] (1, [2.5], [2], [b'b'])
[2] (2, [3.5], [3], [b'c'])
/(根组)'
/.属性集,4个属性:
[类别:='组',
PYTABLES_格式_版本:=“2.0”,
标题:='',
版本:='1.0']
/df(集团)'
/属性集,12个属性:
[类别:='组',
标题:='',
版本:=“1.0”,
数据列:=[],
索引列:=[(0,'索引')],
级别:=1,
nan_代表:=b'nan',

非索引轴:=b“(lp1\n(I1\n(lp2\ncnumpy.core.multiarray\nscalar\np3\n(cnumpy\ndtype\np4\n(S'i8'\nI0\nI1\ntRp5\n(I3\nS'))这些字符串不幸地以这种特定格式存储为python pickle…”。。。"这种情况会一直持续下去,还是有计划在这里使用msgpack。我这样问是因为我看到了您正在使用的msgpack分支。msgpack是一种独立的序列化格式,与PyTables无关。我所指的pickle是PyTables保存可变长度字符串的一种内嵌方式。我认为它是指定的ic不知道这是pytables的行为。如果pytables使用msgpack,其他语言读取数据会更容易,但显然它们的目标是python。pytables在很大程度上是完全跨平台的,但这种特殊情况不是,因为它使用可变长度字符串;我上面的表示例是跨平台的,因为它使用fixed长度字符串。是的,非常感谢您提供的示例。但是,表格格式的读/写速度比“pandas”格式慢得多。我想像往常一样,没有一个简单的解决方案具有所有的好处。