Pythonには数千の外部ライブラリがありますが、その中で最も強力なツールがすでに標準ライブラリに含まれていることをご存知ですか?

このシリーズでは「Python標準ライブラリの深掘り」をテーマに、よく使われるが深く扱われていない標準ライブラリを一つずつ掘り下げていきます。

単なる関数の列挙ではなく、実践的な例を中心に概念を把握し、コードの応用力を高めることを目指し、皆さんのPython活用力を一段階向上させることが目標です。


collectionsの深掘り使用法:基本を超えて実践活用まで

1. なぜ collectionsから始めるのか

collectionsはPythonの組み込みデータ型(list, dict, tuple)を補完しながら、性能と構造の面で非常に効率的な高級コレクションを提供します。実務でよく見られますが、深く扱われることはあまりありません。

この記事では、その中で最も実用的な5つのクラスを中心に、「なぜ使うのか」、「どのように使うのか」、「いつ使うと良いのか」をお伝えします。


2. Counter – 頻度数えの正道、それ以上

Count all the things!

基本概念

collections.CounterはPythonの標準ライブラリcollectionsモジュールに含まれる非常に便利なクラスの一つです。文字通り「カウンター」で、データの出現回数(頻度)を数えるために最適化された特別な辞書と思ってください。

from collections import Counter

c = Counter(['a', 'b', 'c', 'a', 'b', 'a'])
print(c)  # Counter({'a': 3, 'b': 2, 'c': 1})

リスト、文字列、タプル、辞書などイテラブルオブジェクト(iterable)を入れると、それぞれの要素が何回出現したかを数えるデータ構造です。


主な機能とメソッド

📌 様々な初期化方式

Counterは様々な方法で初期化できるため、柔軟にデータを分析できます。

from collections import Counter

print(Counter(['a', 'b', 'a']))
# Counter({'a': 2, 'b': 1}) → リスト

print(Counter({'a': 2, 'b': 1}))
# Counter({'a': 2, 'b': 1}) → 辞書

print(Counter(a=2, b=1))
# Counter({'a': 2, 'b': 1}) → キーワード引数

📌 要素アクセス

Counterdictのように動作しますが、存在しないキーにアクセスするとKeyErrorの代わりに0が返されます。

c = Counter('hello')
print(c['l'])  # 2 ('l'という文字は2回出現)
print(c['x'])  # 0 ('x'は登場していないがエラーの代わりに0)

📌 要素追加/修正

既存の要素に値を追加したり、直接修正したりできます。存在しないキーも自動的に追加されます。

c = Counter('hello')
c['l'] += 3
print(c)
# Counter({'l': 5, 'o': 1, 'h': 1, 'e': 1})

📌 most_common(n) – よく出現する要素の抽出

出現頻度が高い順にn個の要素をタプルのリストとして返します。

c = Counter('banana')
print(c.most_common(2))
# [('a', 3), ('n', 2)] → 'a'は3回、'n'は2回出現

📌 elements() – 要素を反復するイテレーター

カウンターの値に基づいて、その要素を反復するイテレーターを提供します。

c = Counter('banana')
print(list(c.elements()))
# ['b', 'a', 'a', 'a', 'n', 'n']

ただし、値が0以下の要素は含まれません。


📌 数学演算サポート (Counter間の +, -, &, | 演算)

Counterは辞書よりも強力な点の一つは算術/集合演算をサポートしていることです。

c1 = Counter(a=3, b=1)
c2 = Counter(a=1, b=2)

print(c1 + c2)
# Counter({'a': 4, 'b': 3}) → 同じキーは合計される

print(c1 - c2)
# Counter({'a': 2}) → 負の数は無視され、'b'は負の数になるため省略される

print(c1 & c2)
# Counter({'a': 1, 'b': 1}) → 共通部分、最小値基準

print(c1 | c2)
# Counter({'a': 3, 'b': 2}) → 合併、最大値基準

実践活用例

📌 文字列単語分析
text = "the quick brown fox jumps over the lazy dog"
counter = Counter(text.split())
print(counter)
📌 ログ頻度分析
logs = ['INFO', 'ERROR', 'INFO', 'DEBUG', 'ERROR', 'ERROR']
print(Counter(logs))  # Counter({'ERROR': 3, 'INFO': 2, 'DEBUG': 1})
📌 リストの重複要素カウント
nums = [1, 2, 2, 3, 3, 3]
print(Counter(nums))  # Counter({3: 3, 2: 2, 1: 1})

注意点

  • Counterdictを継承していますがソートを保証しません。順序が必要な場合はmost_common()を活用するべきです。
  • 値が0以下になっても項目は削除されず、手動でフィルタリングする必要があるかもしれません。
c = Counter(a=3)
c.subtract({'a': 5})
print(c)  # Counter({'a': -2})  # 値が0以下になっても項目は消えないことに注意

ヒント: 初期化なしで累積する方法

counter = Counter()
with open("data.txt") as f:
    for line in f:
        counter.update(line.strip().split())

まとめ

collections.Counterはデータ分析、ログ処理、テキストマイニングなどでほぼ必須の強力なツールです。初心者には簡単な頻度数えツールとして、熟練者には演算とフィルタリングを組み合わせた高度な処理ツールとして進化できます。


次回予告

  • defaultdict – KeyErrorのない世界、dictより柔軟に!次回もお楽しみに!

標準ライブラリを「深く理解し、正しく使う」だけでも、皆さんのコードの品質は確実に変わるでしょう。