【Python】collections.Counterで要素の出現回数を数える

Python

こんにちは、かつコーチです。

「リストの中で、どの要素が何回出てきたか数えたい」

そんなとき、通常の辞書を使って自力でカウント処理を書いた経験はありませんか。

実はcollections.Counterを使えば、その処理をたった1行で済ませられます。

この記事では、Counterの基本からmost_common()での頻出要素取得、通常の辞書での実装との比較まで解説します。

読み終える頃には、集計処理を驚くほどシンプルに書けるようになります。

Counterの基本の使い方

Counterとは何か

Counterは、collectionsモジュールに含まれる、要素の出現回数を数えるための専用クラスです。

リストやタプル、文字列などを渡すだけで、それぞれの要素が何回出現したかを自動で集計してくれます。

from collections import Counter

fruits = ["りんご", "バナナ", "りんご", "みかん", "バナナ", "りんご"]
counter = Counter(fruits)

print(counter)

実行結果は次の通りです。

Counter({'りんご': 3, 'バナナ': 2, 'みかん': 1})

Counterは辞書(dict)を継承したクラスなので、辞書と同じように扱えます。

from collections import Counter

fruits = ["りんご", "バナナ", "りんご", "みかん", "バナナ", "りんご"]
counter = Counter(fruits)

print(counter["りんご"])
print(counter["メロン"])

実行結果は次の通りです。

3
0

通常の辞書であれば存在しないキーにアクセスするとKeyErrorが発生しますが、Counterは存在しないキーに対して自動で0を返してくれます。

most_common()で頻出要素を取得する

most_common()メソッドを使うと、出現回数が多い順に要素を取り出せます。

from collections import Counter

fruits = ["りんご", "バナナ", "りんご", "みかん", "バナナ", "りんご"]
counter = Counter(fruits)

print(counter.most_common())

実行結果は次の通りです。

[('りんご', 3), ('バナナ', 2), ('みかん', 1)]

引数に数値を渡すと、上位いくつまでを取得するかを指定できます。

from collections import Counter

fruits = ["りんご", "バナナ", "りんご", "みかん", "バナナ", "りんご"]
counter = Counter(fruits)

top2 = counter.most_common(2)
print(top2)

実行結果は次の通りです。

[('りんご', 3), ('バナナ', 2)]

アクセスログの集計や、アンケート結果の集計など「上位N件を知りたい」場面で頻繁に使うメソッドです。

通常の辞書での実装との比較

Counterを使わずに同じ集計処理を書くと、次のようになります。

fruits = ["りんご", "バナナ", "りんご", "みかん", "バナナ", "りんご"]
count_dict = {}

for fruit in fruits:
    if fruit in count_dict:
        count_dict[fruit] += 1
    else:
        count_dict[fruit] = 1

print(count_dict)

実行結果は次の通りです。

{'りんご': 3, 'バナナ': 2, 'みかん': 1}

結果は同じですが、if文でキーの存在をチェックする分、コードが長くなります。

Counterを使えば、この処理がCounter(fruits)の1行で完結します。

よくあるつまずきポイント・エラー対処

Counterの中身をそのまま辞書として更新しようとしてハマる

これは筆者がログ集計スクリプトを書いていたときに実際にハマったつまずきです。

Counterは辞書のように扱えるとはいえ、要素を加算していく際に通常の辞書と同じ書き方をすると、思わぬ挙動になることがあります。

❌ Before(存在しないキーの加算でエラーになると思い込んでいた書き方)

from collections import Counter

counter = Counter()
words = ["apple", "banana", "apple", "apple"]

for word in words:
    if word not in counter:
        counter[word] = 0
    counter[word] += 1

print(counter)

このコードは一応動きますが、Counterが本来持っている「存在しないキーは自動で0扱い」という機能を知らずに、わざわざ存在チェックを書いてしまっています。

筆者は最初、Counterも通常の辞書と同様にKeyErrorが出ると思い込み、余計なif文を書いていました。

✅ After(Counterの機能を活かした書き方)

from collections import Counter

counter = Counter()
words = ["apple", "banana", "apple", "apple"]

for word in words:
    counter[word] += 1

print(counter)

実行結果は次の通りです。

Counter({'apple': 3, 'banana': 1})

Counterは存在しないキーへのアクセスを自動で0として扱ってくれるため、存在チェックのif文は不要です。

さらに言えば、リストをそのまま渡せる場面ならCounter(words)の1行で済ませられます。

まとめ

この記事のポイント

  • Counterは要素の出現回数を自動で集計してくれる専用クラス
  • 存在しないキーにアクセスしてもKeyErrorにならず0が返る
  • most_common()で出現回数が多い順に要素を取得できる
  • most_common(N)で上位N件だけを取得できる
  • 通常の辞書で同じ処理を書くより、Counterの方が圧倒的にシンプル

次に読むべき記事

  • collections.defaultdictで初期値付き辞書を扱う
  • 辞書内包表記・セット内包表記の書き方
  • zip()で複数のリストをまとめて処理する

タグ: Python, 中級者向け, 標準ライブラリ

タイトルとURLをコピーしました