Percentiles & Quantiles
Describe where a score stands within the data with np.percentile and np.quantile — quartiles, the IQR, and the method parameter.
"Is 64 a good score for Virat?" The mean and max don't answer that. A percentile does: it tells you what fraction of the data lies below a value. Selectors use this all the time — "his 90th-percentile score is 88" means only 10% of his innings beat 88.
Definition
The p-th percentile of a dataset is the value below which p percent of the sorted data falls. A quantile is the same idea written as a fraction from 0 to 1 instead of a percentage: the 0.25 quantile = the 25th percentile.
- Sorted data — percentiles are about rank, so NumPy conceptually sorts the values first.
- Interpolation — when the exact position falls between two values, NumPy (by default) draws a straight line between them (
method="linear"). - Quartiles — the 25th, 50th and 75th percentiles split the data into four equal parts: Q1, Q2 (= median), Q3.
| Name | Percentile | Quantile |
|---|---|---|
| Minimum | 0 | 0.0 |
| Q1 (lower quartile) | 25 | 0.25 |
| Median (Q2) | 50 | 0.5 |
| Q3 (upper quartile) | 75 | 0.75 |
| Maximum | 100 | 1.0 |
Syntax
python
np.percentile(a, q, axis=None, method="linear", keepdims=False) # q in 0..100
np.quantile(a, q, axis=None, method="linear", keepdims=False) # q in 0..1| Parameter | Meaning | Default |
|---|---|---|
a | input array | — required |
q | percentile(s) 0–100 for percentile; fraction(s) 0–1 for quantile. A single number or a list | — required |
axis | None (whole array) or an axis | None |
method | how to pick a value between two data points: "linear", "lower", "higher", "nearest", "midpoint", … | "linear" |
keepdims | keep reduced axes with size 1 | False |
Note: like
median, these are function-only — there is noa.percentile()method. In NumPy 2 the oldinterpolation=argument is replaced bymethod=.
Example — quartiles of Virat's season
python
import numpy as np
virat = np.array([72, 45, 88, 31, 64, 0, 103, 52, 19, 77])
print("sorted:", np.sort(virat))
q1, q2, q3 = np.percentile(virat, [25, 50, 75])
print("Q1 =", q1, " median =", q2, " Q3 =", q3)
print("same with quantile:", np.quantile(virat, [0.25, 0.5, 0.75]))
print("90th percentile:", np.percentile(virat, 90))
print("IQR (Q3 - Q1):", q3 - q1)text
sorted: [ 0 19 31 45 52 64 72 77 88 103]
Q1 = 34.5 median = 58.0 Q3 = 75.75
same with quantile: [34.5 58. 75.75]
90th percentile: 89.5
IQR (Q3 - Q1): 41.25How it works: with 10 sorted values, the 25th percentile sits at position 0.25 × (10 − 1) = 2.25 → between 31 and 45, a quarter of the way: 31 + 0.25 × 14 = 34.5. The IQR (interquartile range) is the spread of the middle 50% of innings — a spread measure that ignores the extreme duck and century.
Example — the method parameter
python
import numpy as np
runs = np.array([10, 20, 30, 40])
for m in ["linear", "lower", "higher", "nearest", "midpoint"]:
print(f"{m:<9}", np.percentile(runs, 40, method=m))text
linear 22.0
lower 20
higher 30
nearest 20
midpoint 25.0How it works: the 40th percentile position is 0.4 × 3 = 1.2 → between 20 (pos 1) and 30 (pos 2). linear gives 22.0, lower/higher pick a neighbour, nearest picks the closer one, midpoint averages the two.
Example — per-player percentiles and outlier detection
python
import numpy as np
scores = np.array([
[72, 45, 88, 31, 64],
[56, 0, 74, 88, 32],
[45, 32, 0, 67, 18],
[33, 61, 45, 0, 77],
])
print("75th percentile per player:", np.percentile(scores, 75, axis=1))
runs = np.array([12, 8, 15, 10, 14, 11, 150])
q1, q3 = np.percentile(runs, [25, 75])
iqr = q3 - q1
upper = q3 + 1.5 * iqr
print("upper fence:", upper, " outliers:", runs[runs > upper])text
75th percentile per player: [72. 74. 45. 61.]
upper fence: 20.5 outliers: [150]How it works: the 1.5 × IQR rule (used by box plots) flags any value above Q3 + 1.5×IQR (or below Q1 − 1.5×IQR) as an outlier. The 150 is clearly out of line with the rest.
Common mistakes
- ❌
np.quantile(a, 25)→ValueError: Quantiles must be in the range [0, 1]. ✅np.quantile(a, 0.25)ornp.percentile(a, 25). - ❌
np.percentile(a, 0.25)— runs fine but gives the 0.25th percentile (almost the min). ✅ Use 25 withpercentile. - ❌
a.percentile(50)→ AttributeError. ✅ It's function-only:np.percentile(a, 50). - ❌ Expecting the result to be one of the data values. ✅ With
method="linear"it can be in-between; use"nearest"/"lower"if you need an actual data point.
Comparison — percentile vs quantile vs median
| Function | q scale | Example | Same as |
|---|---|---|---|
np.percentile(a, 50) | 0–100 | 50 | np.median(a) |
np.quantile(a, 0.5) | 0–1 | 0.5 | np.median(a) |
np.percentile(a, [25, 75]) | list allowed | two values back | np.quantile(a, [0.25, 0.75]) |
Interview tip
Q: What is the IQR and why is it preferred over the range for skewed data? A: IQR = Q3 − Q1, the spread of the middle 50% of the data. The range (max − min) depends only on the two most extreme values, so one century or one duck changes it hugely; the IQR ignores the extremes, which makes it robust to outliers.
Key points to remember
- The p-th percentile is the value below which p% of the sorted data lies.
- np.percentile takes q from 0 to 100; np.quantile takes q from 0 to 1 — otherwise identical.
- The 50th percentile / 0.5 quantile is the median; 25 and 75 give the quartiles Q1 and Q3.
- By default (method='linear') NumPy interpolates between neighbouring sorted values.
- IQR = Q3 - Q1 is a robust spread measure; values beyond Q3 + 1.5×IQR or Q1 − 1.5×IQR are usual outlier candidates.
- percentile and quantile are function-only and accept a list of q values and an axis.
Try it yourself
Quartiles and IQR
Find outliers with the 1.5 × IQR rule
Comparing interpolation methods
Practice: 90th percentile per player
Revision Flashcards
Tap a card to flip it and see the answer.
