Python timeit令人惊讶的结果:Counter()vs defaultdict()vs dict()

BlueTrin

我在timeit上获得了非常令人惊讶的结果,有人可以告诉我我做错了什么吗?我正在使用Python 2.7。

这是文件speedtest_init.py的内容:

import random

to_count = [random.randint(0, 100) for r in range(60)]

这些是speedtest.py的内容:

__author__ = 'BlueTrin'

import timeit

def test_init1():
    print(timeit.timeit('import speedtest_init'))

def test_counter1():
    s = """\
    d = defaultdict(int);
    for i in speedtest_init.to_count:
        d[i] += 1
    """
    print(timeit.timeit(s, 'from collections import defaultdict; import speedtest_init;'))

def test_counter2():
    print(timeit.timeit('d = Counter(speedtest_init.to_count);', 'from collections import Counter; import speedtest_init;'))


if __name__ == "__main__":
    test_init1()
    test_counter1()
    test_counter2()

控制台输出为:

C:\Python27\python.exe C:/Dev/codility/chlorum2014/speedtest.py
2.71501962931
65.7090444503
91.2953839048

Process finished with exit code 0

我认为默认情况下timeit()运行代码的1000000倍,因此我需要将时间除以1000000,但是令人惊讶的是Counter的速度比defaultdict()慢。

那是预期的吗?

编辑:

同样,使用dict比defaultdict(int)更快:

def test_counter3():
    s = """\
    d = {};
    for i in speedtest_init.to_count:
        if i not in d:
            d[i] = 1
        else:
            d[i] += 1
    """
    print(timeit.timeit(stmt=s, setup='from collections import defaultdict; import speedtest_init;')

最后一个版本比defaultdict(int)快,这意味着除非您更关心可读性,否则应使用dict()而不是defaultdict()。

马丁·彼得斯(Martijn Pieters)

是的,这是预期的;Counter() 构造的用途Counter.update(),它使用self.get()加载初始值,而不是依靠__missing__

此外,defaultdict __missing__工厂完全由C代码处理,尤其是在使用其他类似的类型int()(本身由C实现)时。Counter源是纯Python,因此该Counter.__missing__方法需要Python框架才能执行。

由于dict.get()仍在C中处理,因此对于,构造器方法是更快的方法Counter(),只要您使用相同的技巧Counter.update()和别名self.get作为本地优先项即可:

>>> import timeit
>>> import random
>>> import sys
>>> sys.version_info
sys.version_info(major=2, minor=7, micro=9, releaselevel='final', serial=0)
>>> to_count = [random.randint(0, 100) for r in range(60)]
>>> timeit.timeit('for i in to_count: c[i] += 1',
...               'from collections import Counter; from __main__ import to_count; c = Counter()',
...               number=10000)
0.2510359287261963
>>> timeit.timeit('for i in to_count: c[i] = c_get(i, 0) + 1',
...               'from collections import Counter; from __main__ import to_count; c = Counter(); c_get = c.get',
...               number=10000)
0.20978617668151855

两者defaultdictCounter为他们的功能,而不是他们的表现内置有用的类; 不依赖__missing__钩子可以更快:

>>> timeit.timeit('for i in to_count: d[i] = d_get(i, 0) + 1',
...               'from __main__ import to_count; d = {}; d_get = d.get',
...               number=10000)
0.11437392234802246

这是使用别名dict.get()方法以实现最大速度的常规词典但随后,您还必须重新实现CounterCounter.most_common()方法的bag行为defaultdict用例去的方式数不胜数。

在Python 3.2中,Counter()通过添加一个处理这种情况的C库来更新速度。参见问题10667在Python 3.4上进行测试,Counter()构造函数现在击败了别名dict.get情况:

>>> timeit.timeit('Counter(to_count)',
...               'from collections import Counter; from __main__ import to_count',
...               number=100000)
0.8332311600097455
>>> timeit.timeit('for i in to_count: d[i] = d_get(i, 0) + 1',
...               'from __main__ import to_count; d = {}; d_get = d.get',
...               number=100000)
0.961191965994658
>>> import sys
>>> sys.version_info
sys.version_info(major=3, minor=4, micro=2, releaselevel='final', serial=0)

(注意:要获得有意义的计时结果,迭代次数从10k增加到100k;因此,如果将上述dict.get()情况与上述情况进行比较,则需要在计时中乘以10倍,即1.144秒)。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

Surprising results with Python timeit: Counter() vs defaultdict() vs dict()

来自分类Dev

Python defaultdict(默认)vs dict.get(键,默认)

来自分类Dev

Python defaultdict(默认)vs dict.get(键,默认)

来自分类Dev

defaultdict vs dict元素初始化

来自分类Dev

python中的OrderedDict vs Dict

来自分类Dev

Python:defaultdict(dict)如何创建嵌套字典?

来自分类Dev

Python-使用dict vs队列进行级别订单遍历

来自分类Dev

Python将元素添加到dict和defaultdict

来自分类Dev

list vs UserList和dict vs UserDict

来自分类Dev

Python将defaultdict复制到具有新密钥顺序的dict

来自分类Dev

Angular:用于switch vs dict查找

来自分类Dev

Python:Collections.Counter与defaultdict(int)

来自分类Dev

Python中的基本布尔表达式产生令人惊讶的结果

来自分类Dev

在Python中对集合,列表和元组进行速度测试可得出令人惊讶的结果

来自分类Dev

Python defaultdict

来自分类Dev

向defaultdict(dict)添加密钥

来自分类Dev

Jinja2 if vs中的语句等于dict

来自分类Dev

Logistic回归-class_weight平衡vs dict参数

来自分类Dev

遍历python中的dict无法产生预期的结果

来自分类Dev

Python dict是对象吗?

来自分类Dev

Basic Dict manipulation in python

来自分类Dev

python argparse dict arg

来自分类Dev

Python中的Union dict

来自分类Dev

Python Dict截断键

来自分类Dev

Python:dict乘法

来自分类Dev

Python Dict,动态插入

来自分类Dev

循环构建dict。Python

来自分类Dev

Dict and List Manipulation Python

来自分类Dev

Python dict的邻接列表