Для подсчета элементов в списке вы можете использовать collections.Counter
, но что, если нужно подсчитать только некоторые элементы?
Я настроил этот пример(обратите внимание: numpy просто для удобства. В общем, список будет содержать произвольные объекты Python):
num_samples = 10000000
num_unique = 1000
numbers = np.random.randint(0, num_unique, num_samples)
Я хотел бы посчитать, как часто число встречается в этом списке, но меня интересует тольков цифрах <= 10. </p>
Это базовый уровень для победы.Счетчик просто считает все, что должно привести к дополнительным затратам.
%%time
counter = Counter(numbers)
CPU times: user 1.38 s, sys: 7.49 ms, total: 1.39 s
Wall time: 1.39 s
Фильтрация повторяемого кода при подсчете кажется невозможной.Но следующий код очень плохой стиль, он проходит по списку дважды, вместо использования одного цикла:
%%time
numbers = [number for number in numbers if number<=10]
counter = Counter(numbers)
CPU times: user 1.3 s, sys: 22.1 ms, total: 1.32 s
Wall time: 1.33 s
Это ускорение в основном незначительно.Давайте попробуем один цикл:
%%time
counter = defaultdict(int)
for number in numbers:
if number > 10:
continue
counter[number]+=1
CPU times: user 1.99 s, sys: 11.5 ms, total: 2 s
Wall time: 2.01 s
Ну, мой единственный цикл намного хуже.Я предполагаю, что Counter получает прибыль от реализации на основе C?
Следующее, что я попробовал, было переключение моего выражения списка на выражение генератора.В принципе это должно означать, что генератор проходит только один раз, пока он потребляется счетчиком.Числа разочаровывают, хотя, в основном, это так же быстро, как ванильный счетчик:
%%time
iterator = (number for number in numbers if number <= 10)
counter = Counter(iterator)
CPU times: user 1.38 s, sys: 8.51 ms, total: 1.39 s
Wall time: 1.39 s
В этот момент я сделал шаг назад и перезапустил цифры несколько раз.Три версии счетчика (нефильтрованные, составление списка, выражение генератора) почти одинаковы по скорости.Версия defaultdict
значительно медленнее.
Как эффективно подсчитывать элементы в списке Python, одновременно фильтруя элементы?