トップページに戻る

Pandas―データ分析(3)GroupBy

分離ー適用ー結合

Pandasが得意としているのは、ある条件でデータを分類し、その特徴を調べるという処理です。具体的には、

  1. DataFrame.groupbyメソッドで小さいDataFrameに分割
  2. グループごとに計算を行う
  3. それらを集めてグループごとの計算結果を表示する

という流れとなります。
どういうgroupに分けるか、分けたDataFrameでどのような計算を行うかは解析の最も難しく面白いところだと思います。
このあたりの手法はGroup By: split-apply-combineを参考にしました。

DataFrame.groupby

引数で与えた列をkeyとして、分割してDataFrameGroupByオブジェクトを返す関数です(分割)。

In [1]:
import pandas as pd

%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
In [2]:
df = pd.DataFrame({
    "alphabet": np.random.choice(list("abc"), 15),
    "randn": np.random.randn(15),
    "rand": np.random.rand(15),
})
df
Out[2]:
alphabet randn rand
0 c 0.475997 0.992821
1 a 0.443803 0.541533
2 a -1.542293 0.385064
3 a 0.480258 0.859190
4 c -1.354883 0.484650
5 b 1.077677 0.478178
6 c -1.049236 0.762415
7 c 0.881290 0.133353
8 c 2.107907 0.020915
9 b 0.976134 0.521719
10 a -1.081692 0.333477
11 b 0.926112 0.134365
12 a -0.184165 0.280311
13 c 0.741431 0.225383
14 b 0.413151 0.149615

DataFrameGroupByオブジェクト

イテレータであり、for ~ in ...の...に置くと、グループ名と分割されたDataFrameを取り出すことが出来ます。

In [3]:
for _name, _df in df.groupby("alphabet"):
    print(_name)
    print(_df)
    print()
a
   alphabet     randn      rand
1         a  0.443803  0.541533
2         a -1.542293  0.385064
3         a  0.480258  0.859190
10        a -1.081692  0.333477
12        a -0.184165  0.280311

b
   alphabet     randn      rand
5         b  1.077677  0.478178
9         b  0.976134  0.521719
11        b  0.926112  0.134365
14        b  0.413151  0.149615

c
   alphabet     randn      rand
0         c  0.475997  0.992821
4         c -1.354883  0.484650
6         c -1.049236  0.762415
7         c  0.881290  0.133353
8         c  2.107907  0.020915
13        c  0.741431  0.225383

In [4]:
# get_groupで特定のkeyを持つDataFrameを取得する
df.groupby("alphabet").get_group("a")
Out[4]:
alphabet randn rand
1 a 0.443803 0.541533
2 a -1.542293 0.385064
3 a 0.480258 0.859190
10 a -1.081692 0.333477
12 a -0.184165 0.280311

DataFrameGroupByオブジェクトのメソッドを呼び出すことで、分割された各DataFrameで計算されます(適用)。
最終的に、グループごとに計算を行った結果がまとめられます(結合)。

In [5]:
# GroupByオブジェクトの関数を呼ぶとグループごとに計算した結果を返す
df.groupby("alphabet").mean()
Out[5]:
randn rand
alphabet
a -0.376818 0.479915
b 0.848268 0.320969
c 0.300417 0.436590

自作関数を各列に適用するためにはaggメソッドを使います。

In [6]:
# 最大値と最小値の差を計算する自作関数
def func(cols):
    return cols.max() - cols.min()

# aggメソッドで各グループ、各列に関数を適用し、値を得る
df.groupby("alphabet").agg(func).plot.bar()
Out[6]:
<AxesSubplot:xlabel='alphabet'>

正規分布乱数の方が最大値と最小値の差が大きいことがわかりますね。

基礎編

応用編