PythonのCounter・defaultdict入門!collectionsで集計とグループ分けを短く書く方法
「単語の出現回数を数えたいだけなのに、if key not in d: を毎回書くのが面倒…」
「カテゴリごとにデータをまとめるコードが、いつの間にか長くなってしまう…」
Pythonで集計のコードを書いていると、こんなモヤモヤを感じること、ありますよね。
そんなときに使えるのが、標準ライブラリの collectionsモジュール にある Counter と defaultdict です。インストール不要で、import するだけで使えます。
この記事は、for文と辞書(dict)の基本がわかるPython初心者〜初級者向けです。「普通の辞書で書いた場合」と比べながら、一緒に見ていきましょう!😊
Counterとdefaultdictってどんなもの?

ざっくり言うと、どちらも 「ちょっと便利になった辞書」 です。
- Counter:数を数える専用の辞書。リストを渡すだけで「何が何回出てきたか」を集計してくれる
- defaultdict:まだ無いキーにアクセスしたとき、自動で初期値を作ってくれる辞書
イメージとしては、Counterは「正の字を自動で書いてくれるメモ帳」、defaultdictは「新しい見出しを勝手に用意してくれるノート」です。
どちらも dict の仲間なので、[] でのアクセスや .items() など、いつもの辞書の書き方がそのまま使えます。
Counterで「何が何回出たか」を一発で数える
まずは、1週間に売れた果物の記録を数えてみます。普通の辞書で書いた場合と、Counterで書いた場合を並べました。
from collections import Counter
# 1週間分の「売れた果物」の記録
sales = ["りんご", "バナナ", "りんご", "みかん", "バナナ", "りんご",
"ぶどう", "みかん", "りんご", "バナナ"]
# --- 方法1: 普通の辞書で数える ---
counts = {}
for fruit in sales:
if fruit not in counts: # 初めて出てきたら0で初期化
counts[fruit] = 0
counts[fruit] += 1
print("辞書:", counts)
# --- 方法2: Counterで数える ---
c = Counter(sales)
print("Counter:", c)
# 多い順に上位2つ
print("TOP2:", c.most_common(2))
# 存在しないキーは 0 が返る(KeyErrorにならない)
print("メロン:", c["メロン"])

実行すると、上の画像のように表示されます。辞書版とCounter版で、集計結果はまったく同じですね。
ポイントをまとめるとこんな感じです👇
- 普通の辞書だと、初めて出たキーを0で初期化する処理が必要(これを忘れて
counts[fruit] += 1だけ書くとKeyErrorになります) - Counterなら
Counter(sales)の1行で集計完了 most_common(2)で多い順の上位2件が(値, 回数)のタプルのリストで取れる- 存在しないキー(メロン)を参照しても、エラーではなく 0 が返る
「ランキングを出したい」「一番多いものを知りたい」という場面では、most_common() がとにかく便利です。自分で sorted() と lambda を組み合わせて並べ替える必要がなくなります。
defaultdictで「グループ分け」と「合計」をスッキリ書く
次は、家計簿のような支出データをカテゴリごとにまとめる例です。
from collections import defaultdict
# (カテゴリ, 金額) の支出データ
expenses = [
("食費", 850), ("交通費", 420), ("食費", 1200),
("日用品", 380), ("交通費", 420), ("食費", 640),
]
# カテゴリごとに金額をリストでまとめる
by_category = defaultdict(list)
for category, amount in expenses:
by_category[category].append(amount) # 初期化なしでいきなりappendできる
# カテゴリごとの合計を集計
totals = defaultdict(int)
for category, amount in expenses:
totals[category] += amount # int() の初期値は 0
for category, amounts in by_category.items():
print(f"{category}: {amounts} 合計 {totals[category]}円")
# 普通の辞書に戻して表示
print(dict(totals))
実行結果です。
食費: [850, 1200, 640] 合計 2690円
交通費: [420, 420] 合計 840円
日用品: [380] 合計 380円
{'食費': 2690, '交通費': 840, '日用品': 380}
ここが重要です👇
defaultdict(list):無いキーにアクセスすると空のリスト[]が自動で用意される → いきなり.append()できるdefaultdict(int):無いキーの初期値はint()の結果、つまり 0 → いきなり+=できるdict(totals)で普通の辞書に戻せるので、JSONに保存したいときも安心
カッコの中に渡すのは「初期値を作る関数」です。list なら空リスト、int なら0、set なら空の集合が初期値になります。list() のようにカッコを付けて呼び出すのではなく、関数そのものを渡す点に注意してください。
⚠️ defaultdictは「見ただけ」でキーが増える
ひとつ、つまずきやすいポイントがあります。defaultdictは、値を読むだけのつもりでもキーが追加されてしまうんです。
実際に試したところ、totals = defaultdict(int) に「食費」だけを入れた状態で print(totals["娯楽費"]) を実行すると 0 が表示され、そのあと dict(totals) を見ると {'食費': 1, '娯楽費': 0} のように、「娯楽費」が0円で登録されていました。
一方、Counterは存在しないキーを c["z"] で参照しても0を返すだけで、キーは増えません("z" in c は False のまま)。
defaultdictで「キーがあるか確認したい」ときは、d[key] ではなく key in d や d.get(key) を使うのが安全です。
実践:アクセスログを集計してみよう
最後に、Counterとdefaultdictを1つのスクリプトで組み合わせてみます。簡単なアクセスログから「人気ページのランキング」と「ユーザーごとに何ページ見たか」を出してみましょう。
これ、実行する前に結果を予想できますか? 特に「sato は何ページ見た?」に注目してみてください。
from collections import Counter, defaultdict
# アクセスログ(時刻, ユーザー, ページ)
logs = """
09:01 sato /top
09:03 suzuki /top
09:05 sato /blog
09:10 tanaka /top
09:12 suzuki /blog
09:15 sato /contact
09:20 tanaka /blog
09:22 suzuki /top
""".strip().splitlines()
page_counter = Counter()
pages_by_user = defaultdict(set) # ユーザーごとに「見たページ」を重複なしで記録
for line in logs:
time, user, page = line.split()
page_counter[page] += 1
pages_by_user[user].add(page)
print("=== 人気ページ ===")
for page, n in page_counter.most_common():
print(f"{page:<9}{n}回")
print("=== ユーザー別 閲覧ページ数 ===")
for user, pages in sorted(pages_by_user.items()):
print(f"{user:<7}{len(pages)}ページ {sorted(pages)}")

実行結果は上の画像のとおりです。sato は3回アクセスして、3ページとも別のページだったので「3ページ」でした。
ポイントをまとめるとこんな感じです👇
Counter()は空で作って、page_counter[page] += 1のように1件ずつ足していく使い方もできるdefaultdict(set)にすると、ユーザーごとに重複なしでページを記録できる(suzukiは /top を2回見ていますが、2ページと数えられています)most_common()に数を指定しなければ、全件を多い順に返してくれる
このパターンは、CSVの集計やセンサーログの分析など、いろいろな場面にそのまま応用できます。
普通の辞書・Counter・defaultdictの使い分け
| やりたいこと | おすすめ |
|---|---|
| 出現回数を数える・ランキングを出す | Counter |
| キーごとにリストや集合にまとめる | defaultdict(list) / defaultdict(set) |
| キーごとに金額などを合計する | defaultdict(int)(Counterでも可) |
| キーが決まっている設定値などを持つ | 普通の辞書 |
より詳しい仕様は、Python公式ドキュメントの collections — コンテナデータ型 で確認できます。
まとめ
- Counter はリストを渡すだけで回数を集計でき、
most_common()でランキングも一発 - defaultdict は無いキーの初期値を自動で作るので、
if key not in d:が不要になる - defaultdictは参照しただけでキーが増えるので、存在チェックには
inやget()を使う - どちらも標準ライブラリなので、
from collections import Counter, defaultdictですぐ使える
「集計のコードって長くなりがち…」と感じていた方も、この2つを覚えるだけでグッと短く、読みやすく書けるようになるはずです。
手元にあるデータで、ぜひ試してみてください🚀
こちらも読まれています
📚 関連商品・おすすめ書籍
※本記事にはアフィリエイトリンクが含まれます。






