Python 为什么itertools.groupby()比使用defaultdict的等效方法慢得多?
我想检查Python 为什么itertools.groupby()比使用defaultdict的等效方法慢得多?,python,performance,Python,Performance,我想检查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] groupd
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
慢3倍
g1 0.170488299769815
g2 0.47328821099654306
即使数据是预先排序的,也就是说,我们不计算sort()
ing(取消注释这两行注释)所花费的时间,因为据推测groupby()
比另一个配方的执行速度要快,速度几乎慢1.5倍
g1 0.1760752039906207
g2 0.246449380071068
为什么??在
g2
中是否有一些我忽略的优化?它与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()]
然后它们的速度几乎相同(在非排序的情况下)。在一个版本中,您正在排序。分拣费用很高。首先,即使没有排序,它也会变慢。另外,
dict
s使用二进制搜索树、哈希树或类似的数据结构,所以每次查找都应该是O(logn)(文档中说最坏的情况是O(n),我不明白),我怀疑这是因为两个lambda的函数调用开销。内联代码总是比函数调用快。不过,我没有任何时间来支持这一点。不知道它到底有多大的不同。遗憾的是,groupby
并不以速度著称。顺便说一句,您可以用操作符.itemgetter(0)
替换extractKey
,这应该会更快一些。还需要注意的是,groupby
在动态生成值的内存受限情况下具有优势;您可以以流式方式处理组,而无需存储它们defaultdict
将需要内存来存储它们。当内存不是问题时,defaultdict
通常会赢,即使输入是预排序的,因为它们在运行时算法上都是等价的(O(n)
),而且groupby
有一些dict
方法可以避免的每元素开销。