1. Counter 是什麼?
Counter 是 Python collections 模組提供的計數工具,主要用途是統計:
- 字串中每個字元出現幾次;
- 清單中每個元素出現幾次;
- 不同類別的資料筆數;
- 狀態、錯誤類型、FTP 類型的分布;
- 多組資料的計數合併與比較。
它本質上是一個「元素 → 次數」的字典。
# %%
from collections import Counter
counter = Counter(["apple", "banana", "apple"])
print(counter)輸出:
2. 建立 Counter
2.1 從 list 建立
from collections import Counter
items = ["active", "bypassed", "active", "unknown"]
status_counter = Counter(items)
print(status_counter)輸出:
2.2 從字串建立
char_counter = Counter("banana")
print(char_counter)字串會被視為一個可迭代物件,因此會逐字元統計。
2.3 從字典建立
counter = Counter({
"active": 10,
"bypassed": 4,
})
print(counter)2.4 建立空的 Counter
counter = Counter()
counter["active"] += 1
counter["bypassed"] += 1
print(counter)輸出:
這比一般字典方便,因為不存在的 key 預設次數是 0。
一般字典則會發生 KeyError:
3. 增加計數
3.1 使用 update
counter = Counter()
counter.update(["active", "active", "bypassed"])
print(counter)也可以分批增加:
3.2 直接使用索引累加
counter = Counter()
counter["active"] += 1
counter["active"] += 1
counter["bypassed"] += 1
print(counter)3.3 從另一個 Counter 增加
counter_a = Counter(active=3, bypassed=1)
counter_b = Counter(active=2, unknown=4)
counter_a.update(counter_b)
print(counter_a)4. 取得計數
4.1 取得特定元素次數
counter = Counter(["active", "active", "bypassed"])
print(counter["active"])
print(counter["bypassed"])
print(counter["missing"])4.2 使用 get
Counter 通常不需要特別使用 get,
因為不存在的 key 已經會回傳 0。
但若要明確表達預設值,仍可使用。
4.3 取得所有元素
假設:
counter = Counter(active=2, bypassed=1)elements() 會依次數展開元素。
注意:次數為零或負數的項目不會被 elements() 輸出。
5. 取得最多項目
5.1 使用 most_common
counter = Counter({
"active": 12,
"bypassed": 5,
"unknown": 2,
})
print(counter.most_common())5.2 只取得前幾名
這適合用於:
- 最常見的錯誤類型;
- 出現次數最多的 Class Name;
- 最常見的 Family;
- 最常見的 FTP 類型。
6. 轉換成一般字典
counter = Counter(active=3, bypassed=1)
data = dict(counter)
print(data)輸出 JSON 時通常也可以直接使用:
import json
json_text = json.dumps(counter, ensure_ascii=False)但建議轉成一般字典,讓資料結構更明確:
json_text = json.dumps(
dict(counter),
ensure_ascii=False,
indent=2,
)7. 計數排序
most_common() 會由大到小排序。
如果要由小到大排序:
counter = Counter(active=10, bypassed=3, unknown=1)
ascending = sorted(
counter.items(),
key=lambda item: item[1],
)
print(ascending)如果要依名稱排序:
by_name = sorted(counter.items())
print(by_name)sorted(counter.items()) vs sorted(counter)
8. Counter 的加減
8.1 Counter 相加
counter_a = Counter(active=3, bypassed=1)
counter_b = Counter(active=2, unknown=4)
result = counter_a + counter_b
print(result)8.2 Counter 相減
counter_a = Counter(active=5, bypassed=3)
counter_b = Counter(active=2, bypassed=1)
result = counter_a - counter_b
print(result)要注意,使用 - 時,結果中的零與負數通常會被移除。
8.3 保留負數
如果需要保留負數,使用 subtract:
counter_a = Counter(active=2)
counter_b = Counter(active=5)
counter_a.subtract(counter_b)
print(counter_a)9. Counter 的集合運算
9.1 取最大值:|
counter_a = Counter(active=5, bypassed=2)
counter_b = Counter(active=3, unknown=4)
result = counter_a | counter_b
print(result)每個 key 取兩邊較大的次數:
9.2 取最小值:&
每個 key 取兩邊較小的次數:
Counter 與 defaultdict 的差異
Counter
適合:
# 只需要統計每個 key 出現幾次
counter = Counter()
counter["active"] += 1defaultdict
適合:
# 每個 key 需要保存一組複雜資料
from collections import defaultdict
data = defaultdict(list)
data["active"].append(node)簡單比較:
如果需要同時保存數量與明細,可以同時使用:
from collections import Counter, defaultdict
counts = Counter()
details = defaultdict(list)
for node in nodes:
reason = node["invalid_reason"]
counts[reason] += 1
details[reason].append(node)12. 常見陷阱
12.1 Counter 不會自動刪除零值
如需移除零值:
counter += Counter()
# 或
counter = Counter({
key: value
for key, value in counter.items()
if value > 0
})不要把 len(counter) 當成總筆數
這代表不同元素種類數,不是總筆數。
總筆數應使用:
若 Python 版本不支援 total(),可使用:
Counter 的 key 必須可雜湊
以下可以作為 key:
"active"
123
("FamilyA", "MP")以下通常不行:
["active"]
{"status": "active"}因為 list 與 dict 不可作為字典 key。
總結
Counter 最適合解決「某些資料各出現幾次」的問題。
最重要的使用原則是:
Counter 用來保存數量,
dict / defaultdict 用來保存明細。
兩者搭配使用,就能同時支援統計、報表、追蹤與下游查詢。 推薦hahow線上學習python: https://igrape.net/30afN