複数の集約値を一度に出したいときはagg()
が便利です。次のように、集約方法のリストを渡すことで複数の集約値を一度に計算します。
# 指定した列でグループ化する
grouped = df.groupby(列名)
# グループごとに複数の方法で集約する
grouped.agg(集約方法のリスト)
集約方法には、集約方法を示す文字列(最大値であれば"max"
など)や関数を指定できます。本問ではまず、集約方法の文字列を指定して複数の集約値を計算する方法を学びます。
具体的な例を見てみましょう。次のような、試験結果と学習時間のデータについて考えます。
生徒ID | クラス | 点数 | 学習時間(分) |
---|---|---|---|
ST001 | 1-A | 60 | 232 |
ST002 | 1-A | 87 | 345 |
ST003 | 1-B | 66 | 180 |
ST004 | 1-A | 72 | 22 |
ST005 | 1-B | 74 | 120 |
ST006 | 1-B | 58 | 215 |
クラスごとに各列の最大値と最小値を計算したい場合、次のように"max"
と"min"
を集約方法として指定します。
# 列「クラス」でグループ化
grouped = df.groupby("クラス")
# 最大値と最小値で集約
grouped.agg(["max", "min"])
点数 | 学習時間(分) | |||
---|---|---|---|---|
max | min | max | min | |
クラス | ||||
1-A | 87 | 60 | 345 | 22 |
1-B | 74 | 58 | 215 | 120 |
複数の集約値を計算した場合、列名が「元のDataFrameの列名」と「集約方法」の2階層になります。このような複数の階層を持つ列名のことをマルチカラムといいます。
今回のクエストでは、「複数の集約値を一度に計算すると、結果の列名が2階層になる」と言う点だけ分かっていれば大丈夫です。
SeriesGroupByのagg()
SeriesGroupByでもagg()
が使えます。SeriesGroupByのagg()
で複数の集約方法を指定すると、結果はマルチカラムではなく通常の列名になります。
# SeriesGroupByのagg()
grouped["点数"].agg(["max", "min"])
クラス | max | min |
---|---|---|
1-A | 87 | 60 |
1-B | 74 | 58 |
列ごとに異なる集約値を使う
データ分析の実務では、列ごとに異なる集約方法を適用したい場合があります。このような場合は、agg()
で キーが列名、値が集約方法の辞書 を指定します。
# 列ごとに異なる集約方法を指定する
grouped.agg({列名1: 集約方法1, 列名2: 集約方法2}
たとえば、列点数
は最大値と最小値、列学習時間(分)
は平均値を出したい場合、次のように指定します。
# 列「クラス」でグループ化
grouped = df.groupby("クラス")
# グループごとに点数の最大値・最小値、学習時間の平均値を出す
grouped.agg({"点数": ["max", "min"], "学習時間(分)": "mean"})
点数 | 学習時間(分) | ||
---|---|---|---|
max | min | mean | |
クラス | |||
1-A | 87 | 60 | 199.666667 |
1-B | 74 | 58 | 171.666667 |
演習
import pandas as pd
# 試験結果のデータを読み込み
df = pd.read_csv("dataset/score_study_time_club.csv", index_col="生徒ID")
# 先頭5行を確認
df.head()
クラス | 点数 | 学習時間(分) | 部活動 | |
---|---|---|---|---|
生徒ID | ||||
ST001 | 1-A | 48.0 | 226 | 合唱部 |
ST002 | 1-A | 0.0 | 24 | 科学部 |
ST003 | 1-B | 80.0 | 271 | 科学部 |
ST004 | 1-A | NaN | 45 | 合唱部 |
ST005 | 1-A | 68.0 | 271 | 美術部 |
今回はクラスごとに集約したいので、groupby()
を使って列クラス
でグループ化します。
# 列「クラス」でグループ化
grouped = df.groupby("クラス")
(1)列点数
の最大値・最小値・平均値
まず、グループごとに各列の最大値・最小値を求めてみましょう。 agg()
メソッドで集約方法が格納されたリストを指定すると、複数の集約値が一括で計算されます。
今回は最大値と最小値を計算したいので、[“max”, “min”]を指定します。実行すると、列名が2階層になり、列ごとに最大値・最小値が計算できることがわかります。
# グループごとに各列の最大値・最小値を計算
agg_df_1 = grouped.agg(["max", "min"])
agg_df_1
点数 | 学習時間(分) | 部活動 | ||||
---|---|---|---|---|---|---|
max | min | max | min | max | min | |
クラス | ||||||
1-A | 98.0 | 0.0 | 381 | 24 | 美術部 | サッカー部 |
1-B | 83.0 | 58.0 | 334 | 192 | 美術部 | ラグビー部 |
(2)列学習時間(分
の最大値・最小値・平均値
集約値に平均値(”mean”)を追加してみましょう。
次のコードを実行すると、列点数
と列学習時間(分)
の結果に”mean”が追加されますが、列部活動
の結果は消えることがわかります。これは、文字列が格納された列部活動
は平均を計算できないためです。このように、計算できない集約値が含まれていると結果から消える点に気をつけてください。
# グループごとに各列の最大値・最小値・平均値を計算
# (列「部活動」は平均値を計算できないので無視される)
agg_df_2 = grouped.agg(["max", "min", "mean"])
agg_df_2
点数 | 学習時間(分) | |||||
---|---|---|---|---|---|---|
max | min | mean | max | min | mean | |
クラス | ||||||
1-A | 98.0 | 0.0 | 66.222222 | 381 | 24 | 245.1 |
1-B | 83.0 | 58.0 | 70.500000 | 334 | 192 | 244.9 |
(3)列部活動
のユニーク数
列ごとに集約値を変えることも可能です。
列点数
と列学習時間(分)
は最大値・最小値・平均値を、列部活動
はユニーク数を計算してみましょう。このような場合は、agg()
にキーが列名、値が集約方法となっている辞書を指定します。
# 列ごとに集約値を指定する
agg_df_3 = grouped.agg(
{
"点数": ["max", "min", "mean"], # 最大値・最小値・平均値で集約
"学習時間(分)": ["max", "min", "mean"], # 最大値・最小値・平均値で集約
"部活動": "nunique", # ユニーク数で集約
}
)
agg_df_3
点数 | 学習時間(分) | 部活動 | |||||
---|---|---|---|---|---|---|---|
max | min | mean | max | min | mean | nunique | |
クラス | |||||||
1-A | 98.0 | 0.0 | 66.222222 | 381 | 24 | 245.1 | 5 |
1-B | 83.0 | 58.0 | 70.500000 | 334 | 192 | 244.9 | 7 |
補足
DataFrameGroupByのdescribe()
を使うと、グループごとに各列の基本統計量を計算できます。
# 列「クラス」でグループ化
grouped = df.groupby("クラス")
# クラスごとに各列の基本統計量を計算
grouped.describe()
実行結果は長いため、省略します。
なお列が長くて見づらい場合は、T
を使って行と列を入れ替えると見やすくなります。
# 縦と横を入れ替えて表示
grouped.describe().T
コメント