值排名
使用 rank() 为列值分配排名,选择并列值的处理方式,并使用 pd.cut() 创建百分位区间。
值排名 是 CoddyKit 上的免费 Pandas & NumPy Academy 课时。 这是第 3 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Pandas & NumPy Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Pandas & NumPy Academy 课程共包含 4 节课。
本课时的部分内容尚未翻译,以英文显示。
What Is Ranking?
Ranking assigns each value in a Series a position based on its relative magnitude — rank 1 for the smallest value, rank n for the largest (or vice versa). Unlike sorting (which reorders rows), rank() adds a new column of ordinal positions alongside the original data. Rankings are used in leaderboards, percentile computation, and certain statistical tests that require ordinal position rather than absolute values.
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.0Ascending vs Descending Rank
By default, rank() gives rank 1 to the smallest value (ascending). To give rank 1 to the largest (e.g., first place in a competition), pass ascending=False. This mirrors the convention of 'first place = highest score' used in sports, leaderboards, and sales rankings.
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.0Tie-Breaking Methods
When multiple rows have the same value (a tie), the method parameter decides how ranks are assigned. The options are: 'average' (default — tied rows share the average rank), 'min' (all tied rows get the lowest rank), 'max' (all get the highest), 'first' (the row appearing first gets the lower rank), and 'dense' (no gaps in rank numbers after a tie).
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 Rank: No Gaps After Ties
The 'dense' method is especially useful when you want a ranking without gaps. With 'min', two entries tied for 2nd place make the next rank 4 (skipping 3). With 'dense', the next rank is always 3, maintaining a continuous sequence. Dense rank is the standard in SQL's DENSE_RANK() window function and is commonly used in leaderboards.
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 3Percentile Rank with pct=True
Setting pct=True in rank() normalises the ranks to the range [0, 1], giving you a percentile rank. A value with percentile rank 0.8 means it is higher than 80% of the values in the column. This is used in finance (percentile performance), grading (score percentiles), and outlier detection.
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.0Ranking Within Groups
To compute ranks within each group independently (e.g., each department's salary rank), combine groupby() with rank(). Use groupby().rank() which applies the rank function group-by-group and returns a Series aligned with the original DataFrame index — perfect for adding a 'rank within group' column.
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 2pd.cut() for Equal-Width Bins
pd.cut(series, bins) divides a continuous numeric column into equal-width intervals (bins) and assigns each value to its bin. This converts a continuous variable into a categorical one, useful for histograms, age groups, income brackets, or any discretisation task. The result is a Categorical Series with interval labels.
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 Seniorpd.qcut() for Equal-Frequency Bins
pd.qcut(series, q) divides values into quantile-based bins where each bin contains approximately the same number of observations. Unlike pd.cut() (equal width), pd.qcut() produces equal-size groups — useful for percentile-based segmentation like decile scores, quintile splits, or quartile groupings.
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 5cut() vs qcut() — Key Differences
Use pd.cut() when your bins have a natural domain meaning (e.g., age brackets 0-18, 18-35, 35-60) — the bin widths matter semantically. Use pd.qcut() when you want equal group sizes regardless of where the boundaries fall — for example, dividing customers into top/bottom quartiles. A skewed distribution will produce very unequal groups with cut() but equal groups with 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)Adding Rank Number as a Column
A clean pattern for producing a ranked output table is: sort descending, reset the index to 0-based, shift by 1 for human-readable 1-based ranking, and display alongside the original data. This produces a presentation-ready leaderboard with no gaps and clean rank numbers.
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)Rank as a Feature for Machine Learning
Rank-transformed features are useful in machine learning because they are robust to outliers — a very large or very small value gets a rank near the extremes rather than skewing the feature distribution. Rank transformation is sometimes used as a preprocessing step before tree-based models or when the numeric scale is not meaningful but relative ordering is.
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 disproportionateQuick Check
Test your understanding of ranking values in Pandas.
Lesson Recap
In this lesson you learned: rank() assigns ordinal positions to values, method='dense' avoids gaps after ties, pct=True gives percentile ranks in [0,1], and groupby().rank() computes within-group ranks. Use pd.cut() for equal-width bins and pd.qcut() for equal-frequency bins when discretising continuous variables. Next up we set and reset the DataFrame index.
常见问题解答
「值排名」课时是免费的吗?
是的 — 「值排名」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Pandas & NumPy Academy 课程的其余内容,请升级到 CoddyKit PRO。 Pandas & NumPy Academy 课程共包含 4 节课。
「值排名」这节课中我会学到什么?
使用 rank() 为列值分配排名,选择并列值的处理方式,并使用 pd.cut() 创建百分位区间。 你通过在浏览器中直接运行的动手代码来练习 Pandas & NumPy Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 Pandas & NumPy Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 Pandas & NumPy Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 3 节课,共 4 节。
「值排名」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 Pandas & NumPy Academy 课中编写并运行代码吗?
能。每节 Pandas & NumPy Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。