Counter: словарь, который считает сам
Counter из collections — словарь, который считает сам: слова строки, буквы слова, повторения в списке. most_common отдаёт самых частых, арифметика счётчиков сравнивает две выборки.
Редакция Питоники
Считать повторения приходится постоянно: слова в тексте, покупки в чеках, голоса в опросе. Ручной счётчик через цикл уже умеет setdefault из урока 10 — но в стандартной библиотеке Python есть готовый инструмент. Counter снимает с программиста весь ручной труд подсчёта: не нужен ни цикл с накопителем, ни проверка, встречался ли элемент раньше.
Первый Counter
from collections import Counter
words = ['чай', 'кофе', 'чай', 'чай', 'кофе', 'сок']
count = Counter(words)
print(count)
print(count['чай'])
Counter({'чай': 3, 'кофе': 2, 'сок': 1})
3Counter — словарь-наследник: ключи — элементы, значения — количества. Печатается он словом Counter перед парами «элемент — количество». Доступ обычный: count['чай'] вернул 3. А вот отсутствие элемента — не ошибка: count['пирог'] вернёт 0. Считать нечего — это честный ответ, а не KeyError.
Подсчёт слов за строку
from collections import Counter
phrase = 'мы пели мы плясали мы пели'
print(Counter(phrase.split()))
print(Counter('абракадабра'))
Counter({'мы': 3, 'пели': 2, 'плясали': 1})
Counter({'а': 5, 'б': 2, 'р': 2, 'к': 1, 'д': 1})split разрезает строку по пробелам в список слов — а список Counter уже умеет считать. Строка и сама по себе последовательность: посчитав её как в уроке 8, получим частоты букв. Так одна строка кода решает классическую задачу частотного анализа.
most_common: самые частые
from collections import Counter
words = ['чай', 'кофе', 'чай', 'чай', 'кофе', 'сок']
count = Counter(words)
print(count.most_common(2))
print(count.most_common(1)[0][0])
[('чай', 3), ('кофе', 2)]
чайfrom collections import Counter
words = ['чай', 'кофе', 'чай', 'чай', 'кофе', 'сок']
count = Counter(words)
count['чай'] += 1
count.update(['сок'])
print(count)
print(count.most_common())
Counter({'чай': 4, 'кофе': 2, 'сок': 2})
[('чай', 4), ('кофе', 2), ('сок', 2)]Counter — это словарь, но не совсем
Counter ведёт себя как словарь и при этом умеет то, чего обычный словарь не умеет. Сначала проверим очевидное: к нему применимы in, перебор, len, доступ по ключу. Отличия — в поведении при отсутствующем ключе и в дополнительных методах.
from collections import Counter
text = 'мы пели мы плясали мы пели'
words = text.split()
count = Counter(words)
print(count)
print(count['мы'])
print(count['танцевали'])
print(len(count))
Counter({'мы': 3, 'пели': 2, 'плясали': 1})
3
0
3Третья строка — главное отличие: 'танцевали' в счётчике нет, но вместо KeyError вернулся 0. Четвёртая — длина счётчика равна числу уникальных слов, а не числу слов в тексте: в строке их было шесть, уникальных три. Для обычного словаря count['танцевали'] уронил бы программу.
Кстати, про разницу в шесть и три. Это не мелочь: если вы считаете уникальные элементы через len(count), то получаете число различных слов, а не длину текста. Задачи «сколько всего слов» и «сколько разных слов» — разные задачи, и Counter отвечает на обе, если знать, какую спрашивать.
Арифметика счётчиков
Вот здесь Counter раскрывается по-настоящему. Счётчики можно складывать, вычитать и сравнивать как множества. Для обычного словаря это было бы несколько строк с циклами, а здесь — одна операция.
from collections import Counter
a = Counter('абракадабра')
b = Counter('абра')
print(a + b)
print(a - b)
print(a & b)
Counter({'а': 7, 'б': 3, 'р': 3, 'к': 1, 'д': 1})
Counter({'а': 3, 'б': 1, 'р': 1, 'к': 1, 'д': 1})
Counter({'а': 2, 'б': 1, 'р': 1})Три операции, три ответа. Сложение складывает количества по каждому ключу. Вычитание вычитает из a количества b и оставляет только положительные результаты — поэтому а встречается 5 раз, б 2, а абра вычитает по одному разу каждого: 5 минус 2 даёт 3, 2 минус 1 даёт 1. Пересечение & оставляет только общие ключи и берёт по минимуму.
Практическое применение: a - b — это «буквы, которые встречаются в первом тексте чаще, чем во втором». Для сравнения двух текстов или подсчёта слов, характерных для одной выборки, такие готовые операции экономят кучу кода. Тот же приём работает и с most_common: посмотрите, какие слова вышли за пределы общей части.
update и накопление
Счётчик можно не только создать сразу, но и наполнять по частям. Метод update принимает строку, список или другой счётчик и прибавляет количества. Это удобно, когда данные приходят порциями: файлы, страницы API, чанки из очереди.
from collections import Counter
count = Counter()
count.update(['чай', 'чай'])
count.update('коф')
print(count)
print(count.most_common(1))
Counter({'чай': 2, 'к': 1, 'о': 1, 'ф': 1})
[('чай', 2)]Строка 'коф' посчиталась по буквам — это не опечатка, а прямое следствие того, что Counter работает с любой последовательностью. Строка — тоже последовательность. Чтобы этого не произошло, передавайте text.split(): список слов, а не строка букв.
Словарь, список и Counter: когда что брать
Стоит проговорить, когда подсчёт через Counter уместен, а когда лучше обойтись без него. Counter — это словарь, у которого values всегда числа и которые всегда означают «сколько раз встретилось». Если вам нужно просто хранить числа под ключами, Counter избыточен: он ничего не добавляет, кроме лишнего импорта.
На практике я беру Counter в трёх случаях. Первый — подсчёт повторов: слова в тексте, голоса в опросе, покупки в заказе. Второй — когда нужно сравнивать две выборки: a - b сразу показывает разницу, и писать цикл с двумя счётчиками не нужно. Третий — когда нужен топ: most_common(10) даёт десять самых частых элементов одной строкой. Во всех остальных случаях обычный словарь с get будет честнее и понятнее.
from collections import Counter
count = Counter(['чай', 'кофе', 'чай'])
print(count.most_common())
print(count.most_common(1))
print(count.most_common(1)[0][0])
print(list(count.elements()))
[('чай', 2), ('кофе', 1)]
[('чай', 2)]
чай
['чай', 'чай', 'кофе']Четыре способа достать самое частое. most_common() без аргумента отдаёт все пары по убыванию частоты, most_common(1) — только первую, а двойное индексирование [0][0] вытаскивает из кортежа сам элемент. Последний вызов elements() разворачивает счётчик обратно в список: каждый элемент повторяется столько раз, сколько его посчитали. Это, кстати, удобный способ получить исходную последовательность заново — сортировкой по ключу.
Что дальше
Counter закрывает задачу подсчёта повторов целиком: одна строка вместо цикла с накопителем. Дальше — словарь, который сам создаёт значения по заданному типу: defaultdict в уроке 12. А если хочется собрать частотный словарь целого текста с нуля — загляните в урок 20, там финальный проект раздела.
Сначала предскажи ответ в голове — это главный навык программиста.
from collections import Counter
print(Counter('мама'))
from collections import Counter
c = Counter(['а', 'б', 'а'])
print(c.most_common(1)[0][0])
from collections import Counter
c = Counter(['сок', 'сок'])
print(c['чай'])
print(sum(c.values()))
1. Что вернёт count['пирог'], если Counter создан без слова 'пирог'?
2. Что делает most_common(2)?
3. Как посчитать частоты слов в строке phrase?
4. Что делает count.update(['сок'])?
5. Чем Counter отличается от обычного dict?
6. Что вернёт a - b, если a = Counter('абракадабра'), а b = Counter('абра')?
7. Что делает count.update('коф') для счётчика, созданного из списка слов?
8. Сколько уникальных слов в счётчике Counter('мы пели мы плясали мы пели'.split())?
Дана строка phrase = 'чай кофе чай сок кофе чай'. Посчитай слова через Counter, выведи счётчик целиком и самое частое слово.
Как посчитать количество слов в строке на Python?
Разрезать строку по пробелам и отдать список в Counter: Counter(phrase.split()) вернёт словарь «слово — сколько раз встретилось». Для уникальных слов удобен len этого счётчика, для самого частого — most_common(1).
Урок 10: setdefaultЧто делает Counter в Python?
Считает элементы последовательности: Counter(['чай', 'чай']) вернёт Counter({'чай': 2}). Это словарь-наследник из стандартного модуля collections, поэтому доступ по ключу, перебор и in работают как у обычного dict.
Что возвращает most_common()?
Список пар «элемент — количество», упорядоченный по убыванию частоты. С аргументом n — только n первых пар, без аргумента — все. most_common(1)[0][0] даёт самый частый элемент.
Падает ли Counter на отсутствующем ключе?
Нет: count['пирог'] вернёт 0, ничего не вставляя в словарь. Это удобно для подсчётов, но опечатки в ключах Counter тоже молча посчитает нулём — проверяйте написание.
Можно ли складывать два счётчика Counter?
Да, и это одно из самых полезных свойств. Оператор + складывает количества по общим ключам, оператор - вычитает и оставляет только положительные результаты, оператор & находит общие ключи по минимуму. Так сравнивают два текста или две выборки: разность показывает, какие слова характерны именно для первого.
Как посчитать количество разных слов, а не общее число слов?
Через len(counter): он считает уникальные элементы. Общее число вхождений даёт sum(counter.values()). Для строки 'мы пели мы плясали мы пели' это 3 и 6 соответственно — две разные величины, которые часто путают.
Почему count.update('коф') посчитает буквы, а не слово?
Потому что update работает с любой последовательностью, а строка — это последовательность букв. Чтобы счётчик считал слова, передавайте text.split(): список слов. Это частая невнимательность при разборе строк.
Понравился урок? Сошлитесь на него
«Counter снимает с программиста весь ручной труд подсчёта: не нужен ни цикл с накопителем, ни проверка, встречался ли элемент раньше.»
Скопируйте готовую ссылку в формате HTML, Markdown или чистый адрес и вставьте в статью на Habr, VC, Telegram-канал или свой блог — так о проекте узнают новые читатели.
Что дальше
Осталось в разделе: 20 из 20. Прогресс хранится в вашем браузере.
Что читать дальше
Словари · Урок 10
setdefault: значение при первом обращении
setdefault возвращает значение по ключу, а если ключа нет — сначала записывает умолчание: группировка гостей по городам без if-проверок, счётчики и подводный камень с вычислением аргумента.
Словари · Урок 12
defaultdict: словарь с заводским умолчанием
defaultdict сам создаёт значение при первом обращении: списки для группировки и нули для счётчиков — без setdefault и проверок. Плюс factory, рецепты по типам и грабли с лишними ключами.
Словари · Урок 13
Сортировка словаря по ключам и значениям
Словарь нельзя отсортировать на месте — но можно получить отсортированный: sorted по ключам, key=lambda по значениям, вторичный ключ кортежем, top-N срезом и dict(sorted(...)) обратно.
Похожие уроки по темам
Подобраны автоматически по пересечению тем и ключевых слов.
Строки · Урок 15
count: считаем вхождения в строке
count отвечает на вопрос «сколько?»: вхождений подстроки, символов в слове, слов в отзыве. Разбираем непересекающийся подсчёт, диапазон поиска и ловушку строки 'ааа'.
python количество вхождений подстрокиpython посчитать символы в строке
Функции · Урок 20
Проект на функциях Python: библиотека утилит для текста
Итоговый проект раздела: своя мини-библиотека утилит для текста — normalize, word_count, top_words. Три куска, каждый запускается и проверяется отдельно.
python подсчёт слов в строкеpython частотность слов
Словари · Урок 20
Проект: частотный словарь текста
Финальный проект: частотный словарь текста — режем текст на слова, чистим, отбрасываем стоп-слова, считаем через Counter и выводим топ-5 ровными колонками.
частотный словарь pythonподсчёт слов python