在Python列表中计算出现次数的最快方法

47

我有一个Python列表,想要知道最快的方法来计算在这个列表中项'1'出现的次数。在我的实际情况中,这个项可能会出现成千上万次,因此我需要一种快速的方法。

['1', '1', '1', '1', '1', '1', '2', '2', '2', '2', '7', '7', '7', '10', '10']

哪种方法更优化: .count 还是 collections.Counter


4
列表是否总是有序的?你是否总是计算第一个项目? - jscs
@JoshCaswell 不,列表没有排序,我会计算任何项。我不确定哪种方法更优化:count 还是 collections.Counter,这就是为什么我问的原因。 - prrao
1
@prrao 这取决于您是否想要多次执行此操作。 - jamylak
@prrao 最好还是使用.count - Jakob Bowyer
@Jakob 谢谢。count 对于大型列表运行良好。 - prrao
显示剩余2条评论
5个回答

81
a = ['1', '1', '1', '1', '1', '1', '2', '2', '2', '2', '7', '7', '7', '10', '10']
print a.count("1")

这可能在C语言层面得到了很好的优化。

编辑:我随机生成了一个大型列表。

In [8]: len(a)
Out[8]: 6339347

In [9]: %timeit a.count("1")
10 loops, best of 3: 86.4 ms per loop

编辑编辑:这可以使用collections.Counter完成。

a = Counter(your_list)
print a['1']

使用我上一个计时示例中的相同列表

In [17]: %timeit Counter(a)['1']
1 loops, best of 3: 1.52 s per loop

我的计时方法很简单,并且取决于许多不同的因素,但它可以为您提供有关性能的良好线索。

以下是一些分析结果

In [24]: profile.run("a.count('1')")
         3 function calls in 0.091 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    0.091    0.091 <string>:1(<module>)
        1    0.091    0.091    0.091    0.091 {method 'count' of 'list' objects}

        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Prof
iler' objects}



In [25]: profile.run("b = Counter(a); b['1']")
         6339356 function calls in 2.143 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    2.143    2.143 <string>:1(<module>)
        2    0.000    0.000    0.000    0.000 _weakrefset.py:68(__contains__)
        1    0.000    0.000    0.000    0.000 abc.py:128(__instancecheck__)
        1    0.000    0.000    2.143    2.143 collections.py:407(__init__)
        1    1.788    1.788    2.143    2.143 collections.py:470(update)
        1    0.000    0.000    0.000    0.000 {getattr}
        1    0.000    0.000    0.000    0.000 {isinstance}
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Prof
iler' objects}
  6339347    0.356    0.000    0.356    0.000 {method 'get' of 'dict' objects}

你认为哪种方法更优化?我猜最好的选择取决于具体情况? - prrao
18
在这种情况下,使用 count 比创建一个 Counter 快大约 20 倍,但是相同的 Counter 可以用于以极低的额外成本检索多个不同值的计数。 如果您需要从同一列表中计算 20 个或更多值,则使用 Counter 将比运行 20 次 .count() 更有效。 - John La Rooy
7
我正在处理一个包含1,000,000个整数的数据集,其中每个整数的范围在100以内,即每个元素大约重复了10,000次。使用Counter而不是.count将我的时间缩短了一半。给Counter点赞。 - shshnk
2
我正在处理一个包含350,000个字符串(URL)的列表:使用Counter只需要不到一秒钟的时间,而在等待.count()完成的过程中,我有时间喝一杯冰沙,所以再次为Counter加1 :) (事实上,我正在计算每个不同的URL,因此,如前所述,在这种情况下最好使用Counter)。 - pawamoy
我可能漏掉了什么。正在处理包含 random.randint(0,sys.maxsize)数字的 list[long] 数据集(多达5000万个),尝试使用相同参数计数另一个 randint.countCounter 快约10倍(仅尝试计数一次)。此外,我切换到 generators,它们可以由 Counter 处理,但综合时间(生成列表/生成器+计数)更倾向于 list.count。这种行为在 Python3Python2 中都是一致的。 - CristiFati

21

通过使用计数器字典,在Python列表中以最高效的方式计算所有元素的出现次数以及最常见元素的出现值。

如果我们的Python列表为:

l=['1', '1', '1', '1', '1', '1', '2', '2', '2', '2', '7', '7', '7', '10', '10']

要查找Python列表中每个项目的出现次数,请使用以下方法:

\>>from collections import Counter

\>>c=Counter(l)

\>>print c

Counter({'1': 6, '2': 4, '7': 3, '10': 2})

查找Python列表中最常出现的/最高出现次数的项:

\>>k=c.most_common()

\>>k

[('1', 6), ('2', 4), ('7', 3), ('10', 2)]

针对最高者

\>>k[0][1]

6

只需使用k[0][0]即可获取该项。

\>>k[0][0]

'1'

要查找列表中第n个最高项及其出现次数,请使用以下方法:

**当n=2时**

\>>print k[n-1][0] # For item

2

\>>print k[n-1][1] # For value

4

2
您可以使用`pandas`,通过将`list`转换为`pd.Series`,然后简单地使用`.value_counts()`。
import pandas as pd
a = ['1', '1', '1', '1', '1', '1', '2', '2', '2', '2', '7', '7', '7', '10', '10']
a_cnts = pd.Series(a).value_counts().to_dict()

Input  >> a_cnts["1"], a_cnts["10"]
Output >> (6, 2)

1

使用lambda和map函数的组合也可以完成任务:

list_ = ['a', 'b', 'b', 'c']
sum(map(lambda x: x=="b", list_))
:2

-2

您可以将列表转换为由空格分隔的元素字符串,并根据要搜索的数字/字符进行拆分。

对于大型列表,这种方法会更加清晰快速。

>>>L = [2,1,1,2,1,3]
>>>strL = " ".join(str(x) for x in L)
>>>strL
2 1 1 2 1 3
>>>count=len(strL.split(" 1"))-1
>>>count
3

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接