Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 为什么itertools.groupby()比使用defaultdict的等效方法慢得多?_Python_Performance - Fatal编程技术网

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
方法可以避免的每元素开销。