groupsを使った各グループの内訳を確認

DataFrameGroupByには各グループを確認するためのいろいろな機能があります。たとえば、次のようなものです

メソッド説明
get_group(グループ名)指定したグループのデータ(DataFrame)を取得
head(行数)各グループの先頭行を、指定した行数だけ取得(デフォルトでは5行)
tail(行数)各グループの末尾行を、指定した行数だけ取得(デフォルトでは5行)
nth(N)N-1番目の行を取得(Nには整数を指定

また、groupby()の結果をループと組み合わせると、各グループの名前(キー)とデータ(DataFrame)を取得できます。

# 各グループの名前(キー)とデータ(DataFrame)を取得
for name, group in grouped:
    print(name)  # グループ名(キー)
    print(group)  # グループのデータ(DataFrame)

生徒ID
クラス点数学習時間(分)
ST0011-A60232
ST0021-A87345
ST0031-B66180
ST0041-A7222
ST0051-B74120
ST0061-B58215

列クラスでグループ化してfor文に渡した場合、次のように表示されます。nameには各グループの名前、groupには各グループのデータ(DataFrame)が代入されます。

# 列「クラス」でグループ化
grouped = df.groupby("クラス")

for name, group in grouped:
    print(name)  # グループ名(キー)
    print("-------------------")
    print(group)  # グループのデータ(DataFrame)
    print("==========")
1-A
-------------------
       クラス  点数  学習時間(分)
生徒ID                   
ST001  1-A  60      232
ST002  1-A  87      345
ST004  1-A  72       22
==========
1-B
-------------------
       クラス  点数  学習時間(分)
生徒ID                   
ST003  1-B  66      180
ST005  1-B  74      120
ST006  1-B  58      215
==========

演習

import pandas as pd

# 試験結果データを読み込み
df = pd.read_csv("dataset/score_basic.csv", index_col="生徒ID")
# 先頭5行を確認
df.head()
クラス点数
生徒ID
ST0011-A48
ST0021-A88
ST0031-B56
ST0041-A66
ST0051-A68

(1)各グループの名前と、そのグループに属するデータ

今回はクラスごとにグループ化したいので、groupby()で列クラスを指定します。前問のおさらいで、まずはgroups属性で各グループに属する行を確認してみましょう。

# 列「クラス」でグループ化
grouped = df.groupby("クラス")
# 各グループのインデックスを確認
grouped.groups
{'1-A': ['ST001', 'ST002', 'ST004', 'ST005', 'ST007', 'ST011', 'ST012', 'ST017', 'ST019', 'ST020'], '1-B': ['ST003', 'ST006', 'ST008', 'ST009', 'ST010', 'ST013', 'ST014', 'ST015', 'ST016', 'ST018']}

DataFrameGroupByオブジェクトをfor文で使うと、各グループの名前(キー)とデータ(DataFrame)を確認できます。

# 各グループの情報を順に表示する
for name, group in grouped:
    print(name)  # グループ名(キー)
    print()  # 空行
    print(group)  # グループに属するデータ(DataFrame)
    print("======================")
1-A

       クラス   点数
生徒ID           
ST001  1-A   48
ST002  1-A   88
ST004  1-A   66
ST005  1-A   68
ST007  1-A   49
ST011  1-A  100
ST012  1-A   84
ST017  1-A   81
ST019  1-A   78
ST020  1-A   90
======================
1-B

       クラス  点数
生徒ID          
ST003  1-B  56
ST006  1-B  58
ST008  1-B  79
ST009  1-B  75
ST010  1-B  40
ST013  1-B  58
ST014  1-B  83
ST015  1-B  62
ST016  1-B  69
ST018  1-B  51
======================

(2)グループ1-Aに属するデータ

次に、グループ1-Aに属するデータを確認しましょう。get_group()を使うと、指定したグループに属するデータを取得できます。

# グループ「1-A」を取得
group_1_A = grouped.get_group("1-A")
group_1_A
クラス点数
生徒ID
ST0011-A48
ST0021-A88
ST0041-A66
ST0051-A68
ST0071-A49
ST0111-A100
ST0121-A84
ST0171-A81
ST0191-A78
ST0201-A90

(3)各グループの成績上位者1〜3位のデータ(点数でソート後、各グループの先頭3行)

DataFrameGroupByオブジェクトのhead()を使うと、各グループの先頭行を、指定した行数分だけ取得できます。

head()を利用して、「各クラスの成績上位者1〜3位のデータ」を取得してみましょう。これは、各グループの行が列点数の高い順で並んでいれば、「先頭3行」を取得することで1〜3位のデータが取得できます(今回は、1〜3位はそれぞれ1人ずつしかいないものとします)。

groupby()後、各グループでは元のDataFrameの行の並び順が保持されています。そのため、各グループでソートしたい場合は、groupby()を使う前にsort_values()を使ってソートします。

# 列「点数」の降順でソート
sorted_df = df.sort_values("点数", ascending=False)
# 先頭10行を確認
sorted_df.head(10)
クラス点数
生徒ID
ST0111-A100
ST0201-A90
ST0021-A88
ST0121-A84
ST0141-B83
ST0171-A81
ST0081-B79
ST0191-A78
ST0091-B75
ST0161-B69

クラスでグループ化してから、head()を使って各グループの先頭3行を表示します。グループ化前のDataFrame(sorted_df)と比較すると、1-Aと1-Bからそれぞれ成績上位3名分のデータが抽出されていることがわかります。

# 列「クラス」でグループ化
sorted_grouped = sorted_df.groupby("クラス")
# 各グループの先頭3行を取得
sorted_grouped.head(3)
クラス点数
生徒ID
ST0111-A100
ST0201-A90
ST0021-A88
ST0141-B83
ST0081-B79
ST0091-B75

(4)各グループの成績上位者3位のデータ(点数でソート後、各グループの3番目の行)

nth()を使うと、各グループから指定した位置のデータを取得します。

これを利用して、各クラスで3番目の成績上位者のデータを取得してみましょう。先頭から3番目なので、引数は2を指定します。

実行結果を確認すると、クラス1-Aでは88点(生徒ST002のデータ)、クラス1-Bでは75点(生徒ST009のデータ)となっており、各グループで上から3行目のデータが取得できていることがわかります。

# 各グループの先頭から3行目(位置は2)を取得
sorted_grouped.nth(2)
点数
クラス
1-A88
1-B75

コメント

タイトルとURLをコピーしました