Open In Colab

データのグルーピング#

本節ではデータをグルーピングして、集計する方法を学びます。ここでいうグルーピングとは、次のステップを指します。

  1. データをグループに分割

  2. 各グループに関数を適用して集計

  3. 集計結果をデータ構造に結合。

import plotly

tips = plotly.data.tips()
tips.head()
total_bill tip sex smoker day time size
0 16.99 1.01 Female No Sun Dinner 2
1 10.34 1.66 Male No Sun Dinner 3
2 21.01 3.50 Male No Sun Dinner 3
3 23.68 3.31 Male No Sun Dinner 2
4 24.59 3.61 Female No Sun Dinner 4

GroupByオブジェクト#

まずは DataFrame をグルーピングするオブジェクトを生成します。 groupby メソッドを実行すると、 DataFrameGroupBy オブジェクトを生成します。このオブジェクトからさまざまなメソッドを実行することにより、データのグループ集計が容易に行えます。

smoker = tips.groupby("smoker")
type(smoker)
pandas.core.groupby.generic.DataFrameGroupBy

DataFrameGroupBy オブジェクトはイテラブル(繰り返し可能)オブジェクトです。指定した列の要素(「smoker」列の場合はYes, Noで)でデータが分割されていることが確認できます。

for x in smoker:
    print(x)
('No',      total_bill   tip     sex smoker   day    time  size
0         16.99  1.01  Female     No   Sun  Dinner     2
1         10.34  1.66    Male     No   Sun  Dinner     3
2         21.01  3.50    Male     No   Sun  Dinner     3
3         23.68  3.31    Male     No   Sun  Dinner     2
4         24.59  3.61  Female     No   Sun  Dinner     4
..          ...   ...     ...    ...   ...     ...   ...
235       10.07  1.25    Male     No   Sat  Dinner     2
238       35.83  4.67  Female     No   Sat  Dinner     3
239       29.03  5.92    Male     No   Sat  Dinner     3
242       17.82  1.75    Male     No   Sat  Dinner     2
243       18.78  3.00  Female     No  Thur  Dinner     2

[151 rows x 7 columns])
('Yes',      total_bill   tip     sex smoker  day    time  size
56        38.01  3.00    Male    Yes  Sat  Dinner     4
58        11.24  1.76    Male    Yes  Sat  Dinner     2
60        20.29  3.21    Male    Yes  Sat  Dinner     2
61        13.81  2.00    Male    Yes  Sat  Dinner     2
62        11.02  1.98    Male    Yes  Sat  Dinner     2
..          ...   ...     ...    ...  ...     ...   ...
234       15.53  3.00    Male    Yes  Sat  Dinner     2
236       12.60  1.00    Male    Yes  Sat  Dinner     2
237       32.83  1.17    Male    Yes  Sat  Dinner     2
240       27.18  2.00  Female    Yes  Sat  Dinner     2
241       22.67  2.00    Male    Yes  Sat  Dinner     2

[93 rows x 7 columns])

DataFrameGroupBy オブジェクトから特定の要素を取り出すには get_group メソッドを実行します。

smoker.get_group("Yes")
total_bill tip sex smoker day time size
56 38.01 3.00 Male Yes Sat Dinner 4
58 11.24 1.76 Male Yes Sat Dinner 2
60 20.29 3.21 Male Yes Sat Dinner 2
61 13.81 2.00 Male Yes Sat Dinner 2
62 11.02 1.98 Male Yes Sat Dinner 2
... ... ... ... ... ... ... ...
234 15.53 3.00 Male Yes Sat Dinner 2
236 12.60 1.00 Male Yes Sat Dinner 2
237 32.83 1.17 Male Yes Sat Dinner 2
240 27.18 2.00 Female Yes Sat Dinner 2
241 22.67 2.00 Male Yes Sat Dinner 2

93 rows × 7 columns

DataFrameGroupBy オブジェクトから記述統計メソッドが実行できます。

smoker.mean(numeric_only=True)
total_bill tip size
smoker
No 19.188278 2.991854 2.668874
Yes 20.756344 3.008710 2.408602

DataFrameGroupBy オブジェクトのメソッドの引数 numeric_onlyTrue (デフォルト)である場合、数値データの列のみを集計します。将来のバージョンではこの引数のデフォルト値は False となるため、DataFrameGroupBy オブジェクトの添字に集計対象の列を渡します。

FutureWarning: The default value of numeric_only in DataFrameGroupBy.mean is deprecated. In a future version, numeric_only will default to False. Either specify numeric_only or select only columns which should be valid for the function. smoker.mean()

DataFrameGroupBy オブジェクトの特定の列に対して集計する場合は、添字に列名を渡します。

smoker["tip"].mean()
smoker
No     2.991854
Yes    3.008710
Name: tip, dtype: float64

DataFrameの select_dtypes メソッドは指定したデータ型のみを取り出したり、除外できます。

numeric = tips.select_dtypes(include=["float", "int"]).columns
numeric
Index(['total_bill', 'tip', 'size'], dtype='object')
smoker[numeric].mean()
total_bill tip size
smoker
No 19.188278 2.991854 2.668874
Yes 20.756344 3.008710 2.408602

複数列に対してグルーピングする場合は、 groupby メソッドにリストで渡します。

tips.groupby(["smoker", "time"])[numeric].mean()
total_bill tip size
smoker time
No Dinner 20.095660 3.126887 2.735849
Lunch 17.050889 2.673778 2.511111
Yes Dinner 21.859429 3.066000 2.471429
Lunch 17.399130 2.834348 2.217391

練習問題1#

tips オブジェクトを「day」列でグルーピングし、合計値を算出してください。

# 解答セル

複数の関数(メソッド)を実行する場合は agg メソッドにリストやタプルで渡します。

smoker[numeric].agg(("sum", "mean"))
total_bill tip size
sum mean sum mean sum mean
smoker
No 2897.43 19.188278 451.77 2.991854 403 2.668874
Yes 1930.34 20.756344 279.81 3.008710 224 2.408602

辞書のキーを列名、値を関数名(メソッド名)に指定することで、列ごとに適用する関数を指定できます。

smoker.agg({"tip": "mean", "total_bill": "std"})
tip total_bill
smoker
No 2.991854 8.255582
Yes 3.008710 9.832154

agg メソッドには任意の関数を渡せます。

smoker[numeric].agg(sum)
total_bill tip size
smoker
No 2897.43 451.77 403
Yes 1930.34 279.81 224

次のコードでは5%パーセンタイルより大きく、95%パーセンタイルより小さい範囲の平均値を算出する関数を作成し、適用しています。

def my_mean(x):
    return x[(x > x.quantile(0.05)) & (x < x.quantile(0.95))].mean()


smoker[["total_bill", "tip", "size"]].agg(my_mean)
total_bill tip size
smoker
No 18.495333 2.877852 3.0
Yes 20.166627 2.900361 3.0

練習問題2#

tips オブジェクトを「day」列でグルーピングし、「size」列の平均値、「tip」列の中央値を算出してください。

# 解答セル