当字符串列内容长于已经存在的内容时,HDFStore.append(string, DataFrame) 失败
Posted
技术标签:
【中文标题】当字符串列内容长于已经存在的内容时,HDFStore.append(string, DataFrame) 失败【英文标题】:HDFStore.append(string, DataFrame) fails when string column contents are longer than those already there 【发布时间】:2013-04-06 00:20:50 【问题描述】:我有一个通过 HDFStore 存储的 Pandas DataFrame,它本质上存储关于我正在执行的测试运行的摘要行。
每行中的几个字段包含可变长度的描述性字符串。
当我进行测试运行时,我创建了一个新的 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 中不存在(因此也不存在任何列)而导致失败的愚蠢行为?
【问题讨论】:
pandas.pydata.org/pandas-docs/dev/io.html#notes-caveats,我想应该放在一个单独的部分。您需要先验地指定您想要拥有的字符串的最大长度,例如min_itemsize = 100
或者您可以为每一列单独执行,请参阅 doc ref,这也可能是一个有用的参考:pandas.pydata.org/pandas-docs/dev/cookbook.html#hdfstore,特别是 Trouble HDFStore 异常
这是另一个例子:pandas.pydata.org/pandas-docs/dev/…
感谢您这么快回来!不幸的是,这似乎对我不起作用 - 我在字典中传递:min_itemsizes = 'bp' : 60, 'sp': 60, 'st': 60, 'title': 60
store.append('tests', test.export_as_df(), min_itemsize = min_itemsizes)
仍然得到同样的错误!我尝试只设置一个整数,但这失败了(我想),因为并非所有字段都是字符串。我在 Pandas 10.1 上。
尝试使用 0.11rc1(刚刚出来)。处理 min_itemsize 的方式发生了 r 变化,并且错误消息 r 更好——它可能在其他地方失败——这更像是一个包罗万象的消息。如果可以,请发布 df.get_dtype_counts() 以及数据样本
更新了0.11rc1下的新错误(上图)
【参考方案1】:
这是新文档部分的链接:http://pandas.pydata.org/pandas-docs/stable/io.html#string-columns
这个问题是您在 min_itemsize 中指定的列不是 data_column。简单的解决方法是将data_columns=True
添加到您的附加语句中,但我还更新了代码以在您传递有效列名时自动创建 data_columns。我认为这是有道理的,您希望有一个最小的列大小,所以让它发生。
还创建了一个新的文档部分字符串列以显示更完整的示例和解释(文档将很快更新)。
# 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
【讨论】:
是的,已经解决了。非常感谢:) 我更新了文档中新字符串列部分的链接,并将这个问题添加到了食谱中 如何为索引中的列设置 min_itemsize?我得到:AttributeError:“'Index'对象没有属性'extend'”以上是关于当字符串列内容长于已经存在的内容时,HDFStore.append(string, DataFrame) 失败的主要内容,如果未能解决你的问题,请参考以下文章
当字符串长于列长度定义时,如何在存储字符串时静默截断字符串?
当输入框字符串长于框大小时,Vue Sortable + Draggable 不起作用