pandasのDataFrameでgroupby
を使うことでグループ化して集約する方法について解説します。
Contents
groupbyによる集約
pandasのDataFrameでデータ分析をする際には、合計や平均等の集約処理をすることがよくあります。データの集約の際には、単純にDataFrame全体に対して集約処理をするだけでなく、ある意味を持ったグループ単位で集約処理をすることでデータに対する有益な情報を得ることができます。
SQLを少し学んだことがある人であれば「groupby
」がすぐに頭に浮かぶと思いますが、pandasのDataFrameでも同様にgroupby
による集約処理が可能です。本記事では、pandasのDataFrameをgroupby
でグループ化して集約する方法について基本的な方法を紹介します。
以降では、以下の簡単なデータを用いてpandasのDataFrameでどのようにgroupby
による集約ができるのかを説明していきます。
上記データのイメージは、製造業で各シリアルナンバーごとに蓄積されている品質データです。データとしては、各シリアル(serial_no
)に対して、品質項目1(quality_val1
)と品質項目2(quality_val2
)の値を持っているような表です。
品目(item_code
)は各製品の種類を表すような区分になりますが、今回はこの品目(item_code
)をキーにしてグループ化し、各品質データを集約をするということを考えてみようと思います。
groupbyの集約の考え方
「分割(split) – 適用(apply) – 結合(combine)」
groupby
による集約では「分割(split) – 適用(apply) – 結合(combine)」に分けて処理がされているということを理解してほしいと思います。以下の図を見てみてください。
この例は今回のサンプルデータに対してitem_code
をキーとしてgroupby
する際の処理の適用イメージです。
groupby
での処理は大きく以下のような手順で実行されています。
- 分割(split):指定したキー(上記例では
item_code
)に応じてDataFrameを分割してグループを作ります。 - 適用(apply):各グループのデータ(上記例では
quality_val1
)に対して集約処理を実施します。この例では合計(sum
)の例を示していますが、他の集約処理でも同様です。 - 結合(combine):各グループの処理結果を結合して、集約結果を完成させます。
上記のような図をイメージしてもらいつつ、以降の具体例を見ていくと、データ処理をイメージしやすいかと思います。では、pandasのgroupby
を使って集約処理を具体的にどのようにコーディングするか、例を使って見ていきましょう。
groupbyによるDataFrameの集約
groupbyによるDataFrameの集約の基本的な使い方
groupby
によるDataFrameの集約の基本的な使い方は以下のようになります。
import pandas as pd quality_result = pd.DataFrame( {'serial_no': ['S001', 'S002', 'S003', 'S004', 'S005', 'S006', 'S007', 'S008', 'S009', 'S010'], 'item_code': ['A', 'A', 'B', 'B', 'C', 'A', 'A', 'B', 'C', 'C'], 'quality_val1': [100, 150, 20, 10, 50, 120, 80, 5, 55, 40], 'quality_val2': [1, 2, 100, 120, 20, 5, 7, 90, 10, 10]} ) print(quality_result, '\n') # item_codeでグループ化 gr = quality_result.groupby('item_code') print(gr, '\n') # グループごとに集約を計算 # print(quality_result.groupby('item_code').sum()) print(gr.sum())
【実行結果】 serial_no item_code quality_val1 quality_val2 0 S001 A 100 1 1 S002 A 150 2 2 S003 B 20 100 3 S004 B 10 120 4 S005 C 50 20 5 S006 A 120 5 6 S007 A 80 7 7 S008 B 5 90 8 S009 C 55 10 9 S010 C 40 10 <pandas.core.groupby.generic.DataFrameGroupBy object at 0x000001A31B0E3EE0> quality_val1 quality_val2 item_code A 450 15 B 35 310 C 145 40
対象となるDataFrameのgroupby
メソッドにキーとなる列名を与えることで、DataFrameGroupBy
オブジェクト(pandas.core.groupby.generic.DataFrameGroupBy
)が生成されます。今回の例では、item_code
を集約のキーとして与えています。
このDataFrameGroupBy
オブジェクトは分割(split)の処理までがされているものになっているので、当該DataFrameGroupBy
オブジェクトに対して集約メソッドを実行することで後続の適用(apply)、結合(combine)が処理され、グループ単位の集約処理が実行できます。
上記例では一度分割までされている情報をgr
という変数に入れ、合計のsum
を呼び出しています。もちろん、quality_result.groupby('item_code').sum()
というように一行で書いても問題ありませんが、DataFrameGroupBy
をオブジェクト化して用意しておけば、sum()
以外にもmax()
等のような他の集約関数を必要に応じて呼び出すことが可能です。
列名を指定して集約する方法
上記例では、対象となるDataFrame全体に対して処理をしたため、集約メソッドが適用できる列が複数ある場合にはすべての列に対して処理が行われます。今回の例でいうと「quality_val1
」「quality_val2
」の両方にsum
が適用されました。
しかし、実際にはquality_val1
の結果のみ必要な場合もあると思います。そのような時にgroupby
オブジェクトは、列インデックスの要領で対象を絞り込んで集約することができます。以下の例で見てみましょう。
import pandas as pd quality_result = pd.DataFrame( {'serial_no': ['S001', 'S002', 'S003', 'S004', 'S005', 'S006', 'S007', 'S008', 'S009', 'S010'], 'item_code': ['A', 'A', 'B', 'B', 'C', 'A', 'A', 'B', 'C', 'C'], 'quality_val1': [100, 150, 20, 10, 50, 120, 80, 5, 55, 40], 'quality_val2': [1, 2, 100, 120, 20, 5, 7, 90, 10, 10]} ) print(quality_result, '\n') # 列を指定して集約する print(quality_result.groupby('item_code')['quality_val1'].sum())
【実行結果】 serial_no item_code quality_val1 quality_val2 0 S001 A 100 1 1 S002 A 150 2 2 S003 B 20 100 3 S004 B 10 120 4 S005 C 50 20 5 S006 A 120 5 6 S007 A 80 7 7 S008 B 5 90 8 S009 C 55 10 9 S010 C 40 10 item_code A 450 B 35 C 145 Name: quality_val1, dtype: int64
上記のように[]
で対象となる列名を指定することで対象列を絞って集約メソッドの実行ができます。上記例では、quarlity_val1
を指定することで結果としてはquality_val1
のみのsum()
による集約結果が得られています。
上記結果では、1列だけ取得してきているのでpandasのSeriesオブジェクトになっています。
グループごとに繰り返し処理をする方法
DataFrameGroupBy
オブジェクトはグループに対する反復をサポートしているため、以下のようにfor
文でグループごとに繰り返し処理をすることができます。
import pandas as pd quality_result = pd.DataFrame( {'serial_no': ['S001', 'S002', 'S003', 'S004', 'S005', 'S006', 'S007', 'S008', 'S009', 'S010'], 'item_code': ['A', 'A', 'B', 'B', 'C', 'A', 'A', 'B', 'C', 'C'], 'quality_val1': [100, 150, 20, 10, 50, 120, 80, 5, 55, 40], 'quality_val2': [1, 2, 100, 120, 20, 5, 7, 90, 10, 10]} ) print(quality_result, '\n') # グループごとに取り出して処理をする for (item_code, group) in quality_result.groupby('item_code'): print(f'item_code: {item_code}') print(f'group_data:\n{group}') print(f"group['quality_val1'].sum() = {group['quality_val1'].sum()}", '\n')
【実行結果】 serial_no item_code quality_val1 quality_val2 0 S001 A 100 1 1 S002 A 150 2 2 S003 B 20 100 3 S004 B 10 120 4 S005 C 50 20 5 S006 A 120 5 6 S007 A 80 7 7 S008 B 5 90 8 S009 C 55 10 9 S010 C 40 10 item_code: A group_data: serial_no item_code quality_val1 quality_val2 0 S001 A 100 1 1 S002 A 150 2 5 S006 A 120 5 6 S007 A 80 7 group['quality_val1'].sum() = 450 item_code: B group_data: serial_no item_code quality_val1 quality_val2 2 S003 B 20 100 3 S004 B 10 120 7 S008 B 5 90 group['quality_val1'].sum() = 35 item_code: C group_data: serial_no item_code quality_val1 quality_val2 4 S005 C 50 20 8 S009 C 55 10 9 S010 C 40 10 group['quality_val1'].sum() = 145
for
文のin
にDataFrameGroupBy
オブジェクトを渡すと「キー」と「グループに該当するDataFrame」が返却されます。for文内当該繰り返しのグループに対するキーがitem_codeに、グループのDataFrameがgroup
に入ります。
上記の例では、返却されてきたグループのDataFrameに対して、集約関数のsum()
を適用することで合計をとっています。このようにグループごとに処理をしたい場合にもgroupby
は便利に扱うことができます。
集約メソッド
いろいろな集約メソッド
上記の例では、集約処理のメソッドとしてsum()
を使った例でgroupby
の使い方を紹介してきました。pandasでは、多くの便利な集約メソッドが用意されています。集約メソッドの中には以下のようなものがあります。必要に応じて選択して使用してください。
集約メソッド | 概要説明 |
---|---|
describe() | データの統計情報をまとめて計算する。 ( count , mean , std , min , 25% , 50% , 75% , max ) |
sum() | 合計を計算する。 |
count() | 要素数を計算する。 |
mean() | 平均値を計算する。 |
median() | 中央値を計算する。 |
std() | 標準偏差を計算する。 |
var() | 分散を計算する。 |
min() | 最小値を計算する。 |
max() | 最大値を計算する。 |
first() | 最初の要素を計算する。 |
last() | 最後の要素を計算する。 |
便利な集約メソッド describe
いろいろな集約メソッドということで表で紹介しましたが、その中でも便利な集約メソッドとしてdescribe
メソッドを実際の例で紹介します。describe
メソッドは他の集約メソッドと使い方は同様で以下のように使用することができます。
import pandas as pd quality_result = pd.DataFrame( {'serial_no': ['S001', 'S002', 'S003', 'S004', 'S005', 'S006', 'S007', 'S008', 'S009', 'S010'], 'item_code': ['A', 'A', 'B', 'B', 'C', 'A', 'A', 'B', 'C', 'C'], 'quality_val1': [100, 150, 20, 10, 50, 120, 80, 5, 55, 40], 'quality_val2': [1, 2, 100, 120, 20, 5, 7, 90, 10, 10]} ) print(quality_result, '\n') # describeメソッド print(quality_result.groupby('item_code')['quality_val1'].describe())
【実行結果】 serial_no item_code quality_val1 quality_val2 0 S001 A 100 1 1 S002 A 150 2 2 S003 B 20 100 3 S004 B 10 120 4 S005 C 50 20 5 S006 A 120 5 6 S007 A 80 7 7 S008 B 5 90 8 S009 C 55 10 9 S010 C 40 10 count mean std min 25% 50% 75% max item_code A 4.0 112.500000 29.860788 80.0 95.0 110.0 127.5 150.0 B 3.0 11.666667 7.637626 5.0 7.5 10.0 15.0 20.0 C 3.0 48.333333 7.637626 40.0 45.0 50.0 52.5 55.0
上記例で見ると分かるように、describ
eメソッドはcount
, mean
, std
, min
, 25%
, 50%
, 75%
, max
というようにデータの特徴を見る際によく確認する項目をまとめて集計してくれます。
まずは、describe
を対象データに対して使ってみるだけで、手軽にデータの特徴を確認することができます。
ピボットテーブルの作成
データをグループ化した使う方法としては、ピボットテーブルもあります。ピボットテーブルは、groupby
を用いることで作成可能ですが、pandasでは、pivot_table
メソッドが用意されていて簡単に作成できます。
ピボットテーブルについては「DataFrameのpivot_tableでピボットテーブルを扱う」でまとめていますので参考にしてください。
まとめ
pandasのDataFrameでgroupby
を使うことでグループ化して集約する方法について解説しました。
集約処理(合計、平均等)の際には、ある区分ごとのグループ単位で集約処理をしたくなりますが、groupby
を使うことで簡単に実現が可能です。本記事では、まず集約処理の考え方を説明して、基本的なgroupby
の使い方を紹介しました。
集約処理は、データ分析で非常に重要な処理の一つです。是非groupby
をうまく使いこなしてほしいと思います。
pandas.DataFrame.groupbyの公式ドキュメントはこちらを参照してください。
上記で紹介しているソースコードについてはgithubにて公開しています。参考にしていただければと思います。