2

私の問題は、DataFrame (hdf5 ファイルに格納されている) に含まれていない文字列を検索しようとすると、クエリを完了するのに非常に長い時間がかかることです。例えば:

2*10^9 行を含む df があります。HDF5 ファイルに保存されます。「data_column」としてマークされた「code」という名前の文字列列があります(したがって、インデックスが付けられます)。

データセット ( store.select('df', 'code=valid_code') ) に存在するコードを検索すると、70K 行を取得するのに約 10 秒かかります。

ただし、データセットに存在しないコード ( store.select('df', 'code=not_valid_code') ) を検索すると、クエリの結果 (0 行) を取得するのに約 980 秒かかります。

次のようなストアを作成します: store = pd.HDFStore('data.h5', complevel=1, complib='zlib') 最初の追加は次のようになります: store.append('df', chunk, data_columns=['code ']、expectedrows=2318185498)

この動作は正常ですか、それとも何か問題がありますか?

ありがとう!

PS:この質問はおそらくこの他の質問に関連しています

アップデート:

Jeff のアドバイスに従って、彼の実験を再現したところ、Mac で次の結果が得られました。これは、生成されたテーブルです。

!ptdump -av test.h5
/ (RootGroup) ''
  /._v_attrs (AttributeSet), 4 attributes:
   [CLASS := 'GROUP',
    PYTABLES_FORMAT_VERSION := '2.1',
    TITLE := '',
    VERSION := '1.0']
/df (Group) ''
  /df._v_attrs (AttributeSet), 14 attributes:
   [CLASS := 'GROUP',
    TITLE := '',
    VERSION := '1.0',
    data_columns := ['A'],
    encoding := None,
    index_cols := [(0, 'index')],
    info := {1: {'type': 'Index', 'names': [None]}, 'index': {}},
    levels := 1,
    nan_rep := 'nan',
    non_index_axes := [(1, ['A'])],
    pandas_type := 'frame_table',
    pandas_version := '0.10.1',
    table_type := 'appendable_frame',
    values_cols := ['A']]
/df/table (Table(50000000,)) ''
  description := {
  "index": Int64Col(shape=(), dflt=0, pos=0),
  "A": StringCol(itemsize=8, shape=(), dflt='', pos=1)}
  byteorder := 'little'
  chunkshape := (8192,)
  autoindex := True
  colindexes := {
    "A": Index(6, medium, shuffle, zlib(1)).is_csi=False,
    "index": Index(6, medium, shuffle, zlib(1)).is_csi=False}
  /df/table._v_attrs (AttributeSet), 11 attributes:
   [A_dtype := 'string64',
    A_kind := ['A'],
    CLASS := 'TABLE',
    FIELD_0_FILL := 0,
    FIELD_0_NAME := 'index',
    FIELD_1_FILL := '',
    FIELD_1_NAME := 'A',
    NROWS := 50000000,
    TITLE := '',
    VERSION := '2.7',
    index_kind := 'integer']

そして、これらは結果です:

In [8]: %timeit pd.read_hdf('test.h5','df',where='A = "foo00002"')
1 loops, best of 3: 277 ms per loop

In [9]: %timeit pd.read_hdf('test_zlib.h5','df',where='A = "foo00002"')
1 loops, best of 3: 391 ms per loop

In [10]: %timeit pd.read_hdf('test.h5','df',where='A = "bar"')
1 loops, best of 3: 533 ms per loop

In [11]: %timeit pd.read_hdf('test_zlib2.h5','df',where='A = "bar"')
1 loops, best of 3: 504 ms per loop

違いが十分に大きくない可能性があるため、同じ実験を試みましたが、より大きなデータフレームを使用しました。また、Linux を搭載した別のマシンでこの実験を行いました。

これがコードです (元のデータセットに 10 を掛けただけです):

import pandas as pd

df = pd.DataFrame({'A' : [ 'foo%05d' % i for i in range(500000) ]})

df = pd.concat([ df ] * 20)

store = pd.HDFStore('test.h5',mode='w')

for i in range(50):
    print "%s" % i
    store.append('df',df,data_columns=['A'])

これはテーブルです:

!ptdump -av test.h5
/ (RootGroup) ''
  /._v_attrs (AttributeSet), 4 attributes:
   [CLASS := 'GROUP',
    PYTABLES_FORMAT_VERSION := '2.1',
    TITLE := '',
    VERSION := '1.0']
/df (Group) ''
  /df._v_attrs (AttributeSet), 14 attributes:
   [CLASS := 'GROUP',
    TITLE := '',
    VERSION := '1.0',
    data_columns := ['A'],
    encoding := None,
    index_cols := [(0, 'index')],
    info := {1: {'type': 'Index', 'names': [None]}, 'index': {}},
    levels := 1,
    nan_rep := 'nan',
    non_index_axes := [(1, ['A'])],
    pandas_type := 'frame_table',
    pandas_version := '0.10.1',
    table_type := 'appendable_frame',
    values_cols := ['A']]
/df/table (Table(500000000,)) ''
  description := {
  "index": Int64Col(shape=(), dflt=0, pos=0),
  "A": StringCol(itemsize=9, shape=(), dflt='', pos=1)}
  byteorder := 'little'
  chunkshape := (15420,)
  autoindex := True
  colindexes := {
    "A": Index(6, medium, shuffle, zlib(1)).is_csi=False,
    "index": Index(6, medium, shuffle, zlib(1)).is_csi=False}
  /df/table._v_attrs (AttributeSet), 11 attributes:
   [A_dtype := 'string72',
    A_kind := ['A'],
    CLASS := 'TABLE',
    FIELD_0_FILL := 0,
    FIELD_0_NAME := 'index',
    FIELD_1_FILL := '',
    FIELD_1_NAME := 'A',
    NROWS := 500000000,
    TITLE := '',
    VERSION := '2.7',
    index_kind := 'integer']

これらはファイルです:

-rw-rw-r-- 1 user user 8.2G Oct  5 14:00 test.h5
-rw-rw-r-- 1 user user 9.9G Oct  5 14:30 test_zlib.h5

そして、これらは結果です:

In [9]:%timeit pd.read_hdf('test.h5','df',where='A = "foo00002"')
1 loops, best of 3: 1.02 s per loop

In [10]:%timeit pd.read_hdf('test_zlib.h5','df',where='A = "foo00002"')
1 loops, best of 3: 980 ms per loop

In [11]:%timeit pd.read_hdf('test.h5','df',where='A = "bar"')
1 loops, best of 3: 7.02 s per loop

In [12]:%timeit pd.read_hdf('test_zlib.h5','df',where='A = "bar"')
1 loops, best of 3: 7.27 s per loop

これらは私のバージョンの Pandas と Pytables です:

user@host:~/$ pip show tables
---
Name: tables
Version: 3.1.1
Location: /usr/local/lib/python2.7/dist-packages
Requires: 

user@host:~/$ pip show pandas
---
Name: pandas
Version: 0.14.1
Location: /usr/local/lib/python2.7/dist-packages
Requires: python-dateutil, pytz, numpy

Pandas なしで Pytables のみを使用した場合に同様の動作を観察したため、この問題が Pandas に関連していないことは確かです。

更新 2:

Pytables 3.0.0 に切り替えたところ、問題は修正されました。これは、Pytables 3.1.1 で生成されたものと同じファイルを使用しています。

In [4]:%timeit pd.read_hdf('test.h5','df',where='A = "bar"')
1 loops, best of 3: 205 ms per loop

In [4]:%timeit pd.read_hdf('test_zlib.h5','df',where='A = "bar"')
10 loops, best of 3: 101 ms per loop
4

2 に答える 2

4

あなたの問題は、私たちが少し前にここで PyTables の人たちと一緒にバグを報告したものだと思います。基本的に、圧縮ストアを使用し、expectedrows を指定し、かつインデックス付きの列を使用すると、誤ったインデックス作成が発生します。

soln は単に expectedrows を使用するのではなく、指定されたチャンクシェイプ (または AUTO) でファイルを ptrepack することです。とにかく、これは良い習慣です。さらに、事前に圧縮を指定するかどうかはわかりませんが、ptrepack を介してこれを行う方がよいでしょう。こちらのドキュメントを参照してください。彼らはこれに関するSOの問題でもあります(基本的にファイルを作成している場合は、今すぐ見つけることができません。事前にインデックスを作成しないでください。可能であれば、追加が完了したら)。

いずれにせよ、テスト ストアの作成:

In [1]: df = DataFrame({'A' : [ 'foo%05d' % i for i in range(50000) ]})

In [2]: df = pd.concat([ df ] * 20)

50M 行を追加します。

In [4]: store = pd.HDFStore('test.h5',mode='w')

In [6]: for i in range(50):
   ...:     print "%s" % i
   ...:     store.append('df',df,data_columns=['A'])
   ...:     

ここにテーブルがあります

In [9]: !ptdump -av test.h5
/ (RootGroup) ''
  /._v_attrs (AttributeSet), 4 attributes:
   [CLASS := 'GROUP',
    PYTABLES_FORMAT_VERSION := '2.1',
    TITLE := '',
    VERSION := '1.0']
/df (Group) ''
  /df._v_attrs (AttributeSet), 14 attributes:
   [CLASS := 'GROUP',
    TITLE := '',
    VERSION := '1.0',
    data_columns := ['A'],
    encoding := None,
    index_cols := [(0, 'index')],
    info := {1: {'type': 'Index', 'names': [None]}, 'index': {}},
    levels := 1,
    nan_rep := 'nan',
    non_index_axes := [(1, ['A'])],
    pandas_type := 'frame_table',
    pandas_version := '0.10.1',
    table_type := 'appendable_frame',
    values_cols := ['A']]
/df/table (Table(50000000,)) ''
  description := {
  "index": Int64Col(shape=(), dflt=0, pos=0),
  "A": StringCol(itemsize=8, shape=(), dflt='', pos=1)}
  byteorder := 'little'
  chunkshape := (8192,)
  autoindex := True
  colindexes := {
    "A": Index(6, medium, shuffle, zlib(1)).is_csi=False,
    "index": Index(6, medium, shuffle, zlib(1)).is_csi=False}
  /df/table._v_attrs (AttributeSet), 11 attributes:
   [A_dtype := 'string64',
    A_kind := ['A'],
    CLASS := 'TABLE',
    FIELD_0_FILL := 0,
    FIELD_0_NAME := 'index',
    FIELD_1_FILL := '',
    FIELD_1_NAME := 'A',
    NROWS := 50000000,
    TITLE := '',
    VERSION := '2.7',
    index_kind := 'integer']

blosc および zlib バージョンを作成します。

In [12]: !ptrepack --complib blosc --chunkshape auto --propindexes test.h5 test_blosc.h5

In [13]: !ptrepack --complib zlib --chunkshape auto --propindexes test.h5 test_zlib.h5

In [14]: !ls -ltr *.h5
-rw-rw-r-- 1 jreback users 866182540 Oct  4 20:31 test.h5
-rw-rw-r-- 1 jreback users 976674013 Oct  4 20:36 test_blosc.h5
-rw-rw-r-- 1 jreback users 976674013 Oct  4  2014 test_zlib.h5

パフォーマンスはかなり似ています(見つかった行の場合)

In [10]: %timeit pd.read_hdf('test.h5','df',where='A = "foo00002"')
1 loops, best of 3: 337 ms per loop

In [15]: %timeit pd.read_hdf('test_blosc.h5','df',where='A = "foo00002"')
1 loops, best of 3: 345 ms per loop

In [16]: %timeit pd.read_hdf('test_zlib.h5','df',where='A = "foo00002"')
1 loops, best of 3: 347 ms per loop

行が欠落しています (ただし、ここでは圧縮された方がパフォーマンスが向上します)。

In [11]: %timeit pd.read_hdf('test.h5','df',where='A = "bar"')
10 loops, best of 3: 82.4 ms per loop

In [17]: %timeit pd.read_hdf('test_blosc.h5','df',where='A = "bar"')
10 loops, best of 3: 32.2 ms per loop

In [18]: %timeit pd.read_hdf('test_zlib.h5','df',where='A = "bar"')
10 loops, best of 3: 32.3 ms per loop

そう。予期される行指定子なしで試し、ptrepack を使用します。

この列のエントリの密度が比較的低いと予想される場合 (例: 一意のエントリの数が少ない)、別の可能性があります。この場合、列全体を選択し、store.select_column('df','A').unique()それをクイック検索メカニズムとして使用します (つまり、まったく検索しません)。

于 2014-10-05T00:49:00.477 に答える