Pythonでリストの連続する同じ要素をグループ化する方法:itertools.groupbyを徹底解説
Pythonでデータを扱う際、リスト内で連続して出現する同じ値の要素を一つのグループとしてまとめたい、というニーズはよくあります。例えば、ログデータから連続するエラーメッセージを抽出したり、時系列データから同じ状態が続く期間を特定したりする際に役立ちます。この記事では、このような「グループ化」を効率的に行うための、Pythonの**itertools.groupby**関数について、短いサンプルコードとともに詳しく解説します。
なぜ連続する要素のグループ化が必要なのか?
連続する要素のグループ化は、データの集計、分析、可視化の前処理として非常に重要です。
-
ログ分析: 連続して発生した同じエラーコードをグループ化し、エラーの発生頻度や継続時間を分析する。
-
イベントシーケンス: ユーザーのアクションログで、同じ操作が連続して行われた回数をカウントする。
-
データ圧縮: 連続する同じデータをまとめることで、データの表現を簡潔にする。
このような場面でitertools.groupbyがその真価を発揮します。
itertools.groupbyとは?
itertoolsモジュールは、効率的なイテレータを作成するための関数群を提供するPythonの標準ライブラリです。その中でもgroupbyは、連続する同じキーを持つ要素をグループ化する機能を提供します。
groupbyの基本的な使い方
groupbyは2つの引数を取ります。
-
イテラブル (iterable): グループ化したいデータ(リストなど)。
-
キー関数 (key function, オプション): 要素をグループ化するための基準となる値を返す関数。指定しない場合、要素そのものがキーとなります。
groupbyは、(キー, グループ)のペアを順に返すイテレータを生成します。各グループもまたイテレータであり、そのグループに属する要素を順に取得できます。
from itertools import groupby
data = [1, 1, 2, 2, 2, 3, 3, 1]
# キー関数を指定しない場合(要素そのものがキー)
for key, group in groupby(data):
print(f"キー: {key}, グループ: {list(group)}")
# 出力:
# キー: 1, グループ: [1, 1]
# キー: 2, グループ: [2, 2, 2]
# キー: 3, グループ: [3, 3]
# キー: 1, グループ: [1]
groupbyの重要なポイント
-
「連続する」要素:
groupbyは、リスト全体で同じ要素を探すのではなく、隣接する同じ要素をグループ化します。上記の例で、最後の1が最初の1, 1とは別のグループになっているのはそのためです。グループ化を行う前にリストをソートすると、全ての同じ要素が隣接するため、意図した通りのグループ化ができます。 -
グループはイテレータ:
groupオブジェクトは一度しかイテレートできません。list(group)のようにして内容を取り出すと、その後に再度イテレートすることはできません。
応用例:様々なデータのグループ化
1. 文字列の連続する文字をグループ化
文字列もイテラブルなので、groupbyを適用できます。
from itertools import groupby
text = "AAABBCcDDEEE"
for char, group in groupby(text):
print(f"文字: {char}, 連続回数: {len(list(group))}")
# 出力:
# 文字: A, 連続回数: 3
# 文字: B, 連続回数: 2
# 文字: C, 連続回数: 1
# 文字: c, 連続回数: 1 # 大文字と小文字は区別される
# 文字: D, 連続回数: 2
# 文字: E, 連続回数: 3
もし大文字・小文字を区別せずにグループ化したい場合は、キー関数を使います。
from itertools import groupby
text = "AAABBCcDDEEE"
# キー関数で小文字に変換
for char_key, group in groupby(text, key=str.lower):
print(f"キー: {char_key}, グループ: {list(group)}")
# 出力:
# キー: a, グループ: ['A', 'A', 'A']
# キー: b, グループ: ['B', 'B']
# キー: c, グループ: ['C', 'c']
# キー: d, グループ: ['D', 'D']
# キー: e, グループ: ['E', 'E', 'E']
2. オブジェクトの特定の属性でグループ化
リストが辞書やカスタムオブジェクトのインスタンスの場合、特定のキーや属性でグループ化できます。
from itertools import groupby
products = [
{"name": "Apple", "category": "Fruit"},
{"name": "Orange", "category": "Fruit"},
{"name": "Carrot", "category": "Vegetable"},
{"name": "Banana", "category": "Fruit"}, # ここでカテゴリが変わるため、'Fruit'が再度出現
{"name": "Potato", "category": "Vegetable"},
]
# グループ化する前に、キーとなるカテゴリでソートする
products.sort(key=lambda x: x["category"])
# products: [{'name': 'Apple', 'category': 'Fruit'}, {'name': 'Orange', 'category': 'Fruit'}, {'name': 'Banana', 'category': 'Fruit'}, {'name': 'Carrot', 'category': 'Vegetable'}, {'name': 'Potato', 'category': 'Vegetable'}]
for category, group in groupby(products, key=lambda x: x["category"]):
print(f"カテゴリ: {category}")
for product in group:
print(f" - {product['name']}")
# 出力:
# カテゴリ: Fruit
# - Apple
# - Orange
# - Banana
# カテゴリ: Vegetable
# - Carrot
# - Potato
重要: groupbyは連続するキーをグループ化するため、オブジェクトの属性でグループ化する際は、事前にその属性でソートしておくことがほぼ必須です。
まとめ
itertools.groupbyは、Pythonでリストの連続する同じ値の要素を効率的にグループ化するための非常に強力なツールです。
-
基本的な使い方:
groupby(iterable, key=key_function)で(キー, グループ)のイテレータを取得。 -
「連続する」に注意: 隣接する要素のみをグループ化するため、必要に応じて事前にソートを行う。
-
グループはイテレータ: グループの内容を処理する際は、一度だけイテレートできる点に注意。
この関数を使いこなすことで、ログ解析、データ集計、特定のパターン検出など、様々なデータ処理タスクをより簡潔かつ効率的に記述できるようになるでしょう。
■プロンプトだけでオリジナルアプリを開発・公開してみた!!
■AI時代の第一歩!「AI駆動開発コース」はじめました!
テックジム東京本校で先行開始。
■テックジム東京本校
「武田塾」のプログラミング版といえば「テックジム」。
講義動画なし、教科書なし。「進捗管理とコーチング」で効率学習。
より早く、より安く、しかも対面型のプログラミングスクールです。
<短期講習>5日で5万円の「Pythonミニキャンプ」開催中。
<月1開催>放送作家による映像ディレクター養成講座
<オンライン無料>ゼロから始めるPython爆速講座
