0Pricing
Pandas & NumPy Academy · レッスン

値の順位付け

rank()を使って列の値に順位を付け、同順位の処理方法を選び、pd.cut()でパーセンタイル区間を作成します。

「値の順位付け」はCoddyKit上の無料Pandas & NumPy Academyレッスンです。 これはレッスン3/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはPandas & NumPy Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Pandas & NumPy Academyコースには全4レッスンが含まれています。

順位付けとは

順位付けとは、各値の相対的な大きさに基づいて、Series内の各値に順位を割り当てることです。最小値を1位、最大値をn位とする場合や、その逆の場合があります。行の順序を変更するソートとは異なり、rank()は元のデータと並べて順位を表す新しい列を追加します。順位は、ランキング表やパーセンタイルの計算、絶対値ではなく順位が必要な一部の統計検定などで使用されます。

import pandas as pd

df = pd.DataFrame({
    'player': ['Alice', 'Bob', 'Carol', 'Dave', 'Eve'],
    'score': [88, 72, 95, 72, 85]
})

df['rank'] = df['score'].rank()
print(df)
#    player  score  rank
# 0   Alice     88   4.0
# 1     Bob     72   1.5   <- tied with Dave
# 2   Carol     95   5.0
# 3    Dave     72   1.5   <- tied with Bob
# 4     Eve     85   3.0

昇順と降順の順位

デフォルトでは、rank()は最小の値に1位を割り当てます(昇順)。最大値に1位を割り当てる場合(競技での1位など)は、ascending=Falseを渡します。これは、スポーツやランキング表、売上ランキングなどで使われる「最高得点が1位」という慣例に対応しています。

import pandas as pd

df = pd.DataFrame({'score': [70, 95, 85, 60, 90]})

# Rank 1 = highest score
df['competition_rank'] = df['score'].rank(ascending=False)
print(df)
#    score  competition_rank
# 0     70               4.0
# 1     95               1.0
# 2     85               3.0
# 3     60               5.0
# 4     90               2.0

同順位の処理方法

複数の行の値が同じ場合(同順位の場合)、methodパラメーターによって順位の割り当て方法を決めます。選択肢は、'average'(デフォルト。同順位の行に平均順位を割り当てる)、'min'(同順位のすべての行に最小順位を割り当てる)、'max'(すべてに最大順位を割り当てる)、'first'(先に登場する行に低い順位を割り当てる)、'dense'(同順位の後も順位番号に空きが生じない)です。

import pandas as pd

s = pd.Series([10, 20, 20, 30])

print('average:', s.rank(method='average').tolist())  # [1.0, 2.5, 2.5, 4.0]
print('min:    ', s.rank(method='min').tolist())      # [1.0, 2.0, 2.0, 4.0]
print('max:    ', s.rank(method='max').tolist())      # [1.0, 3.0, 3.0, 4.0]
print('first:  ', s.rank(method='first').tolist())    # [1.0, 2.0, 3.0, 4.0]
print('dense:  ', s.rank(method='dense').tolist())    # [1.0, 2.0, 2.0, 3.0]

密順位:同順位の後も空きなし

'dense'メソッドは、空きのない順位を作りたい場合に特に便利です。'min'では、2つの項目が2位で同順位になると、次の順位は3位を飛ばして4位になります。'dense'では、次の順位は必ず3位になり、連続した順序が保たれます。密順位はSQLのDENSE_RANK()ウィンドウ関数で標準的に使われ、ランキング表でも一般的です。

import pandas as pd

df = pd.DataFrame({
    'name': ['A', 'B', 'C', 'D', 'E'],
    'score': [100, 80, 80, 60, 60]
})

df['dense_rank'] = df['score'].rank(method='dense', ascending=False).astype(int)
print(df)
#   name  score  dense_rank
# 0    A    100           1
# 1    B     80           2
# 2    C     80           2  <- same score, same rank
# 3    D     60           3  <- next rank is 3, not 4
# 4    E     60           3

pct=True によるパーセンタイル順位

rank()でpct=Trueを設定すると、順位が[0, 1]の範囲に正規化され、パーセンタイル順位を取得できます。パーセンタイル順位が0.8の値は、その列の値の80%より高いことを意味します。これは、金融(パーセンタイルによるパフォーマンス評価)、成績評価(得点のパーセンタイル)、外れ値検出などで使用されます。

import pandas as pd

df = pd.DataFrame({'score': [50, 70, 80, 90, 100]})

df['percentile'] = df['score'].rank(pct=True)
print(df)
#    score  percentile
# 0     50         0.2
# 1     70         0.4
# 2     80         0.6
# 3     90         0.8
# 4    100         1.0

グループ内での順位付け

各グループ内で独立して順位を計算するには(各部署内の給与順位など)、groupby()とrank()を組み合わせます。groupby().rank()を使うと、グループごとに順位関数が適用され、元のDataFrameのインデックスに対応したSeriesが返されます。そのため、「グループ内順位」列の追加に最適です。

import pandas as pd

df = pd.DataFrame({
    'dept': ['Eng', 'Eng', 'HR', 'HR', 'Eng'],
    'name': ['Alice', 'Bob', 'Carol', 'Dave', 'Eve'],
    'salary': [90000, 70000, 55000, 65000, 80000]
})

df['dept_rank'] = df.groupby('dept')['salary'].rank(
    method='dense', ascending=False
).astype(int)
print(df.sort_values(['dept', 'dept_rank']))
#    dept   name  salary  dept_rank
# 0   Eng  Alice   90000          1
# 4   Eng    Eve   80000          2
# 1   Eng    Bob   70000          3
# 3    HR   Dave   65000          1
# 2    HR  Carol   55000          2

等幅ビンのための pd.cut()

pd.cut(series, bins)は、連続した数値列を幅が等しい区間(ビン)に分割し、各値を該当するビンに割り当てます。これにより連続変数をカテゴリ変数に変換できます。ヒストグラム、年齢層、所得区分など、連続値を離散化するさまざまな処理に便利です。結果は、区間ラベルを持つCategoricalのSeriesになります。

import pandas as pd

df = pd.DataFrame({'age': [5, 15, 25, 35, 45, 55, 65, 75]})

df['age_group'] = pd.cut(df['age'], bins=[0, 18, 35, 60, 100],
                          labels=['Child', 'Young Adult', 'Middle Age', 'Senior'])
print(df)
#    age    age_group
# 0    5        Child
# 1   15        Child
# 2   25  Young Adult
# 3   35  Young Adult
# 4   45   Middle Age
# 5   55   Middle Age
# 6   65       Senior
# 7   75       Senior

等頻度ビンのための pd.qcut()

pd.qcut(series, q)は、各ビンにほぼ同じ数の観測値が含まれるよう、分位点に基づくビンに値を分割します。等幅のpd.cut()とは異なり、pd.qcut()は同じ規模のグループを作成します。十分位スコア、五分位への分割、四分位グループなど、パーセンタイルに基づくセグメンテーションに便利です。

import pandas as pd
import numpy as np

np.random.seed(0)
df = pd.DataFrame({'score': np.random.randint(40, 100, 20)})

# Split into 4 equal-frequency quartiles
df['quartile'] = pd.qcut(df['score'], q=4, labels=['Q1', 'Q2', 'Q3', 'Q4'])
print(df['quartile'].value_counts().sort_index())
# Q1    5
# Q2    5
# Q3    5
# Q4    5

cut() と qcut() の主な違い

ビンに自然な領域上の意味がある場合(年齢区分の0~18歳、18~35歳、35~60歳など)はpd.cut()を使います。この場合、ビンの幅に意味があります。境界がどこになるかにかかわらずグループのサイズを等しくしたい場合(顧客を上位四分位と下位四分位に分ける場合など)はpd.qcut()を使います。歪んだ分布では、cut()はグループのサイズが大きく偏りますが、qcut()では均等になります。

import pandas as pd
import numpy as np

np.random.seed(0)
# Skewed distribution: most values near 0
skewed = pd.Series(np.random.exponential(scale=5, size=100).round())

# cut with equal width: many empty or tiny upper bins
cut_counts = pd.cut(skewed, bins=4).value_counts().sort_index()
print('cut():', cut_counts.values)

# qcut with equal frequency: always 25 per group
qcut_counts = pd.qcut(skewed, q=4).value_counts().sort_index()
print('qcut():', qcut_counts.values)

順位番号を列として追加する

順位付きの出力表を作成するには、降順にソートし、インデックスを0始まりにリセットしてから、表示用に1を加えるという方法が分かりやすく便利です。元のデータと並べて表示すれば、空きのない、整った順位番号を持つ、表示用にそのまま使えるランキング表になります。

import pandas as pd

df = pd.DataFrame({
    'team': ['Falcons', 'Eagles', 'Hawks', 'Owls'],
    'wins': [12, 9, 12, 7]
})

leaderboard = (
    df
    .sort_values('wins', ascending=False)
    .reset_index(drop=True)
)
leaderboard.index = leaderboard.index + 1
leaderboard.index.name = 'place'
print(leaderboard)

機械学習の特徴量としての順位

順位に変換した特徴量は、外れ値に頑健であるため、機械学習で役立ちます。極端に大きい値や小さい値があっても、特徴量の分布を歪めるのではなく、両端に近い順位になります。順位変換は、木ベースモデルの前処理として、または数値のスケールには意味がなく相対的な順序だけが重要な場合に使われることがあります。

import pandas as pd
import numpy as np

df = pd.DataFrame({
    'income': [30000, 50000, 70000, 1_000_000]  # outlier at 1M
})

# Add rank as a feature
df['income_rank'] = df['income'].rank(pct=True)
print(df)
#      income  income_rank
# 0    30000         0.25
# 1    50000         0.50
# 2    70000         0.75
# 3  1000000         1.00
# The outlier has rank 1.0 — extreme but not disproportionate

理解度チェック

Pandasでの値の順位付けについて、理解度を確認しましょう。

レッスンのまとめ

このレッスンでは、rank()が値に順位を割り当てること、method='dense'で同順位の後の空きをなくせること、pct=Trueで[0,1]のパーセンタイル順位を取得できること、そしてgroupby().rank()でグループ内の順位を計算できることを学びました。連続変数を離散化する場合、等幅のビンにはpd.cut()を、等頻度のビンにはpd.qcut()を使います。次は、DataFrameのインデックスを設定およびリセットします。

よくある質問

「値の順位付け」レッスンは無料ですか?

はい。「値の順位付け」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Pandas & NumPy Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Pandas & NumPy Academyコースには全4レッスンが含まれています。

「値の順位付け」で何を学びますか?

rank()を使って列の値に順位を付け、同順位の処理方法を選び、pd.cut()でパーセンタイル区間を作成します。 ブラウザで直接実行するハンズオンコードでPandas & NumPy Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

Pandas & NumPy Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのPandas & NumPy Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン3/4です。

「値の順位付け」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このPandas & NumPy Academyレッスンでコードを書いて実行できますか?

はい。すべてのPandas & NumPy Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. 列の値による並べ替え
  2. インデックスによる並べ替え
  3. 値の順位付け
  4. インデックスの設定とリセット
← Pandas & NumPy Academyに戻る