Python: サクッとカウンタを実装する (collections.Counter)

文字列のリストから単語の出現頻度をカウントする、といったケースはしばしばあるかと思います。

dictやdefaultdictで実装すると初期値0の設定が必要だったりしてちょっとめんどくさいです。

words = ["dog", "cat", "dog", "dog", "mouse", "cat"]

# dictの場合
counter = {}
for w in words:
    if w in counter:
        counter[w] += 1
    else:
        counter[w] = 1

# defaultdictの場合
from collections import defaultdict

counter = defaultdict(lambda: 0)
for w in words:
    counter[w] += 1

collections.Counterを使うとワンラインでカウントできます。

counter = Counter(words)

print(counter)
# Counter({'dog': 3, 'cat': 2, 'mouse': 1})

引数無しでもCounterオブジェクトを生成できます。dict同様にキーでアクセスでき、初期値0としてカウントアップできます。

counter = Counter()

for w in words:
    if w == "dog":
        counter["dog"] += 1
    else:
        counter["others"] += 1

print(counter)
# Counter({'dog': 3, 'others': 3})

無い要素にアクセスした場合は0が返ります。

print(counter["rabbit"])  # 0

文字列だけではなく数値やタプルもキーにできます。

counter = Counter([1, 2, 1, 3, 4, 1])
print(counter)
# Counter({1: 3, 2: 1, 3: 1, 4: 1})

counter = Counter([(1, 2), (1, 3), (1, 2), (2, 4)])
print(counter)
# Counter({(1, 2): 2, (1, 3): 1, (2, 4): 1})

Counterオブジェクト同士の加算・減算もできます。"-"オペレータではゼロや負値になりませんが、subtractメソッドを使うとゼロや負になりえます。

counter_plus = counter1 + counter2
print(counter_plus)
# Counter({'dog': 4, 'cat': 2, 'mouse': 1})

counter_minus = counter1 - counter2
print(counter_minus)
# Counter({'dog': 2})

counter1.subtract(counter2)
print(counter1)
# Counter({'dog': 2, 'cat': 0, 'mouse': -1})

dict型への変換も組み込み関数dictでできます。

counter = Counter(words)

counter_dict = dict(counter)

print(type(counter_dict))  # <class 'dict'>
print(counter_dict)
# {'dog': 3, 'cat': 2, 'mouse': 1}

ちょっとした実装で役立ちそうなクラスを紹介しました。