[pandas] GroupByオブジェクト

[pandas] GroupByオブジェクト

groupby操作

 部分的なデータについての集約操作は、groupby とよばれる操作によって実現できます。具体例を使って説明するために、重複要素を含むデータフレームを作成しておきます。

# リストPD38-1

import numpy as np
import pandas as pd

# 重複要素を含むデータフレームを作成
df = pd.DataFrame({"key":["A", "B", "A", "A", "B"],
                   "X":[1, 2, 4,  8, 16],
                   "Y":[1, 3, 9, 27, 81]})

print(df)
  key   X   Y
0   A   1   1
1   B   2   3
2   A   4   9
3   A   8  27
4   B  16  81

 下図にあるように、groupby分割 (split), 適用 (apply), 結合 (combine) という三段階を踏んで実行されます (この図の例では、apply は要素の合計をとる操作です)。

 pandas.groupby (split, apply, combine)

 pandas でこのような操作を実行するためには、最初に groupby()メソッドを使って、DataFrameGroupByオブジェクト を生成することから始めます。

# リストPD38-2

# DataFrameGroupByオブジェクトを生成
gb = df.groupby("key")

print(gb)
<pandas.core.groupby.groupby.DataFrameGroupBy object at 0x05E7FF70>

 DataFrameGroupByオブジェクトに対して集約メソッドを適用すると、分割されていたデータセットが再結合されて新しいデータフレームが生成されます。

# リストPD38-3

# ラベルXの共通要素ごとに総和を計算
s = gb.sum()

print(s)
      X   Y
key        
A     13  37
B     18  84

GroupBy.aggregate()

 aggregate()メソッド を使うと、複数の集約操作をまとめて実行できます。aggregate() は agg() という短縮名で使うこともできます。以下のコードを実行すると、共通要素ごとに [最大値、最小値、平均値] をまとめて計算します。

# リストPD38-4

# 共通要素ごとに最大値、最小値、平均値を計算
x = gb.agg(["max", "min", "mean"])

print(x)
          X                   Y               
     max min  mean      max  min  mean
key                                     
A     8   1   4.333333   27   1   12.333333
B    16   2   9.000000   81   3   42.000000

GroupBy.filter()

 filter()メソッド を使ってグループをフィルタリングできます。引数には、ある列に集約メソッドを適用した結果についての条件式を渡します。たとえば、列ラベル "Y" の要素の最大値が 10 以下となるグループを取得する場合は次のようなコードを記述します (上の図を見てわかるように、要素 "A" に対応するグループがこの条件を満たしています)。

# リストPD38-5

# "X"列の最大値が10以下となるグループを取得
f = gb.filter(lambda t: t["X"].max() < 10)

print(f)
   X   Y
0  1   1
2  4   9
3  8  27

GroupBy.transform()

 transform()メソッド は、グループごとにデータの変換を行なって再結合させます。たとえば、グループごとに (そのグループの) 平均値を引く場合は、以下のようなコードを記述します。

# リストPD38-6

# グループごとに平均値を引く
t = gb.transform(lambda t: t - t.mean())

print(t)
          X          Y
0 -3.333333 -11.333333
1 -7.000000 -39.000000
2 -0.333333  -3.333333
3  3.666667  14.666667
4  7.000000  39.000000

 

groupby操作の実践例

 以下のコードを実行すると、ある学校における 2 クラスの英語と数学の試験結果を記載したファイル (me_score.csv) を読み込んでデータフレームに格納します。

# リストPD39-1

import numpy as np
import pandas as pd

# ファイルのパス
u = "https://python.atelierkobato.com/wp-content/uploads/2019/07/me_score.csv"

# CSVファイルを読み込んでデータフレームに変換
me_score = pd.read_csv(u, encoding="SHIFT-JIS", header=0)

print(me_score)
    クラス   氏名          性別  英語  数学
 0     1     玉田 悠悟      m    71    60
 1     1     三芳野 春      m    63    69
 2     1     水本 大貴      m    76    72
・・・・・・・・・ [中略] ・・・・・・・・
38     2     曵原 じゅんこ  f    74    72
39     2     茶畑 加織      f    50    66

 m は male (男)、f は female (女) の頭文字です。
 データフレームを "クラス" で分割して、DataFrameGroupByオブジェクトを生成してみます。

# リストPD39-2

# SeriesGroupByオブジェクトを生成
gb_c = me_score.groupby("クラス")

print(gb_c)
<pandas.core.groupby.groupby.DataFrameGroupBy object at 0x05E7F3F0>

 gb_c に mean()メソッドを使うと、クラス別の平均点を求めることができます。

# リストPD39-3

# クラスごとに数学の平均点を計算
print(gb_c.mean())
        英語   数学
クラス              
   1    66.95  60.30
   2    58.00  59.85

 次はデータセットを "性別" で分割し、"英語" のデータをもつ SeriesGroupByオブジェクトを生成します。

# リストPD39-4

# SeriesGroupByオブジェクトを生成
gb = me_score.groupby("性別")["英語"]

print(gb)
<pandas.core.groupby.groupby.SeriesGroupBy object at 0x05BEDF30>

 mean()メソッドで男女別の平均点を計算できます。

# リストPD39-5

# 男女別に英語の平均点を計算
s = gb.mean()

print(s)
性別
f    61.10
m    63.85
Name: 英語, dtype: float64

 aggregate()メソッドを使ってみましょう。以下のコードを実行すると、クラス別の数学の最高点と最低点を取得します。

# リストPD39-6

# SeriesGroupByオブジェクトを生成
gb = me_score.groupby("クラス")["数学"]

# クラス別の数学の最高点と最低点を取得
x = gb.agg(["max", "min"])

print(x)
          max  min
クラス
   1       93   43
   2       77   36