【问题标题】:Python collections.Counter: most_common complexityPython collections.Counter: most_common 复杂度
【发布时间】:2015-03-24 19:03:24
【问题描述】:

Python中collections.Counter对象提供的函数most_common的复杂度是多少?

更具体地说,Counter 在计数时保留某种排序列表,当n 是添加到计数器的(唯一)项目数时,它可以比O(n) 更快地执行most_common 操作?供您参考,我正在处理大量文本数据,试图找到第 n 个最常见的标记。

我在 CPython wiki 上查看了 official documentationTimeComplexity article,但找不到答案。

【问题讨论】:

    标签: python time-complexity counter python-collections


    【解决方案1】:

    collections.py的源代码可以看出,如果我们不指定返回元素的个数,most_common会返回一个排序的计数列表。这是一个O(n log n) 算法。

    如果我们使用most_common 来返回k > 1 元素,那么我们使用heapq.nlargest。这是一个O(k) + O((n - k) log k) + O(k log k) 算法,对于一个小常数k 来说非常好,因为它本质上是线性的。 O(k) 部分来自对初始的k 计数进行堆积,第二部分来自n - k 调用heappushpop 方法,第三部分来自对k 元素的最终堆进行排序。由于k <= n,我们可以得出结论,复杂度是:

    O(n log k)

    如果k = 1,那么很容易证明复杂性是:

    O(n)

    【讨论】:

    • 非常优雅。基准测试证实了这一点: # L = rand_list(10000000) # timeit(lambda: sorted(L)[0:6], number=50) # 44.241248495000036 # timeit(lambda: heapq.nsmallest(6, L), number=50) # 14.27249390999998
    • 有一点不明显,我们只需要一个大小为 k 的堆!
    【解决方案2】:

    The source 准确显示发生了什么:

    def most_common(self, n=None):
        '''List the n most common elements and their counts from the most
        common to the least.  If n is None, then list all element counts.
    
        >>> Counter('abracadabra').most_common(3)
        [('a', 5), ('r', 2), ('b', 2)]
    
        '''
        # Emulate Bag.sortedByCount from Smalltalk
        if n is None:
            return sorted(self.iteritems(), key=_itemgetter(1), reverse=True)
        return _heapq.nlargest(n, self.iteritems(), key=_itemgetter(1))
    

    heapq.nlargest 定义在heapq.py

    【讨论】:

    • @RomainG,不用担心,n log n 如果未指定 n 或使用 heapq.nlargest 即 O(n * log(k))
    猜你喜欢
    • 2015-01-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-15
    • 2016-08-20
    • 2016-03-25
    • 1970-01-01
    相关资源
    最近更新 更多