Vấn đề
Bạn cần xác định các mục xuất hiện nhiều nhất trong một chuỗi (sequence).
Giải pháp
Chúng ta có thể sử dụng Counter để theo dõi các mục trong một chuỗi.
Counter là gì?
Counter là một ánh xạ (mapping) chứa số nguyên đếm cho mỗi khóa. Cập nhật một khóa hiện có sẽ tăng đếm của nó. Đối tượng này được dùng để đếm các thể hiện của các đối tượng có thể hash (hashable objects) hoặc như một multiset.
Counter là một trong những "người bạn tốt nhất" của bạn khi thực hiện phân tích dữ liệu. Đối tượng này đã có mặt trong Python một thời gian khá dài, nên đối với nhiều bạn, đây sẽ là một ôn tập nhanh chóng. Chúng ta sẽ bắt đầu bằng cách import Counter từ collections.
from collections import Counter
Một từ điển truyền thống, nếu có khóa bị thiếu, sẽ ném ra KeyError. Từ điển Python sẽ trả về KeyError nếu khóa không tìm thấy.
# Một từ điển rỗng
dict = {}
# kiểm tra khóa trong từ điển rỗng
dict['mystring']
# Error message
# KeyError: 'mystring'
Làm thế nào để tránh ngoại lệ KeyError trong tình huống này?
Counter là một lớp con của từ điển và có hành vi rất giống từ điển, tuy nhiên, nếu bạn tra cứu một khóa bị thiếu, thay vì ném ra KeyError, nó chỉ trả về 0.
# định nghĩa counter c = Counter()
# kiểm tra khóa không có sẵn
print(f"Output\n{c['mystring']}")
0
c['mystring'] += 1
print(f"Output\n{c}")
Counter({'mystring': 1})
print(f"Output\n{type(c)}")
<class 'collections.Counter'>
Các mục xuất hiện nhiều nhất trong một chuỗi
Một trong những điều hay khác về Counter là bạn có thể đưa cho nó một danh sách các đối tượng và nó sẽ đếm chúng cho bạn. Nó giúp chúng ta tránh việc xây dựng vòng lặp để xây dựng counter.
Counter('Peas porridge hot peas porridge cold peas porridge in the pot nine days old'.split())
Counter({'Peas': 1, 'porridge': 3, 'hot': 1, 'peas': 2, 'cold': 1, 'in': 1, 'the': 1, 'pot': 1, 'nine': 1, 'days': 1, 'old': 1})
Phương thức split() sẽ lấy chuỗi và tách nó thành danh sách các từ. Nó tách trên khoảng trắng.
Counter sẽ lặp qua danh sách đó và đếm tất cả các từ, cho chúng ta số đếm như trong kết quả đầu ra.
Còn nhiều hơn nữa, tôi cũng có thể đếm các từ phổ biến nhất trong cụm từ. Phương thức most_common() sẽ cho chúng ta các mục xuất hiện thường xuyên.
count = Counter('Peas porridge hot peas porridge cold peas porridge in the pot nine days old'.split())
print(f"Output\n{count.most_common(1)}")
[('porridge', 3)]
Ví dụ
print(f"Output\n{count.most_common(2)}")
[('porridge', 3), ('peas', 2)]
Ví dụ
print(f"Output\n{count.most_common(3)}")
[('porridge', 3), ('peas', 2), ('Peas', 1)]
Lưu ý rằng nó trả về danh sách các tuple. Phần đầu của tuple là từ, phần thứ hai là số đếm của nó.
Một tính năng ít người biết của các thể hiện Counter là chúng có thể dễ dàng kết hợp bằng các phép toán toán học.
string = 'Peas porridge hot peas porridge cold peas porridge in the pot nine days old' another_string = 'Peas peas hot peas peas peas cold peas' a = Counter(string.split()) b = Counter(another_string.split())
# Cộng số đếm
add = a + b
print(f"Output\n{add}")
Counter({'peas': 7, 'porridge': 3, 'Peas': 2, 'hot': 2, 'cold': 2, 'in': 1, 'the': 1, 'pot': 1, 'nine': 1, 'days': 1, 'old': 1})
# Trừ số đếm
sub = a - b
print(f"Output\n{sub}")
Counter({'porridge': 3, 'in': 1, 'the': 1, 'pot': 1, 'nine': 1, 'days': 1, 'old': 1})
Cuối cùng, Counter rất thông minh trong cách nó lưu trữ dữ liệu trong container. Như bạn thấy ở trên, nó gom nhóm các từ lại khi lưu trữ, cho phép chúng ta lấy chúng cùng nhau - thường được gọi là multiset.
Chúng ta có thể lấy các từ một per một sử dụng elements(). Nó không nhớ thứ tự nhưng gom tất cả các từ trong một cụm từ lại với nhau.
Ví dụ
print(f"Output\n{list(a.elements())}")
['Peas', 'porridge', 'porridge', 'porridge', 'hot', 'peas', 'peas', 'cold', 'in', 'the', 'pot', 'nine', 'days', 'old']
Ví dụ
print(f"Output\n{list(a.values())}")
[1, 3, 1, 2, 1, 1, 1, 1, 1, 1, 1]
Ví dụ
print(f"Output\n{list(a.items())}")
[('Peas', 1), ('porridge', 3), ('hot', 1), ('peas', 2), ('cold', 1), ('in', 1), ('the', 1), ('pot', 1), ('nine', 1), ('days', 1), ('old', 1)]