Skip to content

Python Counter: collections.Counter로 요소 세기 및 집계하기

Updated on

리스트의 요소, 문자열의 문자, 문서의 단어 출현 횟수를 세는 것은 프로그래밍에서 가장 흔한 작업 중 하나입니다. 수동으로 하면 루프를 작성하고, 딕셔너리를 초기화하고, 조건문이나 .get() 호출로 누락된 키를 처리해야 합니다. 이러한 보일러플레이트 코드는 실제 의도를 가리고, 버그를 도입하며, 빈도 카운트가 필요할 때마다 작업을 늦춥니다.

Python의 collections.Counter는 이러한 마찰을 완전히 제거합니다. 한 줄로 해시 가능한 객체를 세고, 가장 흔한 요소를 찾기 위한 내장 메서드를 제공하며, 빈도 분포를 비교하기 위한 산술 연산을 지원합니다. 이 가이드는 기본적인 카운팅부터 고급 멀티셋 연산까지 Counter를 효과적으로 사용하는 데 필요한 모든 것을 다룹니다.

📚

collections.Counter란?

Counter는 Python collections 모듈에 있는 딕셔너리 서브클래스로, 해시 가능한 객체를 세기 위해 특별히 설계되었습니다. 각 요소는 딕셔너리 키로 저장되고, 그 카운트가 해당 값으로 저장됩니다.

from collections import Counter
 
fruits = ['apple', 'banana', 'apple', 'cherry', 'banana', 'apple']
count = Counter(fruits)
print(count)
# Counter({'apple': 3, 'banana': 2, 'cherry': 1})

Counter 생성하기

Counter는 여러 입력 유형을 받아들여 다양한 데이터 소스에 유연하게 대응합니다.

from collections import Counter
 
# 리스트에서
colors = Counter(['red', 'blue', 'red', 'green', 'blue', 'red'])
print(colors)  # Counter({'red': 3, 'blue': 2, 'green': 1})
 
# 문자열에서 (각 문자를 카운트)
letters = Counter('mississippi')
print(letters)  # Counter({'s': 4, 'i': 4, 'p': 2, 'm': 1})
 
# 딕셔너리에서
inventory = Counter({'apples': 15, 'oranges': 10, 'bananas': 7})
 
# 키워드 인수에서
stock = Counter(laptops=5, monitors=12, keyboards=30)

카운트 접근하기

기본 인덱싱

일반 딕셔너리처럼 카운트에 접근하지만, 누락된 키는 KeyError를 발생시키는 대신 0을 반환합니다:

from collections import Counter
 
c = Counter(['a', 'b', 'a'])
print(c['a'])  # 2
print(c['z'])  # 0 (KeyError 없음!)
 
# 일반 dict 동작과 비교
d = {'a': 2, 'b': 1}
# d['z']  # KeyError 발생

이 제로 기본값 동작은 많은 카운팅 시나리오에서 .get(key, 0) 또는 defaultdict(int)의 필요성을 제거합니다.

모든 요소 가져오기

elements() 메서드는 요소에 대한 이터레이터를 반환하며, 각 요소를 카운트만큼 반복합니다:

from collections import Counter
 
c = Counter(a=3, b=2, c=1)
print(list(c.elements()))
# ['a', 'a', 'a', 'b', 'b', 'c']

most_common() 메서드

most_common() 메서드는 빈도순으로 정렬된 요소를 반환합니다.

from collections import Counter
 
text = "to be or not to be that is the question"
word_freq = Counter(text.split())
 
# 모든 요소를 빈도순으로 정렬
print(word_freq.most_common())
# [('to', 2), ('be', 2), ('or', 1), ('not', 1), ...]
 
# 상위 N개 요소만
log_levels = Counter(['INFO', 'WARNING', 'INFO', 'ERROR', 'INFO', 'DEBUG',
                      'WARNING', 'INFO', 'ERROR', 'INFO'])
print(log_levels.most_common(2))
# [('INFO', 5), ('WARNING', 2)]
 
# 가장 적은 것 (역순 슬라이스)
print(log_levels.most_common()[-2:])
# [('DEBUG', 1), ('ERROR', 2)]

Counter 산술 연산

Counter는 빈도 분포의 결합과 비교를 위한 산술 및 집합 연산을 지원합니다.

from collections import Counter
 
morning = Counter(coffee=10, tea=5, juice=3)
afternoon = Counter(coffee=8, tea=7, water=4)
 
# 덧셈: 카운트 결합
total = morning + afternoon
print(total)  # Counter({'coffee': 18, 'tea': 12, 'water': 4, 'juice': 3})
 
# 뺄셈: 양수 카운트만 유지
stock = Counter(apples=20, oranges=15, bananas=10)
sold = Counter(apples=8, oranges=15, bananas=12)
remaining = stock - sold
print(remaining)  # Counter({'apples': 12})
 
# 교집합 (&): 대응하는 카운트의 최솟값
a = Counter(apple=3, banana=2, cherry=5)
b = Counter(apple=1, banana=4, cherry=2)
print(a & b)  # Counter({'cherry': 2, 'banana': 2, 'apple': 1})
 
# 합집합 (|): 대응하는 카운트의 최댓값
print(a | b)  # Counter({'cherry': 5, 'banana': 4, 'apple': 3})
 
# 단항 +: 0 및 음수 카운트 제거
c = Counter(a=3, b=0, c=-2)
print(+c)  # Counter({'a': 3})

업데이트와 차감

from collections import Counter
 
# update()는 카운트를 더함 (dict.update는 교체하지만, 이것은 더함)
c = Counter(a=3, b=1)
c.update(['a', 'b', 'b', 'c'])
print(c)  # Counter({'a': 4, 'b': 3, 'c': 1})
 
# subtract()는 카운트를 차감 (0과 음수 유지)
c = Counter(a=4, b=2, c=0)
c.subtract(Counter(a=1, b=3, c=2))
print(c)  # Counter({'a': 3, 'b': -1, 'c': -2})
 
# total()은 모든 카운트의 합을 반환 (Python 3.10+)
inventory = Counter(widgets=50, gadgets=30, gizmos=20)
print(inventory.total())  # 100

실용적인 사용 사례

단어 빈도 분석

from collections import Counter
import re
 
text = """
Python is a versatile programming language. Python is used for web development,
data science, machine learning, and automation. Python's simplicity makes it
a favorite among developers.
"""
 
words = re.findall(r'\b[a-z]+\b', text.lower())
word_freq = Counter(words)
 
print("Top 5 most frequent words:")
for word, count in word_freq.most_common(5):
    print(f"  {word}: {count}")

아나그램 탐지

from collections import Counter
 
def are_anagrams(word1, word2):
    return Counter(word1.lower()) == Counter(word2.lower())
 
print(are_anagrams("listen", "silent"))  # True
print(are_anagrams("hello", "world"))    # False

투표 집계 시스템

from collections import Counter
 
votes = ['Alice', 'Bob', 'Alice', 'Charlie', 'Bob', 'Alice',
         'Charlie', 'Alice', 'Bob', 'Alice']
 
results = Counter(votes)
winner, winning_votes = results.most_common(1)[0]
total_votes = sum(results.values())
 
print(f"Election Results (Total votes: {total_votes}):")
for candidate, count in results.most_common():
    percentage = (count / total_votes) * 100
    print(f"  {candidate}: {count} votes ({percentage:.1f}%)")
print(f"\nWinner: {winner} with {winning_votes} votes")

로그 파일 분석

from collections import Counter
import re
 
log_entries = [
    "2026-02-10 08:15:00 ERROR Database connection failed",
    "2026-02-10 08:15:01 INFO Retrying connection",
    "2026-02-10 08:15:02 ERROR Database connection failed",
    "2026-02-10 08:16:00 WARNING Disk usage at 85%",
    "2026-02-10 08:17:00 INFO Request processed",
    "2026-02-10 08:18:00 ERROR API timeout",
]
 
levels = Counter(
    re.search(r'(INFO|WARNING|ERROR)', line).group()
    for line in log_entries
)
print("Log Level Distribution:")
for level, count in levels.most_common():
    print(f"  {level}: {count}")

Counter vs defaultdict(int): 언제 어떤 것을 사용할까

특성Counterdefaultdict(int)
목적카운팅 전용으로 설계범용 기본값 딕셔너리
초기화Counter(iterable)로 한 번에 카운트수동 루프 필요
누락된 키0 반환0 반환
most_common()내장 메서드수동 정렬 필요
산술 (+, -)지원미지원
집합 연산 (&, |)지원미지원
elements()확장된 이터레이터 반환사용 불가
update() 동작카운트에 더함값을 교체
성능최적화된 C 구현약간 느림
최적 용도빈도 분석, 멀티셋 연산사용자 정의 기본값 로직

요소를 세거나 빈도 분포를 비교하는 것이 주된 목표라면 Counter를 사용하세요. 카운팅이 더 넓은 데이터 구조 패턴의 부수적인 부분이라면 defaultdict(int)를 사용하세요.

빈도 분포 시각화

Counter로 요소를 센 후, 종종 분포를 시각화하고 싶을 것입니다. 빈도 분포의 인터랙티브 탐색을 위해 PyGWalker (opens in a new tab)는 pandas DataFrame을 Jupyter 내에서 직접 Tableau 스타일의 인터랙티브 UI로 변환합니다:

from collections import Counter
import pandas as pd
import pygwalker as pyg
 
# Counter를 DataFrame으로 변환
data = Counter("abracadabra")
df = pd.DataFrame(data.items(), columns=['Character', 'Count'])
 
# 인터랙티브 시각화 시작
walker = pyg.walk(df)

이것은 큰 카운터가 있고 빈도 분포를 인터랙티브하게 필터링, 정렬, 탐색하고 싶을 때 특히 유용합니다.

FAQ

Python에서 collections.Counter는 무엇을 하나요?

collections.Counter는 해시 가능한 객체를 세는 딕셔너리 서브클래스입니다. 임의의 이터러블을 전달하면 키가 요소이고 값이 카운트인 딕셔너리 같은 객체를 반환합니다. 빈도 분석을 위한 most_common() 같은 메서드, 카운트를 결합하기 위한 산술 연산자를 제공하며, KeyError 대신 누락된 키에 대해 0을 반환합니다.

Python Counter를 사용하여 리스트의 항목 출현 횟수를 세려면?

collections에서 Counter를 임포트하고 리스트를 직접 전달합니다: Counter(['a', 'b', 'a', 'c'])Counter({'a': 2, 'b': 1, 'c': 1})을 반환합니다. 특정 카운트를 얻으려면 요소로 인덱싱합니다: counter['a']2를 반환합니다. 가장 빈번한 항목에는 counter.most_common(n)을 사용합니다.

카운팅에서 Counter와 일반 딕셔너리의 차이는?

Counter는 카운팅 전용으로 설계되었습니다: 한 번의 호출로 전체 이터러블을 세고, KeyError 대신 누락된 키에 0을 반환하며, 정렬된 빈도를 위한 most_common()이 있고, 산술 연산(+, -, &, |)을 지원하며, 값을 교체하는 대신 카운트에 더하는 update()를 포함합니다. 일반 딕셔너리는 수동 루프 구성이 필요하고 이러한 기능이 없습니다.

두 Counter 객체를 빼거나 더할 수 있나요?

네. + 연산자는 카운트를 결합합니다: Counter(a=3) + Counter(a=1)Counter({'a': 4})를 생성합니다. - 연산자는 카운트를 빼고 0 또는 음수 결과를 버립니다. & 연산자는 대응하는 카운트의 최솟값(교집합), |는 최댓값(합집합)을 제공합니다. 음수 카운트를 보존하는 뺄셈에는 subtract() 메서드를 사용하세요.

Python Counter는 대규모 데이터셋에 효율적인가요?

네. Counter는 CPython에서 최적화된 C 코드로 구현되어, 카운팅에서 수동 Python 루프보다 빠릅니다. 이터러블에서 Counter 생성은 O(n)입니다. 개별 카운트 접근은 O(1)입니다. most_common(k) 연산은 top-k 요소만 필요할 때 O(n log k) 효율을 위해 내부적으로 힙을 사용합니다.

결론

Python의 collections.Counter는 요소 세기와 빈도 분석을 위한 표준 도구입니다. 수동 딕셔너리 카운팅을 단일 생성자 호출로 대체하고, 즉시 순위를 위한 most_common()을 제공하며, 멀티셋 비교를 간단하게 만드는 산술 연산을 지원합니다. 단어 빈도 분석, 투표 집계, 재고 관리, 로그 파일 분석 등 무엇을 하든, Counter가 카운팅을 처리하여 중요한 로직에 집중할 수 있습니다.

📚