Самый быстрый способ подсчитать количество вхождений в списке Python

У меня есть список Python, и я хочу знать, как быстрее всего подсчитать количество вхождений элемента '1' в этом списке. В моем реальном случае элемент может встречаться десятки тысяч раз, поэтому мне нужен быстрый способ.

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

Какой подход: .count или collections.Counter, вероятно, более оптимизирован?


person prrao    schedule 17.09.2012    source источник
comment
Всегда ли список отсортирован? Вы всегда считаете первый элемент?   -  person jscs    schedule 17.09.2012
comment
возможный дубликат Как рассчитать количество вхождений элемент списка в Python?   -  person jscs    schedule 17.09.2012
comment
@JoshCaswell Нет, список не отсортирован, и я бы посчитал любой элемент. Я не был уверен, какой подход: count или collections.Counter был лучше оптимизирован, поэтому я и спросил   -  person prrao    schedule 17.09.2012
comment
@prrao Зависит от того, хотите ли вы делать это несколько раз или нет.   -  person jamylak    schedule 17.09.2012
comment
@jamylak Да, я хочу сделать это несколько раз для нескольких элементов.   -  person prrao    schedule 17.09.2012
comment
@prrao Все равно лучше использовать .count   -  person Jakob Bowyer    schedule 17.09.2012
comment
@Якоб Спасибо. count отлично работает для больших списков   -  person prrao    schedule 17.09.2012


Ответы (5)


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}
person Jakob Bowyer    schedule 17.09.2012
comment
Как вы думаете, какой подход лучше оптимизирован? Я думаю, лучший вариант зависит от случая? - person prrao; 17.09.2012
comment
@prrao. В этом случае count примерно в 20 раз быстрее, чем создание Counter, но тот же Counter можно использовать для получения счетчиков с несколькими разными значениями с очень низкими дополнительными затратами. Если вам нужно подсчитать 20 или более значений из одного и того же списка, Counter будет эффективнее, чем запускать .count() 20 раз. - person John La Rooy; 17.09.2012
comment
Я работал с набором данных из 1 000 000 целых чисел, где диапазон набора был 100, т.е. каждый элемент повторялся около 10 000 раз. Использование Counter вместо .count сократило время вдвое. +1 за Counter. - person shshnk; 26.09.2015
comment
И я работал со списком из 350 000 строк (URL-адресов): использование Counter заняло меньше секунды, пока у меня было время выпить коктейль, ожидая выполнения .count(), поэтому +1 снова для Counter :) (Действительно, я подсчитывал каждый отдельный URL-адрес, поэтому, как было сказано ранее, в этом случае лучше использовать счетчик). - person pawamoy; 19.05.2016
comment
Я должен что-то упустить. Работая с наборами данных list[long] (содержащими random.randint(0, sys.maxsize) чисел, до 50 М)` , пытаясь посчитать еще randint с теми же параметрами, .cont примерно в 10 раз быстрее, чем Counter (попробуйте только посчитать однажды). Кроме того, я переключился на генераторы, с которыми Counter умеет обращаться, но комбинированное время (создание списка/генератора + подсчет) благоприятствует list и .count. Поведение одинаково для Python3 и Python2. - person CristiFati; 22.08.2017

С помощью словаря Counter, наиболее эффективным способом подсчитывается количество вхождений всех элементов, а также наиболее распространенных элементов в списке 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
person Surya Prakash Singh    schedule 11.02.2015

Вы можете использовать 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)
person J. Doe    schedule 09.10.2018

Комбинация функции лямбда и карты также может выполнять эту работу:

list_ = ['a', 'b', 'b', 'c']
sum(map(lambda x: x=="b", list_))
:2
person Mahdi Ghelichi    schedule 16.01.2018

Вы можете преобразовать список в строку с элементами, разделенными пробелом, и разделить его на основе числа/символа для поиска.

Будет чистым и быстрым для большого списка.

>>>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
person ravindra ghongane    schedule 03.12.2016