如何使 pandas HDFStore 的“放置”操作更快

sim*_*omo 3 python pandas

我正在尝试使用 pandas、hdf5 构建 ETL 工具包。

我的计划是

  1. 从 mysql 中提取表到 DataFrame;
  2. 将此 DataFrame 放入 HDFStore 中;

但是当我执行步骤 2 时,我发现将数据帧放入 *.h5 文件会花费太多时间。

  • 源mysql服务器中表的大小:498MB
    • 52列
    • 924,624 条记录
  • 将数据帧放入后 *.h5 文件的大小:513MB
    • “put”操作花费 849.345677137 秒

我的问题是:
这个时间成本正常吗?
有什么办法可以让它更快吗?


更新1

谢谢杰夫

  • 我的代码非常简单:

    extract_store = HDFStore('extract_store.h5')
    extract_store['df_staff'] = df_staff

  • 当我尝试“ptdump -av file.h5”时,出现错误,但我仍然可以从此 h5 文件加载数据帧对象:

Tables.Exceptions.HDF5ExtError:HDF5 错误回溯

文件“../../../src/H5F.c”,第 1512 行,在 H5Fopen 中
无法打开文件 文件“../../../src/H5F.c”,第 1307 行,在 H5F_open 中
无法读取超级块文件“../../../src/H5Fsuper.c”,第 305 行,在 H5F_super_read 中
无法找到文件签名文件“../../../src/H5Fsuper.c”,第153行,在H5F_locate_signature中
找不到有效的文件签名

HDF5 错误回溯结束

无法打开/创建文件“extract_store.h5”

  • 其他一些信息:
    • 熊猫版本:'0.10.0'
    • 操作系统:ubuntu服务器10.04 x86_64
    • CPU: 8 * Intel(R) Xeon(R) CPU X5670 @ 2.93GHz
    • 内存总计:51634016 kB

我会将 pandas 更新到 0.10.1-dev,然后重试。


更新2

  • 我已将 pandas 更新为“0.10.1.dev-6e2b6ea”
  • 但时间消耗并没有减少,这次花费了884.15秒
  • “ptdump -av file.h5”的输出是:
    /(根组)''  
      /._v_attrs(AttributeSet),4个属性:  
       [类 := '组',  
        PYTABLES_FORMAT_VERSION := '2.0',  
        标题 := '',  
        版本:='1.0']  
    /df_bugs(组)''  
      /df_bugs._v_attrs(属性集),12个属性:  
       [类 := '组',  
        标题 := '',  
        版本 := '1.0',  
        axis0_variety := '常规',  
        axis1_variety := '常规',  
        block0_items_variety := '常规',  
        block1_items_variety := '常规',  
        block2_items_variety := '常规',  
        n块:= 3,  
        恩迪姆:= 2,  
        pandas_type := '框架',  
        pandas_version := '0.10.1']  
    /df_bugs/axis0(数组(52,))''  
      原子 := StringAtom(itemsize=19, shape=(), dflt='')  
      主丁:= 0  
      味道 := 'numpy'  
      字节顺序 := '不相关'  
      块形状 := 无  
      /df_bugs/axis0._v_attrs(属性集),7个属性:  
       [类 := '数组',  
        味道 := 'numpy',  
        标题 := '',  
        版本:='2.3',  
        种类 := '字符串',  
        名称 := 无,  
        转置 := True]  
    /df_bugs/axis1(数组(924624,))''  
      原子 := Int64Atom(形状=(), dflt=0)  
      主丁:= 0  
      味道 := 'numpy'  
      字节顺序 := '小'  
      块形状 := 无  
      /df_bugs/axis1._v_attrs(属性集),7个属性:  
       [类 := '数组',  
        味道 := 'numpy',  
        标题 := '',  
        版本:='2.3',  
        种类 := '整数',  
        名称 := 无,  
        转置 := True]  
    /df_bugs/block0_items (数组(5,)) ''  
      原子 := StringAtom(itemsize=12, shape=(), dflt='')  
      主丁:= 0   
      味道 := 'numpy'  
      字节顺序 := '不相关'  
      块形状 := 无  
      /df_bugs/block0_items._v_attrs(属性集),7个属性:  
       [类 := '数组',  
        味道 := 'numpy',  
        标题 := '',  
        版本:='2.3',  
        种类 := '字符串',  
        名称 := 无,  
        转置 := True]  
    /df_bugs/block0_values (数组(924624, 5)) ''  
      原子 := Float64Atom(形状=(), dflt=0.0)  
      主丁:= 0  
      味道 := 'numpy'  
      字节顺序 := '小'  
      块形状 := 无  
      /df_bugs/block0_values._v_attrs(属性集),5个属性:  
       [类 := '数组',  
        味道 := 'numpy',  
        标题 := '',  
        版本:='2.3',  
        转置 := True]  
    /df_bugs/block1_items (数组(19,)) ''  
      原子 := StringAtom(itemsize=19, shape=(), dflt='')  
      主丁:= 0  
      味道 := 'numpy'  
      字节顺序 := '不相关'  
      块形状 := 无  
      /df_bugs/block1_items._v_attrs(属性集),7个属性:  
       [类 := '数组',  
        味道 := 'numpy',  
        标题 := '',  
        版本:='2.3',  
        种类 := '字符串',  
        名称 := 无,  
        转置 := True]  
    /df_bugs/block1_values (数组(924624, 19)) ''  
      原子 := Int64Atom(形状=(), dflt=0)  
      主丁:= 0  
      味道 := 'numpy'  
      字节顺序 := '小'  
      块形状 := 无  
      /df_bugs/block1_values._v_attrs(属性集),5个属性:  
       [类 := '数组',  
        味道 := 'numpy',  
        标题 := '',   
        版本:='2.3',  
        转置 := True]  
    /df_bugs/block2_items (数组(28,)) ''  
      原子 := StringAtom(itemsize=18, shape=(), dflt='')  
      主丁:= 0  
      味道 := 'numpy'  
      字节顺序 := '不相关'  
      块形状 := 无  
      /df_bugs/block2_items._v_attrs(属性集),7个属性:  
       [类 := '数组',  
        味道 := 'numpy',  
        标题 := '',  
        版本:='2.3',
        种类 := '字符串',  
        名称 := 无,  
        转置 := True]  
    /df_bugs/block2_values (VLArray(1,)) ''  
      原子 = ObjectAtom()  
      字节顺序='不相关'  
      n行 = 1  
      味道='numpy'  
      /df_bugs/block2_values._v_attrs(属性集),5个属性:  
       [类 := 'VLARRAY',  
        PSEUDOATOM := '对象',  
        标题 := '',   
        版本:='1.3',  
        转置 := True]  
  • 我尝试了下面的代码(将数据帧放入 hdfstore 中,参数“table”为 True),但出现错误,似乎不支持 python 的数据时间类型:

异常:找不到正确的原子类型 -> [dtype->object] 类型为“datetime.datetime”的对象没有 len()


更新3

谢谢杰夫。抱歉耽搁了。

  • 表。版本:'2.4.0'。
  • 是的,884秒只是put操作的成本,没有从mysql进行pull操作的成本
  • 一行数据帧(df.ix[0]):
错误 ID 1
分配给 185
bug_file_loc 无
bug_severity 严重
bug_status已关闭
创造_ts 1998-05-06 21:27:00
delta_ts 2012-05-09 14:41:41
short_desc 两个游标。
host_op_sys 未知
guest_op_sys 未知
优先级P3
代表平台 IA32
记者56
产品ID 7
类别_id 983
组件 ID 12925
分辨率固定
目标里程碑 ws1
质量保证_联系方式 412
状态_白板                         
投票 0
关键词SR
最后更新 2012-05-09 14:41:41
已确认 1
记者_可访问 1
cclist_accessible 1
预计时间 0.00
剩余时间 0.00
截止日期 无
别名 无
found_in_product_id 0
found_in_version_id 0
found_in_phase_id 0
cf_type 缺陷
cf_reported_by 开发
cf_尝试 NaN
cf_失败 NaN
cf_public_summary                         
cf_doc_影响 0
cf_安全 0
cf_build NaN
cf_分支                                 
cf_change NaN
cf_test_id 南
cf_regression 未知
cf_审稿人 0
cf_on_hold 0
cf_public_severity ---
cf_i18n_影响 0
cf_eta 无
cf_bug_source ---
cf_viss 无
名称:0,长度:52
  • 数据框的图片(只需在 ipython 笔记本中输入“df”):
Int64Index:924624 个条目,0 到 924623
数据列:
bug_id 924624 非空值
signed_to 924624 个非空值
bug_file_loc 427318 非空值
bug_severity 924624 非空值
bug_status 924624 非空值
creation_ts 924624 个非空值
delta_ts 924624 个非空值
Short_desc 924624 个非空值
host_op_sys 924624 个非空值
guest_op_sys 924624 个非空值
优先级 924624 非空值
rep_platform 924624 非空值
报告者 924624 非空值
Product_id 924624 非空值
category_id 924624 非空值
component_id 924624 非空值
分辨率 924624 非空值
target_milestone 924624 个非空值
qa_contact 924624 非空值
status_whiteboard 924624 个非空值
投票 924624 个非空值
关键字 924624 个非空值
lastdiffed 924509 个非空值
已确认 924624 个非空值
reports_accessible 924624 个非空值
cclist_accessible 924624 个非空值
estimated_time 924624 个非空值
剩余时间 924624 个非空值
截止日期 0 个非空值
别名 0 非空值
found_in_product_id 924624 个非空值
found_in_version_id 924624 个非空值
found_in_phase_id 924624 个非空值
cf_type 924624 非空值
cf_reported_by 924624 个非空值
cf_attempted 89622 个非空值
cf_failed 89587 个非空值
cf_public_summary 510799 个非空值
cf_doc_impact 924624 个非空值
cf_security 924624 非空值
cf_build 327460 非空值
cf_branch 614929 个非空值
cf_change 300612 非空值
cf_test_id 12610 个非空值
cf_regression 924624 个非空值
cf_reviewer 924624 个非空值
cf_on_hold 924624 个非空值
cf_public_severity 924624 非空值
cf_i18n_impact 924624 个非空值
cf_eta 3910 非空值
cf_bug_source 924624 个非空值
cf_viss 725 个非空值
数据类型:float64(5)、int64(19)、object(28)
  • 在“convert_objects()”之后:
数据类型:datetime64[ns](2)、float64(5)、int64(19)、object(26)
  • 并将转换后的数据帧放入 hdfstore 成本:749.50 s :)
    • 看来减少“对象”数据类型的数量是降低时间成本的关键
  • 并将转换后的数据帧放入 hdfstore 中,参数“table”为 true 仍会返回该错误
/usr/local/lib/python2.6/dist-packages/pandas-0.10.1.dev_6e2b6ea-py2.6-linux-x86_64.egg/pandas/io/pytables.pyc 中 create_axes(self,axes,obj,validate 、nan_rep、data_columns、min_itemsize、**kwargs)
   第2203章
   2204 除外(异常),详细信息:
-> 2205 raise Exception("找不到正确的原子类型 -> [dtype->%s] %s" % (b.dtype.name, str(detail)))
   第2206章
   2207
异常:找不到正确的原子类型 -> [dtype->object] 类型为“datetime.datetime”的对象没有 len()
  • 我试图将数据框放在没有日期时间列的情况下

更新4

  • mysql中有4列,其类型为datetime:
    • 创建_ts
    • 增量_ts
    • 最后的差异
    • 最后期限

调用convert_objects()后:

  • 创建_ts:
时间戳: 1998-05-06 21:27:00
  • 增量_ts:
时间戳: 2012-05-09 14:41:41
  • 最后的差异
日期时间. 日期时间(2012, 5, 9, 14, 41, 41)
  • 无论调用“convert_objects”之前还是之后,截止日期始终为“无”
没有任何
  • 将没有列“lastdiff”的数据帧花费691.75 秒
  • 当放置没有列“lastdiff”的数据框并将参数“table”设置为 True 时,我收到一个新错误:
/usr/local/lib/python2.6/dist-packages/pandas-0.10.1.dev_6e2b6ea-py2.6-linux-x86_64.egg/pandas/io/pytables.pyc 中 create_axes(self,axes,obj,validate 、nan_rep、data_columns、min_itemsize、**kwargs)
   第2203章
   2204 除外(异常),详细信息:
-> 2205 raise Exception("找不到正确的原子类型 -> [dtype->%s] %s" % (b.dtype.name, str(detail)))
   第2206章
   2207

异常:找不到正确的原子类型 -> [dtype->object] 类型“Decimal”的对象没有 len()
  • mysql中'estimated_time','remaining_time','cf_viss'列的类型是'decimal'

更新5

  • 我已通过以下代码将这些“十进制”类型列转换为“浮点”类型:
no_diffed_converted_df_bugs.estimated_time = no_diffed_converted_df_bugs.estimated_time.map(float)
  • 现在,时间成本是372.84 秒
  • 但'table'版本放置仍然引发错误:
/usr/local/lib/python2.6/dist-packages/pandas-0.10.1.dev_6e2b6ea-py2.6-linux-x86_64.egg/pandas/io/pytables.pyc 中 create_axes(self,axes,obj,validate 、nan_rep、data_columns、min_itemsize、**kwargs)
   第2203章
   2204 除外(异常),详细信息:
-> 2205 raise Exception("找不到正确的原子类型 -> [dtype->%s] %s" % (b.dtype.name, str(detail)))
   第2206章
   2207

异常:找不到正确的原子类型 -> [dtype->object] 类型“datetime.date”的对象没有 len()

Jef*_*eff 5

我非常确信您的问题与 DataFrame 中实际类型的类型映射以及 PyTables 存储它们的方式有关。

  • 具有固定表示的简单类型(浮点型/整数型/布尔型),这些类型被映射到固定的 c 类型
  • 如果可以正确转换日期时间,则会对其进行处理(例如,它们的数据类型为“datetime64[ns]”,特别是 datetimes.date 不会被处理(NaN 是一个不同的故事,根据使用情况可能会导致整个列类型被错误处理)
  • 字符串被映射(在Storer对象中映射到Object类型,Table将它们映射到String类型)
  • 不处理 Unicode
  • 所有其他类型都作为存储中的对象处理,或者为表抛出异常

这意味着,如果您要对 Storer(固定表示)执行put,那么所有不可映射类型都将变成 Object,请参阅此。PyTables 对这些列进行腌制。请参阅下面的 ObjectAtom 参考

http://pytables.github.com/usersguide/libref/declarative_classes.html#the-atom-class-and-its-descendants

表将引发无效类型(我应该在此处提供更好的错误消息)。我想如果您尝试存储映射到 ObjectAtom 的类型(出于性能原因),我也会提供警告。

要强制某些类型,请尝试其中一些:

import pandas as pd

# convert None to nan (its currently Object)
# converts to float64 (or type of other objs)
x = pd.Series([None])
x = x.where(pd.notnull(x)).convert_objects()

# convert datetime like with embeded nans to datetime64[ns]
df['foo'] = pd.Series(df['foo'].values, dtype = 'M8[ns]')
Run Code Online (Sandbox Code Playgroud)

这是 64 位 Linux 上的示例(文件有 1M 行,磁盘大小约为 1 GB)

In [1]: import numpy as np

In [2]: import pandas as pd

In [3]: pd.__version__
Out[3]: '0.10.1.dev'

In [3]: import tables

In [4]: tables.__version__
Out[4]: '2.3.1'

In [4]: df = pd.DataFrame(np.random.randn(1000 * 1000, 100), index=range(int(
   ...: 1000 * 1000)), columns=['E%03d' % i for i in xrange(100)])

In [5]: for x in range(20):
   ...:     df['String%03d' % x] = 'string%03d' % x

In [6]: df
Out[6]: 
<class 'pandas.core.frame.DataFrame'>
Int64Index: 1000000 entries, 0 to 999999
Columns: 120 entries, E000 to String019
dtypes: float64(100), object(20)

# storer put (cannot query) 
In [9]: def test_put():
   ...:     store = pd.HDFStore('test_put.h5','w')
   ...:     store['df'] = df
   ...:     store.close()

In [10]: %timeit test_put()
1 loops, best of 3: 7.65 s per loop

# table put (can query)
In [7]: def test_put():
      ....:     store = pd.HDFStore('test_put.h5','w')
      ....:     store.put('df',df,table=True)
      ....:     store.close()


In [8]: %timeit test_put()
1 loops, best of 3: 21.4 s per loop
Run Code Online (Sandbox Code Playgroud)