データのグルーピング
Contents
データのグルーピング#
本節ではデータをグルーピングして、集計する方法を学びます。ここでいうグルーピングとは、次のステップを指します。
データをグループに分割
各グループに関数を適用して集計
集計結果をデータ構造に結合。
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_only
が True
(デフォルト)である場合、数値データの列のみを集計します。将来のバージョンではこの引数のデフォルト値は 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」列の中央値を算出してください。
# 解答セル