HDFStore.append(string, DataFrame) завершается с ошибкой, когда содержимое строкового столбца длиннее, чем уже существующее

У меня есть Pandas DataFrame, хранящийся через HDFStore, который, по сути, хранит сводные строки о тестовых запусках, которые я делаю.

Несколько полей в каждой строке содержат описательные строки переменной длины.

Когда я выполняю тестовый прогон, я создаю новый DataFrame с одной строкой в ​​нем:

def export_as_df(self):
    return pd.DataFrame(data=[self._to_dict()], index=[datetime.datetime.now()])

А затем вызовите HDFStore.append(string, DataFrame), чтобы добавить новую строку в существующий DataFrame.

Это отлично работает, за исключением того, что содержимое одного из строковых столбцов больше, чем самый длинный уже существующий экземпляр, после чего я получаю следующую ошибку:

File "<ipython-input-302-a33c7955df4a>", line 516, in save_pytables
store.append('tests', test.export_as_df())
File "/Library/Frameworks/EPD64.framework/Versions/7.3/lib/python2.7/site-packages/pandas/io/pytables.py", line 532, in append
self._write_to_group(key, value, table=True, append=True, **kwargs)
File "/Library/Frameworks/EPD64.framework/Versions/7.3/lib/python2.7/site-packages/pandas/io/pytables.py", line 788, in _write_to_group
s.write(obj = value, append=append, complib=complib, **kwargs)
File "/Library/Frameworks/EPD64.framework/Versions/7.3/lib/python2.7/site-packages/pandas/io/pytables.py", line 2491, in write
min_itemsize=min_itemsize, **kwargs)
File "/Library/Frameworks/EPD64.framework/Versions/7.3/lib/python2.7/site-packages/pandas/io/pytables.py", line 2254, in create_axes
raise Exception("cannot find the correct atom type -> [dtype->%s,items->%s] %s" % (b.dtype.name, b.items, str(detail)))
Exception: cannot find the correct atom type -> [dtype->object,items->Index([bp, id, inst, per, sp, st, title], dtype=object)] [values_block_3] column has a min_itemsize of [51] but itemsize [46] is required!

Я не могу найти документацию о том, как указать длину строки при создании DataFrame. Какое решение здесь?

Обновлять:

Код, который не работает:

        store = pd.HDFStore(pytables_store)            
        for test in self.backtests:
            try:
                min_itemsizes = { 'buy_pattern' : 60, 'sell_pattern': 60, 'strategy': 60, 'title': 60 }
                store.append('tests', test.export_as_df(), min_itemsize = min_itemsizes)

Вот ошибка в 0.11rc1:

File "<ipython-input-110-492b7b6603d7>", line 522, in save_pytables
  store.append('tests', test.export_as_df(), min_itemsize = min_itemsizes)
File "/Users/admin/dev/pandas/pandas-0.11.0rc1/pandas/io/pytables.py", line 610, in append
  self._write_to_group(key, value, table=True, append=True, **kwargs)
File "/Users/admin/dev/pandas/pandas-0.11.0rc1/pandas/io/pytables.py", line 871, in _write_to_group
  s.write(obj = value, append=append, complib=complib, **kwargs)
File "/Users/admin/dev/pandas/pandas-0.11.0rc1/pandas/io/pytables.py", line 2707, in write
  min_itemsize=min_itemsize, **kwargs)
File "/Users/admin/dev/pandas/pandas-0.11.0rc1/pandas/io/pytables.py", line 2447, in create_axes
  self.validate_min_itemsize(min_itemsize)
File "/Users/admin/dev/pandas/pandas-0.11.0rc1/pandas/io/pytables.py", line 2184, in validate_min_itemsize
  raise ValueError("min_itemsize has [%s] which is not an axis or data_column" % k)
ValueError: min_itemsize has [buy_pattern] which is not an axis or data_column

Образец данных:

                           all_day              buy_pattern  \
2013-04-14 12:11:44.377695   False  Hammer() and LowerLow()   

                                                           id instrument  \
2013-04-14 12:11:44.377695  tafdcc96ba4eb11e2a86d14109fcecd49     EURUSD   

                            open_margin periodicity sell_pattern strategy  \
2013-04-14 12:11:44.377695       0.0001     1:00:00                 Tsl()   

                           title  top_bottom  wick_body  
2013-04-14 12:11:44.377695   tsl         0.5          2 

типы:

print prob_test.export_as_df().get_dtype_counts() 

    bool       1
    float64    2
    int64      1
    object     7
    dtype: int64

Я удаляю файл h5 каждый раз, так как хочу чистых результатов. Хотите знать, есть ли что-то столь же глупое, как сбой, потому что df не существует в h5 (и, следовательно, не существует никаких столбцов) во время первого добавления?


person ultra909    schedule 13.04.2013    source источник
comment
pandas.pydata.org/pandas-docs/dev/io. html#notes-caveats, я полагаю, следует поместить в отдельный раздел. Вам нужно заранее указать максимальную длину строк, которые вы хотите иметь, например. min_itemsize = 100 или вы можете сделать это отдельно для каждого столбца, см. ссылку на документ, также это может быть полезной ссылкой: pandas.pydata.org/pandas-docs/dev/cookbook.html#hdfstore, в частности все исключение Trouble HDFStore   -  person Jeff    schedule 13.04.2013
comment
вот еще один пример: pandas. pydata.org/pandas-docs/dev/   -  person Jeff    schedule 13.04.2013
comment
Спасибо, что так быстро вернулись! К сожалению, это не работает для меня - я передаю словарь: min_itemsizes = { 'bp' : 60, 'sp': 60, 'st': 60, 'title': 60 } store.append('tests', test.export_as_df(), min_itemsize = min_itemsizes) Все еще получаю ту же ошибку! Я попытался просто установить целое число, но это не удалось (я полагаю), потому что не все поля являются строками. Я на пандах 10.1.   -  person ultra909    schedule 13.04.2013
comment
попробуйте использовать 0.11rc1 (только что вышла). есть изменения в способе обработки min_itemsize и сообщения об ошибках r лучше - возможно, где-то еще произошел сбой - это больше похоже на сообщение для всех. Пожалуйста, опубликуйте df.get_dtype_counts() вместе с образцом данных, если вы можете   -  person Jeff    schedule 13.04.2013
comment
Обновлено с новой ошибкой под 0.11rc1 (выше)   -  person ultra909    schedule 14.04.2013


Ответы (1)


Вот ссылка на новый раздел документов по этому поводу: http://pandas.pydata.org/pandas-docs/stable/io.html#string-columns

Эта проблема заключается в том, что вы указываете столбец в min_itemsize, который не является столбцом данных. Простой обходной путь — добавить data_columns=True к оператору добавления, но я также обновил код, чтобы автоматически создавать столбцы данных, если вы передаете допустимое имя столбца. Я думаю, что это имеет смысл, вы хотите иметь минимальный размер столбца, так что пусть это произойдет.

Также создан новый раздел документации Строковые столбцы, чтобы показать более полный пример с объяснением (документация скоро будет обновлена).

# this is the new behavior (after code updates)
n [340]: dfs = DataFrame(dict(A = 'foo', B = 'bar'),index=range(5))

In [341]: dfs
Out[341]: 
     A    B
0  foo  bar
1  foo  bar
2  foo  bar
3  foo  bar
4  foo  bar

# A and B have a size of 30
In [342]: store.append('dfs', dfs, min_itemsize = 30)

In [343]: store.get_storer('dfs').table
Out[343]: 
/dfs/table (Table(5,)) ''
  description := {
  "index": Int64Col(shape=(), dflt=0, pos=0),
  "values_block_0": StringCol(itemsize=30, shape=(2,), dflt='', pos=1)}
  byteorder := 'little'
  chunkshape := (963,)
  autoIndex := True
  colindexes := {
    "index": Index(6, medium, shuffle, zlib(1)).is_CSI=False}

# A is created as a data_column with a size of 30
# B is size is calculated
In [344]: store.append('dfs2', dfs, min_itemsize = { 'A' : 30 })

In [345]: store.get_storer('dfs2').table
Out[345]: 
/dfs2/table (Table(5,)) ''
  description := {
  "index": Int64Col(shape=(), dflt=0, pos=0),
  "values_block_0": StringCol(itemsize=3, shape=(1,), dflt='', pos=1),
  "A": StringCol(itemsize=30, shape=(), dflt='', pos=2)}
  byteorder := 'little'
  chunkshape := (1598,)
  autoIndex := True
  colindexes := {
    "A": Index(6, medium, shuffle, zlib(1)).is_CSI=False,
    "index": Index(6, medium, shuffle, zlib(1)).is_CSI=False}
person Jeff    schedule 14.04.2013
comment
Да, это исправило это. Большое спасибо :) - person ultra909; 14.04.2013
comment
Я обновил ссылку на новый раздел String Column в документах и ​​добавил этот вопрос в поваренную книгу. - person Jeff; 15.04.2013
comment
как вы устанавливаете min_itemsize для столбца, который является частью индекса? Я получаю: AttributeError: объект «Индекс» не имеет атрибута «расширить» - person pocketfullofcheese; 21.03.2014