結論から言うと、collections はリストや辞書を使った処理を、より書きやすくするための標準ライブラリです。
Pythonでは、データを数えたり、種類ごとにまとめたりする処理をよく書きます。
通常の辞書でも実現できますが、毎回初期値を確認するコードが増えると、本当にやりたい処理が見えにくくなることがあります。
この記事では、注文データを集計する例を使って、Counter と defaultdict の基本を整理します。
この記事でわかること
完成コード
完成コードは次の通りです。
from collections import Counter, defaultdict
orders = [
{"customer": "田中", "category": "文具", "amount": 1200},
{"customer": "佐藤", "category": "食品", "amount": 2500},
{"customer": "田中", "category": "文具", "amount": 800},
{"customer": "鈴木", "category": "食品", "amount": 1500},
{"customer": "佐藤", "category": "書籍", "amount": 3000},
]
def count_by_category(items: list[dict[str, object]]) -> Counter[str]:
return Counter(str(item["category"]) for item in items)
def group_amounts_by_customer(items: list[dict[str, object]]) -> dict[str, list[int]]:
grouped: defaultdict[str, list[int]] = defaultdict(list)
for item in items:
customer = str(item["customer"])
amount = int(item["amount"])
grouped[customer].append(amount)
return dict(grouped)
category_counts = count_by_category(orders)
amounts_by_customer = group_amounts_by_customer(orders)
print("カテゴリ別件数")
for category, count in category_counts.most_common():
print(f"{category}: {count}件")
print("顧客別金額")
for customer, amounts in amounts_by_customer.items():
print(f"{customer}: 合計{sum(amounts)}円")このコードを実行すると、カテゴリ別の注文件数と、顧客別の注文金額合計を表示します。
コードのポイント
このコードでは、注文データの集計に Counter と defaultdict を使っています。
Counterでカテゴリごとの件数を数えていますmost_common()で件数が多い順に取り出していますdefaultdict(list)で顧客ごとの金額リストを作っています- キーが初めて出てきたときの初期化処理を書かずに済んでいます
- 最後に通常の
dictに変換して返しています
collections は特別なことをするためだけのライブラリではありません。
よくあるデータ処理を、読みやすく短く書くために使える道具です。
コードを順番に説明します
主要な処理を分けて説明します。
1. Counterで件数を数えます
def count_by_category(items: list[dict[str, object]]) -> Counter[str]:
return Counter(str(item["category"]) for item in items)Counter は、同じ値が何回出てきたかを数えるためのクラスです。
ここでは、注文データから category を取り出し、カテゴリごとの件数を数えています。
通常の辞書で書く場合は、キーがあるかどうかを確認してから数を増やす必要があります。Counter を使うと、その部分を短く書けます。
2. most_commonで多い順に取り出します
for category, count in category_counts.most_common():
print(f"{category}: {count}件")most_common() は、件数が多い順に結果を返します。
集計結果をレポートとして表示したい場合に便利です。
上位3件だけ見たい場合は、category_counts.most_common(3) のように数を指定できます。
アクセスログやアンケート結果のように、よく出る値を確認したいときにも使えます。
3. defaultdictでグループ分けします
grouped: defaultdict[str, list[int]] = defaultdict(list)
for item in items:
customer = str(item["customer"])
amount = int(item["amount"])
grouped[customer].append(amount)defaultdict(list) は、まだ存在しないキーにアクセスしたとき、自動で空のリストを用意します。
そのため、grouped[customer].append(amount) とそのまま書けます。
通常の辞書で同じことをする場合、キーがなければ空リストを作る処理が必要です。defaultdict を使うと、グループ分けの本筋だけを書きやすくなります。
4. 通常のdictに戻して返します
return dict(grouped)defaultdict は辞書のように使えますが、戻り値として外へ渡すときは通常の dict に変換することがあります。
そのほうが、呼び出し側が特別な初期値の動きを意識しなくて済みます。
関数の中では defaultdict を使って処理を簡単にし、外へ返すときは普通の辞書にする、という使い方は実務でも扱いやすい形です。
実務で使うときのポイント
実務では、collections はログ集計、注文集計、アンケート結果、ファイル種別の集計などで役立ちます。
特に、同じ値を数えるなら Counter、キーごとにリストへまとめるなら defaultdict(list) が使いやすいです。
ただし、便利だからといって何でも collections に寄せる必要はありません。
単純な辞書で十分に読みやすい処理なら、そのままでも問題ありません。
初期化処理や集計処理が増えて読みにくくなったときに、Counter や defaultdict を選ぶと効果が分かりやすいです。
第3章で扱ったCSV読み込みと組み合わせると、ファイルから読んだデータを集計できます。
第6章の標準ライブラリを組み合わせていくと、外部ライブラリなしでも小さな業務集計ツールを作れるようになります。