Класс Counter модуля collections

Курс по стандартной библиотеке: https://stepik.org/a/259466?utm_source=proproprogs

Смотреть материал на YouTube | RuTube

Рассмотрим еще один класс Counter модуля connections, входящий в состав стандартной библиотеки Python. С помощью этого класса удобно производить подсчет повторяющихся элементов различных последовательностей.

Пользоваться им очень просто. Пусть у нас имеется строка 'abrakadabra', в которой необходимо определить число повторений ее символов. Для этого достаточно создать объект класса Counter с передачей этой строки:

from collections import Counter
 
s = 'abrakadabra'
syms = Counter(s)

В итоге syms будет словарем с ключами в виде символов и значениями – числом их повторения в строке s:

print(syms) # Counter({'a': 5, 'b': 2, 'r': 2, 'k': 1, 'd': 1})

Помимо строки в Counter можно передавать любую итерируемую последовательность, например:

c1 = Counter(['abc', 'cba', 'abc', 'ABC', 'ABC']) # Counter({'abc': 2, 'ABC': 2, 'cba': 1})
c2 = Counter((1, 2, 0, 4, 3, 2, 1, 1)) # Counter({1: 3, 2: 2, 0: 1, 4: 1, 3: 1})

И даже вложенные последовательности:

c3 = Counter([(1, 2, 3), ('a', 'b'), (1, 2), (1, 2, 3)]) # Counter({(1, 2, 3): 2, ('a', 'b'): 1, (1, 2): 1})

Единственное ограничение, чтобы подсчитываемые элементы были хэшируемыми, т.к. они являются ключами словаря. Например, определять вложенные списки вместо кортежей недопустимо.

Конечно, в самом простом случае, объект класса Counter можно создать без каких-либо данных:

c = Counter() # пустой словарь

Или же с набором любых желаемых пар ключ-значение:

c = Counter({'Alex': 2, 'Mike': 1}) # Counter({'Alex': 2, 'Mike': 1})
w = Counter(car=1, house=2, dog=5) # Counter({'dog': 5, 'house': 2, 'car': 1})

Так как класс Counter унаследован от встроенного класса словаря dict, то объекты счетчика Counter поддерживают все стандартные словарные операции и методы. Например:

c['Alex'] # 2
c['Mike'] = 7 # изменение счетчика
c['Serg'] # 0

Обратите внимание, что для несуществующих ключей класс Counter возвращает значение 0, в отличие от словаря dict, который в этом случае генерирует исключение KeyError:

d = {}
d['a'] # KeyError

Методы класса Counter

Также несколько иначе работает метод update() класса Counter. С его помощью можно к существующим ключам прибавлять новые значения. Например:

c = Counter({'Alex': 2, 'Mike': 1})
c.update({'Alex': 1, 'Serg': 5})  # Counter({'Serg': 5, 'Alex': 3, 'Mike': 1})

Видим, что к существующим ключам добавляются значения, а изначально несуществующие ключи, просто создаются.

Следующий метод most_common(), который присущ именно классу Counter, позволяет отобрать наиболее встречаемые элементы, то есть, ключи с наибольшими значениями:

c.most_common(2) # [('Serg', 5), ('Alex', 3)]
c.most_common() # [('Serg', 5), ('Alex', 3), ('Mike', 1)]

Возвращается список с кортежами в формате ключ-значение. Причем, когда не указывается количество возвращаемых элементов, то возвращаются все в порядке убывания частоты.

Следующий метод elements() класса Counter возвращает итератор для получения всех элементов (ключей):

c.elements() # <itertools.chain object at 0x000002082A4DE1A0>
lst = list(c.elements())

При отображении списка lst увидим последовательность:

['Alex', 'Alex', 'Alex', 'Mike', 'Serg', 'Serg', 'Serg', 'Serg', 'Serg']

По сути, здесь ключи, которые повторяются указанное число раз.

Еще один метод total(), который появился в версии Python 3.10, возвращает сумму значений всех счетчиков:

c.total() # 9

Операции с классом Counter

С объектами класса Counter можно выполнять ряд полезных операций. Пусть имеются два следующих объекта:

c1 = Counter(a=1, b=3, c=2)
c2 = Counter(b=2, d=3, f=1)

При сложении этих объектов будут складываться соответствующие значения ключей словарей и формироваться новый объект Counter:

c1 + c2 # Counter({'b': 5, 'd': 3, 'c': 2, 'a': 1, 'f': 1})

При вычитании соответствующие значения вычитаются:

c1 - c2 # Counter({'c': 2, 'a': 1, 'b': 1})
c2 - c1 # Counter({'d': 3, 'f': 1})

Обратите внимание, что если в процессе вычитания значение ключа становится меньше или равно нулю, то этот ключ исключается (удаляется).

Кроме того с объектами c1, c2 можно выполнять операции объединения и пересечения подобно множествам:

c1 | c2 # объединение: Counter({'b': 3, 'd': 3, 'c': 2, 'a': 1, 'f': 1})
c1 & c2 # пересечение: Counter({'b': 2})

При объединении одинаковые ключи оставляются с наибольшим значением, а при пересечении – с наименьшим значением.

Все эти же самые операции можно записывать и в таком виде:

c1 -= c2
c2 += c1
c1 |= c2
c1 &= c2

Кроме того, дополнительно существует метод subtract(), который позволяет вычислять отрицательные значения при вычитании объектов. Например:

c1 = Counter(a=1, b=3, c=2)
c2 = Counter(b=2, d=3, f=1)
c1.subtract(c2) # Counter({'c': 2, 'a': 1, 'b': 1, 'f': -1, 'd': -3})

Изменения сохраняются в объекте c1.

Вот общие возможности класса Counter. Использовать его полезно, когда в программе нужно выполнять подсчет повторяющихся элементов. Довольно часто это требуется в таких задачах, как:

  • анализ текста: подсчет символов, слов, предложений;
  • работа с базами данных: агрегирование результатов запросов;
  • аналитика больших наборов данных: быстрое получение статистических данных.

Курс по стандартной библиотеке: https://stepik.org/a/259466?utm_source=proproprogs

Видео по теме