2013-06-11 3 views
8

나는 Saddle (saddle.github.io)의 저자로서 pandas와 비슷한 기능을 제공합니다 (그러나 JVM의 Scala에서). 나는 pandas의 DataFrame의 HDF5 직렬화 형식이 Saddle의 DataFrame과 상호 운용 될 수 있도록 노력하고 있습니다. 현재 Saddle에서 문자열 배열 직렬화를 구현하고 있습니다. 그래서 내 질문은 팬더 DataFrame 문자열을 serialize하는 방법입니다. 내가 팬더의 HDF5 파일을 작성하는 경우 다음과 같이 내가 볼팬더에 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 파일을 h5dump, 그 문자열 블록 (block2_values가) 데이터 형식 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의 코드에 대해서도 만족할 것입니다. :)

답변

6

표면적으로는 매우 단순 해 보이지만 실제적으로는 상당히 복잡한 예제를 골랐습니다. 이렇게하면 3 개의 서로 다른 데이터 블록 (각 dtype에 대해 1 개)을 저장하고 이러한 각 저장소와 색인 및 데이터를 저장합니다.

내가 저장 한 객체는 Storer 형식이며 numpy 배열은 한 번에 모두 쓰여지므로 한 번 쓰면 변경할 수 없습니다. 여기 문서를 참조하십시오 : http://pandas.pydata.org/pandas-docs/dev/io.html#hdf5-pytables

PyTables 워드 프로세서 현재 위치 : http://pytables.github.io/usersguide/libref/declarative_classes.html#the-atom-class-and-its-descendants

이러한 문자열은 불행하게도 저장이 특정 형식의 파이썬 피클로 저장됩니다, 그래서 당신은 그들에게 크로스 플랫폼을 디코딩 할 수 있을지 모르겠어요.

더 많은 기본 유형을 사용하여 저장되고 쉽게 내보낼 수있는 Table 개체를 더 쉽게 읽을 수 있습니다 (예 : 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 -avd tmp.h5 유틸리티를 사용하여,이 다음을 얻을 수 있습니다. < PyTables 3.0.0 (방금 나온) 또는 py3 (우리는 0.11.1에서 지원 예정)을 읽는 중입니다. 그런 다음 문자열은 모두 utf-8로 인코딩되어 바이트로 기록됩니다. (PyTables 3.0.0,) 이전에는 문자열이 ascii로 기록되었습니다.

/ (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']) 

더 자세히 논의하려면 나에게 연락하는 것이 가장 좋습니다.

+0

"이 문자열은 유감스럽게도이 특정 형식의 파이썬 피클로 저장됩니다 ..."이렇게 유지되거나 msgpack을 사용할 계획입니다. 당신이 작업하고있는 msgpack 브랜치를 보았 기 때문에 묻습니다. –

+0

msgpack은 PyTables와는 아무런 관련이없는 독립적 인 직렬화 형식입니다. 내가 말하는 피클은 PyTables가 가변 길이 문자열을 저장하는 인라인 방식입니다. – Jeff

+0

필자는 팬더에 특화된 것으로 생각하고 이것이 pytables 동작이라는 것을 알지 못했습니다. pytables가 msgpack을 사용하면 다른 언어가 데이터를 읽는 것이 더 쉬울 것이지만 분명히 목표는 파이썬입니다. –