쿼카러버의 기술 블로그
[Python Advanced] Collections 라이브러리 1탄 : Counter (Pythonic하게 Count하는 법) 본문
[Python Advanced] Collections 라이브러리 1탄 : Counter (Pythonic하게 Count하는 법)
quokkalover 2022. 1. 20. 00:15Python의 가장 큰 장점은 다양한 라이브러리를 사용할 수 있다는 점이다. 이들을 좀 활용해보고 정리하는 차원에서 앞으로 Python Advanced시리즈를 써보려고 한다.
우선 Collections, Itertools, Lambda 등 여러가지 라이브러리들에 대해 집중 탐구해보려고 한다.
일단 첫 시작은 Collection 모듈이다.
Collections모듈은 dict, list, set, tuple과 같은 일반적으로 사용되는 built-in container를 약간 변형해서 대체해주는 특별한 container들을 제공한다.
예:
1) Counter
2) NamedTuple,
3) orderedDict,
4) Default Dict
본 글에서는 Counter
에 집중한다.
Counter
Counter는 key로 string, list와 같은 built-in container내의 아이템들을 key로, 아이템의 갯수를 value로 바꾸어 dictionary자료형에 담아주는 container다. 이렇게 말로쓰면 어려운데(나는 어려움. 독자는 아닐수도) 아래 예시를 보면 아마 5초만에 이해할 수 있을 것이다. 참고 읽어보기를 바란다.
기능
1) string, list같은 container내의 각 unique한 element들의 갯수를 파악할 수 있다.
2) Counter는 Counter끼리의 addition, subtraction, intersection, union같은 Arithmetic operation을 매우 쉽게 할 수 있도록 해준다.
용도
1) Text File 내의 단어 갯수 찾기
2) Matplotlib을 활용해서 Categorical Data 차트 그리기
3) Sample의 mode(=통계에서의 mode the most frequent value)찾기
예시
글로 설명하면 복잡하고 예시로 설명하겠다.
from collections import Counter
a = "bbbcccdfffrrr"
counter_example = Counter(a)
print(counter_example)
>>> Counter({'b': 3, 'c': 3, 'f': 3, 'r': 3, 'd': 1})
위 예시에서 보이듯이, string내 각 문자들(b, c, d, f, r)의 갯수를 새서, 각 문자를 key로 그리고, string내 각 문자들의 갯수를 value로 담고 있다.
이제 이 Counter내의 값들을 dict로 변형하면 (물론 counter자료형의 내장 함수들도 있는데, 편의상 dict로 변형해서 사용한다.)
dict_counter = dict(my_counter)
print(dict_counter)
이제 dict와 똑같이 아래 연산들을 실행해볼 수 있다.
print(dict_counter)
print(dict_counter.keys())
print(dict_counter.values())
#>>> {'b': 3, 'c': 3, 'd': 1, 'f': 3, 'r': 3}
#>>> dict_keys(['b', 'c', 'd', 'f', 'r'])
#>>> dict_values([3, 3, 1, 3, 3])
string뿐만 아니라 list도 가능하다.
my_list = ["asd", "as", "as", "cds", "cds", "bbc", "bbc", "bbc"]
counter_example = Counter(my_list)
print(counter_example)
#>>> Counter({'bbc': 3, 'as': 2, 'cds': 2, 'asd': 1})
dict_counter = dict(counter_example)
print(dict_counter)
print(dict_counter.keys())
print(dict_counter.values())
#>>> {'asd': 1, 'as': 2, 'cds': 2, 'bbc': 3}
#>>> dict_keys(['asd', 'as', 'cds', 'bbc'])
#>>> dict_values([1, 2, 2, 3])
기본적인 Counter 사용법은 위와 같고 이제 아까 말했던 Arithmetic Operation에서의 활용사례를 한번 살펴보자.
Addtion of two Counters
각 Coutner내의 key들의 갯수끼리의 덧셈을 구해줌. 하나의 Counter에만 있어도, 더해줌.
from collections import Counter
c1 = Counter('aabvbdfmfmfdds')
c2 = Counter('serosdkfgdfglsl')
print("c1:", c1)
print("c2:", c2)
print("c1 + c2 :", c1 + c2)
#>>> c1: Counter({'d': 3, 'f': 3, 'a': 2, 'b': 2, 'm': 2, 'v': 1, 's': 1})
#>>> c2: Counter({'s': 3, 'd': 2, 'f': 2, 'g': 2, 'l': 2, 'e': 1, 'r': 1, 'o': 1, 'k': 1})
#>>> c1 + c2 : Counter({'d': 5, 'f': 5, 's': 4, 'a': 2, 'b': 2, 'm': 2, 'g': 2, 'l': 2, 'v': 1, 'e': 1, 'r': 1, 'o': 1, 'k': 1})
Subtraction of two Counters
각 Counter내의 key들의 갯수의 차를 구해줌 (positive count만 남음) 장바구니로 만들고, 한번에 장바구니의 차를 뺄 수도 있음.
from collections import Counter
t1 = Counter('aabbddffggjik')
t2 = Counter('aaabbbssshhhggdkkll')
print("t1:", t1)
print("t2:", t2)
print("t1-t2 :", t1-t2)
print("t2-t1 :", t2-t1)
>>> t1: Counter({'a': 2, 'b': 2, 'd': 2, 'f': 2, 'g': 2, 'j': 1, 'i': 1, 'k': 1})
>>> t2: Counter({'a': 3, 'b': 3, 's': 3, 'h': 3, 'g': 2, 'k': 2, 'l': 2, 'd': 1})
>>> t1-t2 : Counter({'f': 2, 'd': 1, 'j': 1, 'i': 1})
>>> t2-t1 : Counter({'s': 3, 'h': 3, 'l': 2, 'a': 1, 'b': 1, 'k': 1})
Intersections(&) of two Counters
각 counter에서 겹치는 element 갯수의 최소값을 리턴한다 min(t1[x], t2[x]):
from collections import Counter
t1 = Counter('aaabbbbccdeeee')
t2 = Counter('aabbccccdddee')
print("t1 :", t1)
print("t2 :", t2)
print("t1&t2 :", t1&t2)
#>>> t1 : Counter({'e': 4, 'b': 4, 'a': 3, 'c': 2, 'd': 1})
#>>> t2 : Counter({'c': 4, 'd': 3, 'a': 2, 'e': 2, 'b': 2})
#>>> t1&t2 : Counter({'c': 2, 'a': 2, 'e': 2, 'b': 2, 'd': 1})
Union(|) of two Counters
각 counter내의 key들의 갯수의 최대값을 리턴
한 Counter에만 있는 key는 같이 포함됨
from collections import Counter
t1 = Counter('aaabbbbccdeeeef')
t2 = Counter('aabbccccdddee')
print("t1 :", t1)
print("t2 :", t2)
print("t1|t2 :", t1|t2)
>>> t1 : Counter({'b': 4, 'e': 4, 'a': 3, 'c': 2, 'd': 1, 'f': 1})
>>> t2 : Counter({'c': 4, 'd': 3, 'a': 2, 'b': 2, 'e': 2})
>>> t1|t2 : Counter({'b': 4, 'c': 4, 'e': 4, 'a': 3, 'd': 3, 'f': 1})
Counter를 활용하여 Multiset과 set으로의 기능 동시에 활용
Python의 set은 중복된값을 허용하지 않는다. 하지만 아래처럼 Counter를 활용하면 여러개의 값을 허용하는 Multiset과 set을 동시에 만들 수 있다.
from collections import Counter
# A Python multiset
multiset = Counter([1, 1, 2, 3, 3, 3, 4, 4])
multiset
#>>>Counter({3: 3, 1: 2, 4: 2, 2: 1})
# The keys are equivalent to a set
multiset.keys() == {1, 2, 3, 4}
#>>>True
위 기능은 쇼핑카트 같은데 사용할 수 있는데, 하나의 상품을 여러개 담도록 하고 각 가격을에 대해 가격을 적용하고 계산하고싶을 때 아래 예시처럼 활용해볼 수 있겠다.
from collections import Counter
prices = {"course": 97.99, "book": 54.99, "wallpaper": 4.99}
cart = Counter(course=1, book=3, wallpaper=2)
for product, units in cart.items():
subtotal = units * prices[product]
price = prices[product]
print(f"{product:9}: ${price:7.2f} × {units} = ${subtotal:7.2f}")
#>>> course : $ 97.99 × 1 = $ 97.99
#>>> book : $ 54.99 × 3 = $ 164.97
#>>> wallpaper: $ 4.99 × 2 = $ 9.98
다양한 활용 기타 예시
import math
from collections import Counter
prime_factors = Counter({2: 2, 3: 3, 17: 1})
math.prod(prime_factors.elements())
#>>> 1836
from collections import Counter
"".join(Counter("mississippi").elements())
#>>> 'miiiisssspp'
unary operation
from collections import Counter
counter = Counter(a=2, b=-4, c=0)
+counter
#> Counter({'a': 2})
-counter
#> Counter({'b': 4})
참고자료 :
https://www.guru99.com/python-counter-collections-example.html
https://www.python-engineer.com/courses/advancedpython/06-collections/
https://www.geeksforgeeks.org/operations-on-python-counter/
'[Python]' 카테고리의 다른 글
[Flask] Flask의 context 간단 정리 (application context, request context) (4) | 2022.01.31 |
---|---|
[python] anaconda 가상환경 만들 때 주의사항 (0) | 2022.01.27 |
파이썬으로 이런것도 가능해?(cross-platform, shell script, 리액트 개발) (pyodide, shellpy, kivy, pythonfire) (0) | 2022.01.01 |
이스케이프 문자 \r 과 \n은 무엇일까? (2) | 2019.01.28 |
파이썬으로 이메일 보내는 방법 (텍스트 작성) [SMTP] (1/2) (0) | 2019.01.03 |