0Pricing
Pandas & NumPy Academy · レッスン

グループ内の順位とパーセンタイル

groupby().rank()でグループ内の順位を計算し、pd.qcutで相対比較用のパーセンタイル区間を作成します。

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

グループ内で順位を付ける理由

生の値は、相対的な順位よりも意味が伝わりにくいことがあります。月間売上が50,000ドルの営業担当者は、平均が30,000ドルなら上位の成績ですが、平均が80,000ドルなら成績不振です。グループ内で順位を計算すると(たとえば地域ごと、または四半期ごとに順位を付けると)、グループごとの異なる基準値を考慮した正規化済みの比較ができます。Pandasでは、groupby().rank()を使ってグループ内の順位を簡単に計算できます。

import pandas as pd
import numpy as np

np.random.seed(42)
df = pd.DataFrame({
    'rep': ['Alice', 'Bob', 'Carol', 'Dave', 'Eve',
            'Frank', 'Grace', 'Hank', 'Iris', 'Jake'],
    'region': ['East']*5 + ['West']*5,
    'sales': np.random.randint(30000, 100000, 10)
})
print(df.sort_values('region'))

Series.rank() — 基本的な順位付け

Series.rank()は各値に順位を割り当てます。順位1が最小値、順位nが最大値です。ascending=Falseパラメータを指定すると方向が反転し、順位1が最大値になります。デフォルトでは同順位の値をその順位の平均で処理するため、結果は整数ではなく浮動小数点のSeriesになります。5つの値を持つ列では、順位は1.0から5.0の範囲になります。同順位がある場合は、2.5のように同じ順位を共有する値もあります。

import pandas as pd

s = pd.Series([80, 45, 90, 45, 70])

print('Values:', s.values)
print('Rank (ascending=True, default):', s.rank().values)
print('Rank (ascending=False — best=1):', s.rank(ascending=False).values)
# Note: two 45s share ranks 1 and 2 → both get 1.5

rank()の同順位処理方法

methodパラメータは、同順位の値をどのように処理するかを制御します。選択肢は、'average'(デフォルト。同順位の値に順位の平均を割り当てる)、'min'(すべての同順位の値に最小順位を割り当てる)、'max'(すべてに最大順位を割り当てる)、'first'(登場順に順位を付けるため、同順位にならない)、'dense'(順位に欠番を作らない。1, 2, 3, 3, 4は、1, 2, 3, 3, 5ではなく1, 2, 3, 3, 4になる)です。'dense'メソッドは、パーセンタイル形式の順位付けに最も便利です。

import pandas as pd

s = pd.Series([80, 45, 90, 45, 70])

result = pd.DataFrame({
    'value': s,
    'average': s.rank(method='average'),
    'min': s.rank(method='min'),
    'max': s.rank(method='max'),
    'first': s.rank(method='first'),
    'dense': s.rank(method='dense')
})
print(result)

groupby().rank()によるグループ内の順位付け

groupby('group_col')['value_col'].rank()は、各グループ内で独立して順位を計算します。順位は各グループの開始時にリセットされるため、East地域で最も成績のよい担当者はEastで順位1になり、West地域で最も成績のよい担当者もWestで順位1になります。これにより、groupbyによる順位付けはグループ間の公平な比較に役立ちます。

import pandas as pd
import numpy as np

np.random.seed(42)
df = pd.DataFrame({
    'rep': list('ABCDEABCDE'),
    'region': ['East']*5 + ['West']*5,
    'sales': np.random.randint(30000, 100000, 10)
})

# Rank within each region (best = rank 1)
df['rank_in_region'] = df.groupby('region')['sales'].rank(ascending=False, method='min')
df_sorted = df.sort_values(['region', 'rank_in_region'])
print(df_sorted.to_string(index=False))

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

rank()でpct=Trueを設定すると、パーセンタイル順位が返されます。これは、グループ内で現在の値以下の値がどの程度の割合を占めるかを表す、0から1までの値です。パーセンタイル順位が0.8の場合、その値は80パーセンタイルにあり、全値の80%を上回ることを意味します。この正規化により、グループの実際のサイズを知らなくても、サイズの異なるグループの値を直接比較できます。

import pandas as pd
import numpy as np

np.random.seed(0)
df = pd.DataFrame({
    'name': list('ABCDEFGHIJ'),
    'region': ['East']*5 + ['West']*5,
    'score': np.random.randint(50, 100, 10)
})

# Percentile rank within region
df['pct_rank'] = df.groupby('region')['score'].rank(pct=True)
df['percentile'] = (df['pct_rank'] * 100).round(0).astype(int)
print(df.sort_values(['region', 'percentile'], ascending=[True, False]).to_string(index=False))

pd.qcut:分位点に基づくビニング

pd.qcut(series, q)は、値を出現頻度が均等なq個のビンに分割し、各ビンにほぼ同じ数の観測値が入るようにします。同じ幅の区間を使うpd.cutとは異なり、pd.qcutはデータの分布に合わせて区間の境界を調整します。これは、パフォーマンス層を作成するための四分位(q=4)、五分位(q=5)、十分位(q=10)に最適です。

import pandas as pd
import numpy as np

np.random.seed(42)
sales = pd.Series(np.random.exponential(scale=50000, size=100))

# Divide into quartiles
quartiles = pd.qcut(sales, q=4, labels=['Q1', 'Q2', 'Q3', 'Q4'])

result = pd.DataFrame({'sales': sales, 'quartile': quartiles})
print('Quartile counts (should be ~25 each):')
print(result['quartile'].value_counts().sort_index())
print('\nMean sales per quartile:')
print(result.groupby('quartile')['sales'].mean().round(0))

pd.cutとpd.qcutの比較

pd.cut(series, bins=n)は幅が均等な区間を作成します(範囲は同じで、値の数は異なります)。pd.qcut(series, q=n)は頻度が均等な区間を作成します(値の数は同じで、範囲は異なります)。偏りのあるデータでは、pd.cutを使うと裾のビンがほぼ空になる一方、pd.qcutでは観測値が均等に分散されます。区間の境界にビジネス上の自然な意味がある場合(価格帯、年齢層)はpd.cutを、グループのサイズを均等にしたいパフォーマンス層にはpd.qcutを選択してください。

import pandas as pd
import numpy as np

np.random.seed(0)
# Right-skewed data
data = pd.Series(np.random.exponential(1, 100))

cut_result = pd.cut(data, bins=5).value_counts().sort_index()
qcut_result = pd.qcut(data, q=5).value_counts().sort_index()

print('Equal-width bins (pd.cut) — uneven counts:')
print(cut_result.to_string())
print('\nEqual-frequency bins (pd.qcut) — even counts:')
print(qcut_result.to_string())

pd.qcutによる十分位ラベルの作成

pd.qcut(series, q=10, labels=range(1,11))は、各観測値を十分位(1から10)に割り当てます。これは、マーケティング分析(顧客価値の十分位)、信用スコアリング(リスクの十分位)、A/Bテスト(コホート分析用のトラフィックの十分位)で標準的に使われる手法です。labelsパラメータには、qと同じ長さの任意のリストを指定できます。より読みやすい出力にするには、['Bottom 10%', ..., 'Top 10%']のような文字列を使用してください。

import pandas as pd
import numpy as np

np.random.seed(7)
customer_value = pd.Series(np.random.exponential(500, 1000))

# Assign to deciles 1-10
decile_labels = [f'D{i}' for i in range(1, 11)]
customer_decile = pd.qcut(
    customer_value,
    q=10,
    labels=decile_labels
)

result = pd.DataFrame({'value': customer_value, 'decile': customer_decile})
print('Mean customer value per decile:')
print(result.groupby('decile')['value'].mean().round(0))

グループ内のパーセンタイルビン

groupbyとpd.qcutをtransformと組み合わせると、各グループ内でパーセンタイルビンを作成できます。これは、顧客を全体ではなく地域ごとに順位付けしたい場合に便利です。全体では下位十分位の顧客が、所属地域では上位十分位になることもあります。groupby('group')['value'].transform(lambda x: pd.qcut(x, q=4, labels=['Q1','Q2','Q3','Q4']))を使用してください。

import pandas as pd
import numpy as np

np.random.seed(42)
df = pd.DataFrame({
    'customer': range(20),
    'region': ['North']*10 + ['South']*10,
    'spend': np.random.randint(100, 1000, 20)
})

# Quartile within each region
def quartile_label(x):
    return pd.qcut(x, q=4, labels=['Q1','Q2','Q3','Q4'])

df['region_quartile'] = df.groupby('region')['spend'].transform(quartile_label)
print(df.sort_values(['region', 'region_quartile']).to_string(index=False))

グループ内のトップN

「各地域の成績上位3人は誰か」というのは、よくあるビジネス上の問いです。groupby().rank()で順位を付け、その後に順位でフィルタリングします。df[df['rank_col'] <= 3]のように記述します。これはグループのサイズに関係なく適切に動作し、カットオフ地点で同順位がある場合は3行を超えて残すことで、同順位も適切に処理します。または、groupby().nlargest(n)を使えば、順位列を追加せずにグループごとの最大値n個を直接取得できます。

import pandas as pd
import numpy as np

np.random.seed(0)
df = pd.DataFrame({
    'rep': [f'Rep_{i}' for i in range(15)],
    'region': ['East']*5 + ['West']*5 + ['North']*5,
    'revenue': np.random.randint(40000, 120000, 15)
})

df['region_rank'] = df.groupby('region')['revenue'].rank(ascending=False, method='min')

print('Top 2 per region:')
top2 = df[df['region_rank'] <= 2].sort_values(['region', 'region_rank'])
print(top2[['rep', 'region', 'revenue', 'region_rank']].to_string(index=False))

順位とTransformを組み合わせた正規化

groupby().rank(pct=True)をtransformと組み合わせると、元のDataFrameにパーセンタイル順位の列を追加できます。この正規化済みの列は、生の値よりもモデルの特徴量として役立つことがよくあります。尺度に依存せず、グループ間で比較できるためです。機械学習では、パーセンタイル順位は標準化(zスコア化)に代わるシンプルな方法であり、外れ値の影響を受けにくいという利点があります。

import pandas as pd
import numpy as np

np.random.seed(1)
df = pd.DataFrame({
    'product': np.random.choice(['A', 'B', 'C'], 30),
    'score': np.random.randint(50, 100, 30)
})

# Percentile rank within each product group
df['global_pct'] = df['score'].rank(pct=True).round(3)
df['group_pct'] = df.groupby('product')['score'].rank(pct=True).round(3)

print(df.sort_values(['product', 'score']).head(12).to_string(index=False))

クイックチェック

このレッスンで学んだ順位およびパーセンタイル操作について、理解度を確認しましょう。

レッスンのまとめ

このレッスンでは、Series.rank()が同順位処理を設定できる数値順位を計算すること、groupby().rank()が各グループ内で順位をリセットして公平なグループ間比較を可能にすること、pct=Trueが順位をパーセンタイル(0から1)に変換すること、そしてpd.qcutが四分位、十分位、パーセンタイル層の割り当てに使える頻度均等のビンを作成することを学びました。次は、プロファイリング、遅いループの回避、効率的なデータ型など、Pandasのパフォーマンス改善のヒントについて学びます。

よくある質問

「グループ内の順位とパーセンタイル」レッスンは無料ですか?

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

「グループ内の順位とパーセンタイル」で何を学びますか?

groupby().rank()でグループ内の順位を計算し、pd.qcutで相対比較用のパーセンタイル区間を作成します。 ブラウザで直接実行するハンズオンコードでPandas & NumPy Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

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

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

「グループ内の順位とパーセンタイル」レッスンにはどのくらい時間がかかりますか?

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

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

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

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

  1. ローリングウィンドウ
  2. 拡張ウィンドウ
  3. 指数加重移動平均
  4. グループ内の順位とパーセンタイル
← Pandas & NumPy Academyに戻る