加快数据转换速度

时间:2013-07-31 23:37:03

标签: python optimization transformation

我有一个给定的(通过第三方,因此不可更改)输入数据在以下结构中:数据是4元组的列表,每个4元组代表一个出击。每个出击的第一个元素是从总共20个可能的类别中选择的长度为1到5的类别列表(不重复);第二个要素是参与的人数;第三个是指示出击开始的日期时间对象;最后一个元素是一个datetime-object,表示sortie的结束。

现在我必须将此数据转换为以下格式:对于每个类别,我需要计算(a)此类别的出动次数,(b)花费的总时间,(c)每次出动所花费的平均时间,(d)“工时”总数,即每次出击的持续时间总和乘以同一次出击的参与者人数,以及(e)每次出击的平均“工时”。

我的第一次天真尝试如下:

def transform (data):
    t = defaultdict (lambda: (0, 0, 0) )

    for row in data:
        delta = row [3] - row [2]
        hours = delta.days * 24 + delta.seconds / 3600
        manHours = row [1] * hours
        for cat in row [0]:
            t [cat] = (t [cat] [0] + 1, t [cat] [1] + hours, t [cat] [2] + manHours)

    return {k: (v [0], v [1], v [1] / v [0], v [2], v [2] / v [0] ) for k, v in t.items () }

我正在使用以下内容进行分析:

cats = [_ for _ in range (20) ]
for test in range (1000):
    data = [ (random.sample (cats, random.randint (1, 5) ), random.randint (2, 40), datetime.datetime (2013, 1, 1, 8), datetime.datetime (2013, 1, 1, 9) ) for _ in range (1000) ]
    transform (data)

使用-m cProfile

我已经在stackoverflow上多次阅读了itertools对于高性能迭代,分组,计数等的令人难以置信的优势,直到用户更喜欢使用itertools而非简单的dict-或list-comprehension。

我想利用这个模块,但我不确定如何充分利用它。因此:

a)转换功能可以通过哪种方式进行时间优化(加速)?

b)itertools可以通过哪种方式帮助我完成这项工作?

我事先感谢你的答案。

-

供参考:在我的盒子(AMD Phenom II Quad,4 GB RAM,4 GB交换)上使用Python 3.3.1 (default, Apr 17 2013, 22:30:32) [GCC 4.7.3] on linux分析器吐出:1000 2.027 0.002 2.042 0.002 trans.py:6(transform)。从pyhton3迁移到pypy不是一种选择。

修改 示例数据(使用ISO表示)或使用第二个代码段创建(显然不是现实生活)数据:

[([6, 4, 15], 3, '2013-07-31T17:23:00', '2013-07-31T18:40:00'), ([9, 18, 5], 15, '2013-07-08T17:49:00', '2013-07-08T18:57:00'), ([7, 14, 17, 12, 0], 18, '2013-07-20T08:16:00', '2013-07-20T09:06:00'), ([6, 1], 32, '2013-07-31T07:14:00', '2013-07-31T09:01:00'), ([17, 7], 7, '2013-07-05T06:59:00', '2013-07-05T07:52:00')]

2013年8月2日: 不幸的是,对于使用numpy比不使用numpy慢360%的想法:

 1000    1.828    0.002    1.842    0.002 prof.py:8(transform) #original function
 1000    0.159    0.000    8.457    0.008 prof.py:43(transform3) #numpy function

1 个答案:

答案 0 :(得分:0)

您可以使用numpy

from collections import defaultdict
from datetime import datetime

import numpy as np

def transform(data):
    pair_type = np.dtype([('team_size', int), ('duration', 'timedelta64[s]')])
    rec_array = np.core.records.array
    total = np.sum
    mean = np.mean
    one_hour = np.timedelta64(1, 'h')
    tmp = defaultdict(list)
    for categories, team_size, begin, end in data:
        for category in categories:
            tmp[category].append((team_size, end - begin))
    for category, pairs in tmp.items():
        pairs = rec_array(pairs, dtype=pair_type)
        hours = pairs.duration / one_hour
        man_hours = pairs.team_size * hours
        yield category, (
                len(pairs),
                total(hours),
                mean(hours),
                total(man_hours),
                mean(man_hours))

some_data = ...
result = dict(transform(some_data))

我不知道它是否更快。如果您试用,请报告结果。

另外,我的n fu不太好。所以,如果有人知道如何改进它,请告诉我。