背景
最近需要把数据从csv文件中读取出来,然后写入hdf5中。
使用DataFrame读取csv,然后调用df的to_hdf方法直接写入hdf5文件。
我使用的是table模式,示例代码如下:
import pandas as pd
import numpy as np
days = ['2021-01-01', '2021-01-02']
country = ['usa', 'china','rusia']
df = pd.DataFrame(index=days, columns=country)
df.index.name = 'days'
...
df.to_hdf('country.hdf5', 'country', format='t')
调用to_hdf时报错如下:
Traceback (most recent call last):
File "generate_hdf5.py", line 59, in <module>
df_close.to_hdf(dst_file_name, 'close', format='t')
File "/usr/local/anaconda3/lib/python3.8/site-packages/pandas/core/generic.py", line 2606, in to_hdf
pytables.to_hdf(
File "/usr/local/anaconda3/lib/python3.8/site-packages/pandas/io/pytables.py", line 280, in to_hdf
f(store)
File "/usr/local/anaconda3/lib/python3.8/site-packages/pandas/io/pytables.py", line 262, in <lambda>
f = lambda store: store.put(
File "/usr/local/anaconda3/lib/python3.8/site-packages/pandas/io/pytables.py", line 1092, in put
self._write_to_group(
File "/usr/local/anaconda3/lib/python3.8/site-packages/pandas/io/pytables.py", line 1742, in _write_to_group
s.write(
File "/usr/local/anaconda3/lib/python3.8/site-packages/pandas/io/pytables.py", line 4218, in write
table = self._create_axes(
File "/usr/local/anaconda3/lib/python3.8/site-packages/pandas/io/pytables.py", line 3887, in _create_axes
data_converted = _maybe_convert_for_string_atom(
File "/usr/local/anaconda3/lib/python3.8/site-packages/pandas/io/pytables.py", line 4887, in _maybe_convert_for_string_atom
for i in range(len(block.shape[0])):
TypeError: object of type 'int' has no len()
定位
查阅了相关资料,对于通常的Python代码来说,这个错误就是对int类型数据使用了len方法。
因为int不是str,它并没有len方法,报这个错误是自然的。
然而我们的代码并没有对int调用len。这时,就要考虑一下to_hdf的底层实现了。它可能对DataFrame中的元素调用了len。
而我的df在创建时,默认会有很多的NaN,如果没有填充值,可能会出问题。
解决办法:显式转换df中默认的NaN为numpy.nan。
只需要一行代码:
df.fillna(np.nan, inplace=True)
再执行后面的to_hdf就没有问题了。
小结
解决这个问题的关键在于理解df中数据的类型及转换为hdf5的原理。
根据错误提示,顺滕摸瓜,也能快速地找到解决问题的方法。
如果在创建df数据时,就充分考虑到数据类型以及后续的转换,或许就不会出现后续的各种问题了。