2013-06-11 7 views
8

Jestem autorem Saddle (saddle.github.io), który zapewnia funkcjonalność podobną w duchu do pand (ale w Scala na maszynie JVM). Próbuję zapewnić, że format serializacji HDF pand o strukturze DataFrame jest kompatybilny z formatem Saddle. Obecnie wdrażam serializację ciągów znaków w trybie Saddle. Moje pytanie brzmi: jak pandas DataFrame serializuje ciągi znaków. Jeśli utworzyć plik hdf5 w pand następująco:Szczegóły serializacji na serialu HDF5 w pandach?

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

I h5dump plik wynikowy tmp.h5, widzę, że blok string (block2_values) jest przechowywana jako typ danych H5T_VLEN i przypisują

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

To wskazuje na zestaw znaków ASCII; jednak bajty, które widzę zakodowane, nie wydają się odpowiadać ASCII (tj. "a", "b", "c"). Ciekawi mnie również skąd pochodzi STRSIZE 8. Czy ktoś może rzucić światło na szczegóły implementacji serializacji ciągów, która odbywa się za pośrednictwem pand -> pytables -> hdf5? (Byłbym również zadowolony z wszelkich wskazówek do kodowania w pandach/pytabach, gdzie mogę zacząć głębiej kopać :)

Odpowiedz

6

Wybrałeś przykład, który na powierzchni wydaje się bardzo prosty, ale w rzeczywistości jest dość skomplikowany za kulisami. To kończy się przechowywanie 3 różnych bloków danych (1 dla każdego typu), oraz każdego z tych sklepów i indeksów oraz danych.

Przechowywany obiekt to format, który nazywam formatem Storer, co oznacza, że ​​numpy tablice są zapisywane wszystkie naraz, więc po ich zapisaniu nie można ich zmienić. Zobacz docs tutaj: http://pandas.pydata.org/pandas-docs/dev/io.html#hdf5-pytables

PyTables docs tutaj: http://pytables.github.io/usersguide/libref/declarative_classes.html#the-atom-class-and-its-descendants

Te ciągi niestety są przechowywane jako marynaty Python w tym konkretnym formacie przechowywania, więc nie wiem, czy można odkodować im cross-platform.

Będziesz mieć łatwiejszy odczyt obiektu Table, który jest przechowywany przy użyciu bardziej podstawowych typów, które można łatwo wyeksportować (istnieje sekcja w dokumentach na temat eksportu do R na przykład).

spróbować przeczytaniu tego formatu:

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

użyciu narzędzia PyTables ptdump -avd tmp.h5, to daje następujące. Jeśli czytasz < PyTables 3.0.0 (który właśnie wyszedł), lub w py3 (które będziemy obsługiwać w 0.11.1). Następnie wszystkie łańcuchy są zakodowane w UTF-8 jako bajty. Przed wersją (PyTables 3.0.0) ciągi są zapisywane jako 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']) 

Prawdopodobnie najlepiej skontaktować się ze mną w trybie off-line w celu dalszej dyskusji.

+0

"Te ciągi niestety są przechowywane jako pikle Pythona w tym szczególnym formacie ..." czy pozostanie to w ten sposób, czy też istnieje plan użycia msgpack tutaj. Pytam, ponieważ widziałem gałąź msgpack, nad którą pracujesz. –

+0

msgpack to niezależny format serializacji, który nie ma nic wspólnego z PyTables. Pikle, o której mówię, to in-line sposób, w jaki PyTables zapisuje ciągi o zmiennej długości. – Jeff

+0

Myślałem, że to była specyficzna panda i nie wiedziałem, że to jest zachowanie drażliwe. Gdyby w pytables użyto msgpack byłoby łatwiej innym językom odczytać dane, ale oczywiście ich celem jest python. –