通し番号の付与 cumcount()

cumcount()

cumcount() はDataFrameにはなく、DataFrameGroupByだけで使えるメソッドです。グループごとに、データに対して通し番号をふりたい時に使います。たとえば、以下のようなケースです。

  • 複数ユーザーの購入履歴のログで、ユーザーごとに何回目の購入データかわかるように識別子をふる
  • 複数クラスの試験結果のデータで、クラスごとに生徒に対して一意な識別子をふる

次のように記述して使います。

# 指定した列名でグループ化
grouped = df.groupby(列名)
# グループごとに0始まりの通し番号をふる
grouped.cumcount()

デフォルトでは、上の行から順に通し番号をふります。下の行から通し番号をふりたい場合は、引数ascendingFalseを指定します。

DataFrameGroupByのrank()は列ごとに値を計算するため結果がDataFrameになりますが、cumcount()は行の並び順で値が決まります。つまり、列の値は無関係なので、結果はSeriesになります。

具体的な例を見てみましょう。次のような試験結果と学習時間のデータについて考えます。


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

クラスごとに、各データに0始まりの通し番号をふってみましょう。

# 列「クラス」でグループ化
grouped = df.groupby("クラス")
# グループごとに0始まりの通し番号をふる
grouped.cumcount()

実行結果:

生徒ID
ST001    0
ST002    1
ST003    0
ST004    2
ST005    1
ST006    2
dtype: int64
https://images.pyq.jp/repo/prod/pandas_groupby_transform_v2/groupby_cumcount.jpg

各グループごとに、上から順に通し番号がふられていることがわかります。
たとえば、クラス1-Aのデータ(ST001ST002ST004)は、行の並び順にしたがって生徒ST0010、 生徒ST0021、生徒ST0042になっています。

演習

import pandas as pd

# 試験結果のデータを読み込み
df = pd.read_csv("dataset/score_study_time.csv", index_col="生徒ID")
# 先頭5行を確認
df.head()
クラス点数学習時間(分)
生徒ID
ST0011-A48.0226
ST0021-A0.024
ST0031-B80.0271
ST0041-ANaN45
ST0051-A68.0271

今回はクラスごとに通し番号をふるので、groupby()を使ってクラスごとにグループ化します。

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

各クラスの上の行から順に、0始まりの通し番号を割り当てましょう。

これは、cumcount()を使って実現できます。rank()は列ごとに計算されるので結果はDataFrameでしたが、cumcount()は列の値は関係ないため、結果はSeriesの形で得られます。

# グループ内で上から順に通し番号をつける
cumcount_df = grouped.cumcount()
cumcount_df
生徒ID
ST001    0
ST002    1
ST003    0
ST004    2
ST005    3
ST006    1
ST007    4
ST008    2
ST009    3
ST010    4
ST011    5
ST012    6
ST013    5
ST014    6
ST015    7
ST016    8
ST017    7
ST018    9
ST019    8
ST020    9
dtype: int64

実行結果を、新しい列として元のDataFrameに追加しましょう。In [4]:

# グループ内での通し番号を新しい列として追加する
df["グループ内ID"] = cumcount_df
# 結果の先頭5行を確認
df.head()
クラス点数学習時間(分)グループ内ID
生徒ID
ST0011-A48.02260
ST0021-A0.0241
ST0031-B80.02710
ST0041-ANaN452
ST0051-A68.02713

確認のため、クラスが1-Aのデータの結果を見てみましょう。クラス1-Aのデータの中で上の行から順に012……と通し番号が割り振られていることがわかります。In [5]:

# 1-Aのデータだけを確認する
df[df["クラス"] == "1-A"]
クラス点数学習時間(分)グループ内ID
生徒ID
ST0011-A48.02260
ST0021-A0.0241
ST0041-ANaN452
ST0051-A68.02713
ST0071-A49.02364
ST0111-A98.03815
ST0121-A84.02866
ST0171-A81.03557
ST0191-A78.03268
ST0201-A90.03019

同様に、クラス1-Bのデータも確認してみましょう。こちらも、グループ内の上の行から順に0始まりの通し番号が付与されていることがわかります。このように、DataFrameGroupByオブジェクトのcumcount()ではグループ単位で変換処理が適用されます。In [6]:

# 1-Bのデータだけを確認する
df[df["クラス"] == "1-B"]
クラス点数学習時間(分)グループ内ID
生徒ID
ST0031-B80.02710
ST0061-B58.02151
ST0081-B79.03342
ST0091-B75.02563
ST0101-BNaN2294
ST0131-B58.01925
ST0141-B83.02866
ST0151-B62.02207
ST0161-B69.02228
ST0181-BNaN2249

コメント

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