파이썬 collections 모듈의 Counter 사용법
이번 포스팅에서는 데이터의 개수를 셀 때 매우 유용한 파이썬의 collections 모듈의 Counter 클래스에 대해서 알아보겠습니다.
Counter 기본 사용법
collections 모듈의 Counter 클래스는 별도 패키지 설치 없이 파이썬만 설치되어 있다면 다음과 같이 임포트해서 바로 사용할 수 있습니다.
from collections import Counter
Counter 생성자는 여러 형태의 데이터를 인자로 받는데요.
먼저 중복된 데이터가 저장된 배열을 인자로 넘기면 각 원소가 몇 번씩 나오는지가 저장된 객체를 얻게 됩니다.
>>> Counter(["hi", "hey", "hi", "hi", "hello", "hey"])
Counter({'hi': 3, 'hey': 2, 'hello': 1})
Counter 생성자에 문자열을 인자로 넘기면 각 문자가 문자열에서 몇 번씩 나타나는지를 알려주는 객체가 반환됩니다.
>>> Counter("hello world")
Counter({'l': 3, 'o': 2, 'h': 1, 'e': 1, ' ': 1, 'w': 1, 'r': 1, 'd': 1})
파이썬 3.7부터는 Counter를 출력할 때 개수가 많은 순서대로 원소가 정렬되어 보입니다.
예전 버전에서는 삽입 순서대로 나왔기 때문에, 오래된 예제와 출력이 다르더라도 당황하지 않으셔도 됩니다.
Counter를 사전처럼 사용하기
collections 모듈의 Counter 클래스는 파이썬의 기본 자료구조인 사전(dictionary)을 확장하고 있기 때문에, 사전에서 제공하는 API를 그대로 다 사용할 수가 있습니다.
예를 들어, 대괄호를 이용하여 키로 값을 읽을 수 있고요.
counter = Counter("hello world")
counter["o"], counter["l"]
(2, 3)
특정 키에 해당하는 값을 갱신할 수도 있고요.
counter["l"] += 1
counter["h"] -= 1
counter
Counter({'l': 4, 'o': 2, 'e': 1, ' ': 1, 'w': 1, 'r': 1, 'd': 1, 'h': 0})
if 문에서 in 키워드를 이용하여 특정 키가 카운터에 존재하는지를 확인할 수 있습니다.
if "o" in counter:
print("o in counter")
del counter["o"]
if "o" not in counter:
print("o not in counter")
o in counter
o not in counter
사전으로 Counter 흉내하기
Counter를 사용하는 것은 쉽지만 Counter를 만드는 것은 그만큼 간단하지는 않습니다.
일반 사전을 이용하여 어떤 단어가 주어졌을 때 단어에 포함된 각 알파벳의 글자 수를 세어주는 함수를 작성해보겠습니다.
def countLetters(word):
counter = {}
for letter in word:
if letter not in counter:
counter[letter] = 0
counter[letter] += 1
return counter
countLetters('hello world')
{'h': 1, 'e': 1, 'l': 3, 'o': 2, ' ': 1, 'w': 1, 'r': 1, 'd': 1}
가장 흔한 데이터 찾기
아마도 실전에서 Counter가 자주 쓰이는 경우는 가장 많이 나온 데이터나 가장 적게 나온 데이터를 찾을 때일 텐데요.
Counter 클래스는 이와 같은 작업을 좀 더 쉽게 할 수 있도록, 데이터의 개수가 많은 순으로 정렬된 배열을 리턴하는 most_common()이라는 메서드를 제공하고 있습니다.
from collections import Counter
Counter('hello world').most_common()
[('l', 3), ('o', 2), ('h', 1), ('e', 1), (' ', 1), ('w', 1), ('r', 1), ('d', 1)]
이 메서드의 인자로 숫자 K를 넘기면 그 숫자 만큼만 리턴하기 때문에, 가장 개수가 많은 K개의 데이터를 얻을 수도 있습니다.
from collections import Counter
Counter('hello world').most_common(1)
[('l', 3)]
Counter의 most_common() 함수가 없었다면 가장 많이 나온 데이터를 구하려면 다음과 같은 함수를 직접 작성했어야겠죠? 😝
from collections import Counter
def find_max(word):
counter = Counter(word)
max_count = -1
for letter in counter:
if counter[letter] > max_count:
max_count = counter[letter]
max_letter = letter
return max_letter, max_count
find_max('hello world')
('l', 3)
산술 연산자 활용
Counter가 재밌는 부분은 바로 마치 숫자처럼 산술 연산자를 사용할 수 있다는 것인데요.
예를 들어, 아래와 같이 2개의 카운터 객체가 있을 때,
counter1 = Counter(["A", "A", "B"])
counter2 = Counter(["A", "B", "B"])
이 두 객체를 더할 수도 있고요.
counter1 + counter2
Counter({'A': 3, 'B': 3})
이 두 객체를 뺄 수도 있습니다.
counter1 - counter2
Counter({'A': 1})
뺄셈의 결과로 0이나 음수가 나온 경우에는 최종 카운터 객체에서 제외가 되니 이 부분 주의해서 사용하시길 바랍니다.
전체 개수 구하기
전체 데이터가 몇 개인지 세고 싶을 때는 파이썬 3.10부터 추가된 total() 메서드를 사용하면 편리합니다.
from collections import Counter
Counter("hello world").total()
11
예전에는 sum(counter.values())처럼 값들을 일일이 더해야 했는데, total() 메서드 덕분에 의도가 훨씬 명확하게 드러나죠.
전체 코드
본 포스팅에서 제가 작성한 전체 코드는 아래에서 직접 확인하고 실행해보실 수 있습니다.
마치며
이상으로 파이썬에서 제공하는 collections 모듈의 Counter 클래스에 대해서 간단히 살펴보았습니다.
같은 collections 모듈에는 없는 키에 기본값을 자동으로 채워주는 defaultdict도 있으니 함께 살펴보시면 데이터를 다룰 때 큰 도움이 됩니다.
좀 더 자세한 사항은 파이썬 공식 레퍼런스의 Counter 문서를 참고 바랍니다.
This work is licensed under CC BY 4.0