首页 > 解决方案 > 为什么 itertools.groupby() 比使用 defaultdict 的等效方法慢得多?

问题描述

我想检查groupby()基于defaultdict分组数据的自定义配方和自定义配方之间哪个更快:

from collections import defaultdict
from itertools import groupby

def g1(data):
    groupdict = defaultdict(list)
    for value in data:
        group = value[0]
        value = value[1]
        groupdict[group].append(value)
    return [(key, ''.join(values)) for key, values in groupdict.items()]

def g2(data):
    extractKey = lambda x: x[0]
    aggregate = lambda g: ''.join(x[1] for x in g)
    #return [(k, aggregate(g)) for k, g in groupby(data, extractKey)]
    return [(k, aggregate(g)) for k, g in groupby(sorted(data, key=extractKey), extractKey)]

import random

keys = list(range(1,100))
vals = 'abcdefghijklmnopqrstuvwxyz'

data = [(random.choice(keys), random.choice(vals)) for _ in range(1000)]
#data.sort()

import timeit

for g in ('g1', 'g2'):
    print(g, timeit.timeit(g + '(data)', number=1000, globals=globals()))

令我惊讶的是,groupby()它几乎比defaultdict.

g1 0.17048488299769815

g2 0.47328821099654306

即使数据是预先排序的,即我们不计算sort()ing所花费的时间(取消注释两个注释行),据说groupby()应该比另一个配方执行得更快,它几乎慢了 1.5 倍。

g1 0.17607520399906207

g2 0.2464493800071068

为什么?g2我确实忽略了一些优化吗?

标签: pythonperformance

解决方案


lambda与仅索引到元组相比,它与调用的开销有关。

如果您重写第一个案例以使用extractKey

def g1(data):
    groupdict = defaultdict(list)
    extractKey = lambda x: x[0]
    for value in data:
        group = extractKey(value)
        value = value[1]
        groupdict[group].append(value)
    return [(key, ''.join(values)) for key, values in groupdict.items()]

然后它们的速度几乎相同(在非排序情况下)。


推荐阅读