【问题标题】:Python collections.Counter() runtimePython collections.Counter() 运行时
【发布时间】:2016-11-09 18:28:43
【问题描述】:

我只是遇到了一个需要列出列表的问题,例如l = [1, 2, 3, 4],转换成 dic,例如{1:1、2:1、3:1、4:1}。我只想知道我应该使用 collections.Counter() 还是自己写一个循环来做到这一点。内置方法比自己写循环快吗?

【问题讨论】:

  • 使用collections.Counter(),因为它就是这样做的。为什么要编写自己的代码 ;)
  • 你总是可以测试如果有更快的东西,使用timeit模块。在 Python 3 中,Counter 对象具有 C 性能改进,并且确实非常快。
  • @MartijnPieters:我使用timeit 计算,我自己的代码比Counter 快。可能是我做错了什么,但在我看来一切都一样
  • @anonymous:我确实提到在 Python 3 中它更快。您可能在使用 Python 2 吗?请参阅下面的答案以获得基准。
  • 是的,我使用的是 Python 2。可能就是这个原因。

标签: python counter


【解决方案1】:

如果有更快的速度,您总是可以测试,使用timeit 模块。在 Python 3 中,Counter 对象具有 C 性能改进并且确实非常快:

>>> from timeit import timeit
>>> import random, string
>>> from collections import Counter, defaultdict
>>> def count_manually(it):
...     res = defaultdict(int)
...     for el in it:
...         res[el] += 1
...     return res
...
>>> test_data = [random.choice(string.printable) for _ in range(10000)]
>>> timeit('count_manually(test_data)', 'from __main__ import test_data, count_manually', number=2000)
1.4321454349992564

>>> timeit('Counter(test_data)', 'from __main__ import test_data, Counter', number=2000)
0.776072466003825

这里Counter() 快​​了 2 倍。

也就是说,除非您将代码的性能关键部分计算在内,否则请牢记可读性和可维护性,在这方面,Counter() 胜过编写您自己的代码。

除此之外,Counter() 对象提供了字典之上的功能:它们可以被视为 multisets(您可以求和或减去计数器,并产生并集或交集),并且它们可以按计数有效地为您提供前 N 个元素。

【讨论】:

  • 是的,你是对的。在 Python 2 中它更慢,但在 Python 3 中更快
  • 非常感谢!!
【解决方案2】:

这取决于可读性 v/s 效率。让我们先看看这两个实现。我将使用它作为示例运行的列表:

my_list = [1, 2, 3, 4, 4, 5, 4, 3, 2]

使用collections.Counter()

from collections import Counter
d = Counter(my_list)

使用collections.defaultdict() 创建我自己的计数器:

from collections import defaultdict
d = defaultdict(int)
for i in [1, 2, 3, 4, 4, 5, 4, 3, 2]: 
    d[i] += 1

如您所见,collections.Counter() 更具可读性

让我们看看使用timeit的效率:

  • Python 2.7中:

    mquadri$ python -m "timeit" -c "from collections import defaultdict" "d=defaultdict(int)" "for i in [1, 2, 3, 4, 4, 5, 4, 3, 2]: d[i] += 1"
    100000 loops, best of 3: 2.95 usec per loop
    
    mquadri$ python -m "timeit" -c "from collections import Counter" "Counter([1, 2, 3, 4, 4, 5, 4, 3, 2])"
    100000 loops, best of 3: 6.5 usec per loop
    

    collection.Counter() 实现比自己的代码慢 2 倍

  • Python 3中:

    mquadri$ python3 -m "timeit" -c "from collections import defaultdict" "d=defaultdict(int)" "for i in [1, 2, 3, 4, 4, 5, 4, 3, 2]: d[i] += 1"
    100000 loops, best of 3: 3.1 usec per loop
    
    mquadri$ python3 -m "timeit" -c "from collections import Counter" "Counter([1, 2, 3, 4, 4, 5, 4, 3, 2])"
    100000 loops, best of 3: 5.57 usec per loop
    

    collections.Counter() 比自己的代码快一倍

【讨论】:

  • 我仍然认为无论哪种方式都是 O(n) 复杂度。
猜你喜欢
  • 1970-01-01
  • 2016-06-26
  • 1970-01-01
  • 2016-04-08
  • 1970-01-01
  • 1970-01-01
  • 2019-04-02
  • 2016-06-18
  • 2016-02-15
相关资源
最近更新 更多