rank()の使い方

DataFrameやSeriesのrank()を使うと、順位を計算できます。

具体的な例を見てみましょう。次のような、あるゲームのユーザーごとのスコアについて考えます。スコアは、値が小さいほど良いものとします。


ユーザーID
スコア
user15
user250
user310
user4100

次のように書くと、指定した列を昇順で並び替えた順で順位付けした結果が得られます。

# 列スコアを昇順で順位付け
df["スコア"].rank()
ユーザーID
user1    1.0
user2    3.0
user3    2.0
user4    4.0
Name: スコア, dtype: float64

最もスコアが小さいuser1が1位、最もスコアが大きいuser4が4位になっていることがわかります。

https://images.pyq.jp/repo/prod/pandas_prepare_calc_v2/rank_series.jpg

引数ascendingを使って、順位付けを昇順でするか降順でするか指定できます。

  • True: 昇順(デフォルト)。最も小さい値が1位になる。
  • False: 降順。最も大きい値が1位になる。

rank()で便利なのは、同一順位の扱いを指定できる点です。

具体的な例を見てみましょう。次のデータでは、user2user3が同点(50点)なので同一順位になります。

ユーザーIDスコア
user15
user250
user350
user4100

同一順位がある場合、順位付けを考える上でのポイントは次の2つです。

  • (1) 同一順位であるuser2user3は何位になるか
  • (2) user2user3の次に点数が大きいuser4は何位になるか

どう計算したいかは状況によって変わります。

(1)のuser2user3の順位については、「user2user31位の次なのだから2人とも2位」と考えることもできれば「2位と3位の間だと考えて2.5位」という考え方もあります。

また、(2)のuser4の順位については「user2user3が2位なら、2位の次であるuser4は3位」と考えることもできれば「2位が2人いて4人目に相当するからuser4は4位」という考え方もできます。

rank()では、引数methodを使って同一順位の計算方法を指定できます。

説明例(今回のケース)
"average"平均値(デフォルト)2位と3位の平均なので、user2もuser3も2.5位
"min"同一のデータの中で最小の順位。次の順位は同一データの数だけカウントアップするuser2とuser3は2位。user4は 4位
"max"同一のデータの中で最大の順位user2とuser3は3位。user4は 4位
"dense"同一のデータの中で最小の順位。次の順位は+1した値user2とuser3は2位。user4は3位
https://images.pyq.jp/repo/prod/pandas_prepare_calc_v2/rank_series_method.jpg

DataFrameのrank()を使うと、デフォルトではすべての列について順位づけした結果を得られます。
cumsum()同様、引数axisで順位を求める方向を指定可能です。

  • 0: 行方向の処理。列ごとに各行の順位を計算。デフォルト。
  • 1: 列方向の処理。行ごとに各列の順位を計算。

演習

import pandas as pd

# テストの成績を読み込み
df = pd.read_csv("dataset/score_rank.csv", index_col="生徒番号")
df
国語数学
生徒番号
user190100
user29290
user36090
user47879

国語の点数で順位付けした結果を列国語の順位に格納しましょう。

点数が高いほど良い順位(小さい順位)にしたい、つまり降順で並び替えた順位にしたいので、引数ascendingFalseを指定します。 実行すると、1番国語の点数が高いuser2が1位、次に点数が高いuser1が2位になっていることがわかります。

# 国語の点数で順位付けした結果を新しい列として追加
df["国語の順位"] = df["国語"].rank(ascending=False)
df
国語数学国語の順位
生徒番号
user1901002.0
user292901.0
user360904.0
user478793.0

次に、数学の点数で順位づけした結果を列数学の順位に格納しましょう。

数学の点数は、user2user3が90点で同じ順位です。デフォルトでは、平均をとって2人とも2.5位になります(2位と3位の平均)。

# 数学の点数で順位付けした結果を新しい列として追加
# デフォルトでは、同点の場合は平均をとった順位になる
df["数学の順位"] = df["数学"].rank(ascending=False)
df
国語数学国語の順位数学の順位
生徒番号
user1901002.01.0
user292901.02.5
user360904.02.5
user478793.04.0

引数methodを使って、同一順位の計算方法を変えてみましょう。

引数methodに”min”を指定すると、user2もuser3も2位になります。これは、「2位と3位の内の最小値」が採用されるためです。 また、user4の順位が4位になっています。

# "min": 同点の場合は、最小の順位になるように指定
df["数学の順位_min"] = df["数学"].rank(method="min", ascending=False)
df

国語
数学国語の順位数学の順位数学の順位_min
生徒番号
user1901002.01.01.0
user292901.02.52.0
user360904.02.52.0
user478793.04.04.0

引数methodに指定する値を”dense”に変えてみましょう。

実行すると、user2とuser3が2位である点は”min”と同じですが、user4の順位が3位になることがわかります。 「4番目の人だから4位」とするか「2位の次だから3位」とするかによって使い分けましょう。

# "dense": 同一順位の次の順位が"min"とは変わる
df["数学の順位_dense"] = df["数学"].rank(method="dense", ascending=False)
df
国語数学国語の順位数学の順位数学の順位_min数学の順位_dense
生徒番号
user1901002.01.01.01.0
user292901.02.52.02.0
user360904.02.52.02.0
user478793.04.04.03.0

DataFrameのrank()を使うと、各行または各列について順位を一括で求められます。
デフォルトでは行方向に沿って順位を計算するため、「各科目ごとに誰が何位だったか」がわかります。

# テストの成績を読み込み
df = pd.read_csv("dataset/score_rank.csv", index_col="生徒番号")
# 列ごとに順位を計算(=各科目ごとに誰が何位だったか)
df.rank(ascending=False)

生徒番号
国語数学
user12.01.0
user21.02.5
user34.02.5
user43.04.0

引数axis1を指定すると行方向に沿って順位が計算されるので、「各生徒ごとにどの科目が何位だったか」 がわかります。
たとえばuser1は国語が90点、数学が100点なので、国語が2位、数学が1位になります。

# 行ごとに順位を計算(=各生徒ごとにどの科目が何位だったか)
df.rank(ascending=False, axis=1)

生徒番号
国語数学
user12.01.0
user21.02.0
user32.01.0
user42.01.0

コメント

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