1

几天前,我发布了一个关于“如何使 pandas HDFStore 'put' 操作更快”的问题,感谢 Jeff 的回答,我找到了一种更有效的方法来从 db 中提取数据并将它们存储到 hdf5 文件中。

但是通过这种方式,我必须根据它们的类型为每一列填充缺失的数据,并在每一个表上做这些工作(在大多数情况下,这项工作是重复的)。否则,当我将数据帧放入 hdf5 文件时,数据帧中的 None 对象会导致性能问题。

有没有更好的方法来完成这项工作?

我刚刚阅读了这个问题“ENH:sql to provide NaN/NaT conversions”

  • NaT 可以与其他类型一起使用吗?(datetime64 除外)
  • 在将数据帧存储到 hdf5 文件时,我可以使用它替换数据帧中的所有 None 对象而不用担心性能问题吗?

更新1

  • PD。版本:0.10.1
  • 我现在正在使用 np.nan 来填充缺失的数据。但是我遇到了两个问题。
    • 同时具有 np.nan 和 datetime.datetime objs 的列不能转换为 'datetime64[ns]' 类型,并且在将它们放入 hdfstore 时会引发异常。
    在 [155] 中:len(df_bugs.lastdiffed[df_bugs.lastdiffed.isnull()])
    输出[155]:150

    在 [156] 中:len(df_bugs.lastdiffed)
    出[156]:1003387

    在 [158] 中:df_bugs.lastdiffed.astype(df_bugs.creation_ts.dtype)

    -------------------------------------------------- -------------------------
    ValueError Traceback(最近一次调用最后一次)
     在 ()
    ----> 1 df_bugs.lastdiffed.astype(df_bugs.creation_ts.dtype)

    /usr/local/lib/python2.6/dist-packages/pandas-0.10.1-py2.6-linux-x86_64.egg/pandas/core/series.pyc in astype(self, dtype)
        第777章
        第778章
    --> 779 铸造 = com._astype_nansafe(self.values, dtype)
        第780章
        781

    /usr/local/lib/python2.6/dist-packages/pandas-0.10.1-py2.6-linux-x86_64.egg/pandas/core/common.pyc in _astype_nansafe(arr, dtype)
       第1047章
       1048 # 解决 NumPy 损坏问题,#1987
    -> 1049 返回 lib.astype_intsafe(arr.ravel(), dtype).reshape(arr.shape)
       1050
       第1051章

    /usr/local/lib/python2.6/dist-packages/pandas-0.10.1-py2.6-linux-x86_64.egg/pandas/lib.so 在 pandas.lib.astype_intsafe (pandas/lib.c:11886 )()

    /usr/local/lib/python2.6/dist-packages/pandas-0.10.1-py2.6-linux-x86_64.egg/pandas/lib.so in util.set_value_at (pandas/lib.c:44436)( )

    ValueError:必须是 datetime.date 或 datetime.datetime 对象


        # df_bugs_sample1 = df_bugs.ix[:10000]
    在 [147] 中:%prun store.put('df_bugs_sample1', df_bugs_sample1, table=True)

    /usr/local/lib/python2.6/dist-packages/pandas-0.10.1-py2.6-linux-x86_64.egg/pandas/io/pytables.pyc in put(self, key, value, table, append , **kwargs)
        456表
        第457章
    --> 458 self._write_to_group(key, value, table=table, append=append, **kwargs)
        459
        460 def删除(自我,键,其中=无,开始=无,停止=无):

    /usr/local/lib/python2.6/dist-packages/pandas-0.10.1-py2.6-linux-x86_64.egg/pandas/io/pytables.pyc in _write_to_group(self, key, value, index, table , 附加, complib, **kwargs)
        786 raise ValueError('非表不支持压缩')
        787
    --> 788 s.write(obj = value, append=append, complib=complib, **kwargs)
        789 如果 s.is_table 和索引:
        790 s.create_index(列=索引)

    /usr/local/lib/python2.6/dist-packages/pandas-0.10.1-py2.6-linux-x86_64.egg/pandas/io/pytables.pyc in write(self, obj, axes, append, complib , complevel, fletcher32, min_itemsize, chunksize, expectedrows, **kwargs)
       第2489章
       第2490章
    -> 2491 min_itemsize=min_itemsize, **kwargs)
       2492
       2493 如果不是 self.is_exists:

    /usr/local/lib/python2.6/dist-packages/pandas-0.10.1-py2.6-linux-x86_64.egg/pandas/io/pytables.pyc in create_axes(self,axes,obj,validate,nan_rep , data_columns, min_itemsize, **kwargs)
       第2252章
       2253 除外(例外),详细信息:
    -> 2254 raise Exception("找不到正确的原子类型 -> [dtype->%s,items->%s] %s" % (b.dtype.name, b.items, str(detail)))
       2255 j += 1
       2256

    例外:找不到正确的原子类型 -> [dtype->object,items->Index([bug_file_loc, bug_severity, bug_status, cf_branch, cf_bug_source, cf_eta, cf_public_severity, cf_public_summary, cf_regression, cf_reported_by, cf_type, guest_op_sys, host_op_sys, 关键字, lastdiffed, priority, rep_platform, resolution, short_desc, status_whiteboard, target_milestone], dtype=object)] 'datetime.datetime' 类型的对象没有 len()

  • 而另一个 df 似乎不能完全放入数据框中,如下例所示,条目数为13742515,但在我将数据框放入 hdfstore 并取出后,条目数变为1041998。这很奇怪~
    在 [123]:df_bugs_activity
    出[123]:
    
    Int64Index:13742515 个条目,0 到 13742514
    数据列:
    添加了 13111366 个非空值
    attach_id 1041998 非空值
    bug_id 13742515 非空值
    bug_when 13742515 非空值
    fieldid 13742515 非空值
    id 13742515 非空值
    删除了 13612258 个非空值
    谁 13742515 个非空值
    数据类型:datetime64[ns](1)、float64(1)、int64(4)、object(2)


    在 [121] 中:%time store.put('df_bugs_activity2', df_bugs_activity, table=True)

    CPU 时间:用户 35.31 秒,系统:4.23 秒,总计:39.54 秒
    挂壁时间:39.65 秒

    在 [122] 中:%time store.get('df_bugs_activity2')

    CPU 时间:用户 7.56 秒,系统:0.26 秒,总计:7.82 秒
    挂壁时间:7.84 秒
    输出[122]:
    
    Int64Index:1041998 个条目,2012 到 13354656
    数据列:
    添加了 1041981 个非空值
    attach_id 1041998 非空值
    bug_id 1041998 非空值
    bug_when 1041998 非空值
    fieldid 1041998 非空值
    id 1041998 非空值
    删除了 1041991 个非空值
    谁 1041998 个非空值
    数据类型:datetime64[ns](1)、float64(1)、int64(4)、object(2)

更新 2

  • 创建数据框的代码:
    def grab_data(table_name, size_of_page=20000):
        '''
        从 db 表中获取数据

        size_of_page:sql的limit子类的第二个参数
        '''
        cur.execute('select count(*) from %s' % table_name)
        records_number = cur.fetchone()[0]
        loop_number = records_number / size_of_page + 1
        print '****\nStart Grab %s\n****\nrecords_number: %s\nloop_number: %s' % (table_name, records_number, loop_number)

        开始位置 = 0
        df = DataFrame() # 警告:这个数据框对象将包含一个表的所有记录,所以要小心内存使用!

        对于我在范围内(0,loop_number):
            sql_export = 'select * from %s limit %s, %s' % (table_name, start_position, size_of_page)
            df = df.append(psql.read_frame(sql_export, conn), verify_integrity=False, ignore_index=True)

            start_position += size_of_page
            打印 'start_position: %s' % start_position

        返回df

    df_bugs = grab_data('错误')
    df_bugs = df_bugs.fillna(np.nan)
    df_bugs = df_bugs.convert_objects()

  • df_bugs 的结构:
Int64Index:1003387 个条目,0 到 1003386
数据列:
别名 0 非空值
assign_to 1003387 个非空值
bug_file_loc 498160 非空值
bug_id 1003387 非空值
bug_severity 1003387 非空值
bug_status 1003387 非空值
category_id 1003387 非空值
cclist_accessible 1003387 非空值
cf_attempted 102160 个非空值
cf_branch 691834 非空值
cf_bug_source 1003387 非空值
cf_build 357920 非空值
cf_change 324933 非空值
cf_doc_impact 1003387 非空值
cf_eta 7223 非空值
cf_failed 102123 非空值
cf_i18n_impact 1003387 非空值
cf_on_hold 1003387 非空值
cf_public_severity 1003387 非空值
cf_public_summary 587944 非空值
cf_regression 1003387 非空值
cf_reported_by 1003387 非空值
cf_reviewer 1003387 非空值
cf_security 1003387 非空值
cf_test_id 13475 个非空值
cf_type 1003387 非空值
cf_viss 1423 个非空值
component_id 1003387 非空值
creation_ts 1003387 非空值
截止日期 0 非空值
delta_ts 1003387 个非空值
估计时间 1003387 个非空值
everconfirmed 1003387 个非空值
found_in_phase_id 1003387 非空值
found_in_product_id 1003387 非空值
found_in_version_id 1003387 非空值
guest_op_sys 1003387 非空值
host_op_sys 1003387 非空值
关键字 1003387 个非空值
lastdiffed 1003237 个非空值
优先级 1003387 非空值
product_id 1003387 非空值
qa_contact 1003387 非空值
剩余时间 1003387 个非空值
rep_platform 1003387 非空值
记者 1003387 非空值
report_accessible 1003387 非空值
分辨率 1003387 非空值
short_desc 1003387 非空值
status_whiteboard 1003387 非空值
target_milestone 1003387 非空值
投票 1003387 个非空值
数据类型:datetime64[ns](2)、float64(10)、int64(19)、object(21)

更新 3

  • 写入 csv 并从 csv 读取:
    在 [184] 中:df_bugs.to_csv('df_bugs.sv')
    在 [185] 中:df_bugs_from_scv = pd.read_csv('df_bugs.sv')
    在 [186] 中:df_bugs_from_scv
    出[186]:
    
    Int64Index:1003387 个条目,0 到 1003386
    数据列:
    未命名:0 1003387 个非空值
    别名 0 非空值
    assign_to 1003387 个非空值
    bug_file_loc 0 个非空值
    bug_id 1003387 非空值
    bug_severity 1003387 非空值
    bug_status 1003387 非空值
    category_id 1003387 非空值
    cclist_accessible 1003387 非空值
    cf_attempted 102160 个非空值
    cf_branch 345133 非空值
    cf_bug_source 1003387 非空值
    cf_build 357920 非空值
    cf_change 324933 非空值
    cf_doc_impact 1003387 非空值
    cf_eta 7223 非空值
    cf_failed 102123 非空值
    cf_i18n_impact 1003387 非空值
    cf_on_hold 1003387 非空值
    cf_public_severity 1003387 非空值
    cf_public_summary 588 个非空值
    cf_regression 1003387 非空值
    cf_reported_by 1003387 非空值
    cf_reviewer 1003387 非空值
    cf_security 1003387 非空值
    cf_test_id 13475 个非空值
    cf_type 1003387 非空值
    cf_viss 1423 个非空值
    component_id 1003387 非空值
    creation_ts 1003387 非空值
    截止日期 0 非空值
    delta_ts 1003387 个非空值
    估计时间 1003387 个非空值
    everconfirmed 1003387 个非空值
    found_in_phase_id 1003387 非空值
    found_in_product_id 1003387 非空值
    found_in_version_id 1003387 非空值
    guest_op_sys 805088 非空值
    host_op_sys 806344 非空值
    关键字 532941 个非空值
    lastdiffed 1003237 个非空值
    优先级 1003387 非空值
    product_id 1003387 非空值
    qa_contact 1003387 非空值
    剩余时间 1003387 个非空值
    rep_platform 424213 非空值
    记者 1003387 非空值
    report_accessible 1003387 非空值
    分辨率 922282 非空值
    short_desc 1003287 非空值
    status_whiteboard 0 个非空值
    target_milestone 423276 个非空值
    投票 1003387 个非空值
    数据类型:float64(12)、int64(20)、object(21)
4

1 回答 1

1

我会回答自己,并感谢杰夫的帮助。

首先,更新 1 中的第二个问题(“一个 df 似乎无法完全放入数据帧”)已得到修复

而且,我遇到的最大问题是处理同时包含 python 的datetime obj 和None obj 的列。幸运的是,自 0.11-dev 以来,pandas 提供了更便捷的方式。我在我的项目中使用了下面的代码,并为某些行添加了注释,希望它可以帮助其他人:)

cur.execute('select * from table_name')
result = cur.fetchall()

# For details: http://www.python.org/dev/peps/pep-0249/#description
db_description = cur.description
columns = [col_desc[0] for col_desc in db_description]

# As the pandas' doc said, `coerce_float`: Attempt to convert values to non-string, non-numeric objects (like decimal.Decimal) to floating point
df = DataFrame(result, columns=columns, coerce_float=True)

# dealing the missing data
for column_name in df.columns:
    # Currently, calling function `fillna(np.nan) on a `datetime64[ns]` column will cause an exception
    if df[column_name].dtype.str != '<M8[ns]':
        df[column_name].fillna(np.nan)

# convert the type of columns which both have np.nan and datetime obj from 'object' to 'datetime64[ns]'(short as'<M8[ns]')
# find the table columns whose type is Date or Datetime
column_name_type_tuple = [column[:2] for column in db_description if column[1] in (10, 12)]
# check whose type is 'object'
columns_need_conv = [column_name for column_name, column_type in column_name_type_tuple if str(df[column_name].dtype) == 'object']

# do the type converting
for column_name in columns_need_conv:
    df[column_name] = Series(df[column_name].values, dtype='M8[ns]')

df = df.convert_objects()

在此之后,df 应该适合存储在 h5 文件中,不再需要“pickle”。

ps:

一些配置文件:
complib:'lzo',complevel:1
table1,7,810,561 条记录,带有 2 个 int cols 和 1 个 datetime col,放置操作成本为49s

table2,1,008,794 条记录,4 个 datetime cols,4 个 float64 cols,19 个 int cols,24 个 object(string) cols,放置操作花费170s

于 2013-03-19T14:40:26.520 回答