W3docs

Percentiles in Python with NumPy

Learn how to calculate percentiles in Python using NumPy. Covers quartiles, IQR outlier detection, interpolation methods, and practical ML use cases.

A percentile tells you the value below which a given percentage of observations in your dataset fall. If a student scores at the 80th percentile on an exam, 80 % of scores are below theirs. Percentiles are a cornerstone of exploratory data analysis and are used in machine learning for outlier detection, feature clipping, and reporting model performance across subgroups.

This chapter covers:

  • What a percentile is and how it is calculated
  • How to use numpy.percentile() and numpy.quantile()
  • Quartiles and the five-number summary
  • The interquartile range (IQR) for outlier detection
  • Interpolation methods and when they matter
  • Finding the percentile rank of a specific value with SciPy
  • Practical ML use cases: winsorization and data clipping

What Is a Percentile?

A percentile divides a sorted dataset into 100 equal parts. The P-th percentile is the value at or below which P percent of the data falls.

PercentileCommon nameMeaning
25thQ1 (first quartile)25 % of values are below this point
50thQ2 / MedianHalf the values are below this point
75thQ3 (third quartile)75 % of values are below this point
90th90 % of values are below this point

Percentiles are closely related to mean, median, and mode: the 50th percentile is exactly the median.

Percentile vs. quantile

The terms are often used interchangeably. A quantile expresses the same idea using a fraction from 0 to 1 instead of a percentage from 0 to 100:

  • The 25th percentile = the 0.25 quantile
  • The 75th percentile = the 0.75 quantile

NumPy provides both np.percentile() and np.quantile(). They behave identically; choose whichever makes your code clearer.

Calculating a Percentile with NumPy

numpy.percentile(a, q) takes an array-like a and a percentile q (0–100) and returns the interpolated value at that position.

Calculate the 75th percentile of a dataset

import numpy as np

data = [10, 20, 30, 40, 50]
result = np.percentile(data, 75)
print(result)  # Output: 40.0

Pass a list to q to calculate multiple percentiles in one call — NumPy returns them in an array:

Calculate the 25th, 50th, and 75th percentiles at once

import numpy as np

data = [10, 20, 30, 40, 50]
p25, p50, p75 = np.percentile(data, [25, 50, 75])
print(f'Q1 = {p25}')  # Output: Q1 = 20.0
print(f'Q2 = {p50}')  # Output: Q2 = 30.0
print(f'Q3 = {p75}')  # Output: Q3 = 40.0

Using np.quantile()

np.quantile() accepts a fraction (0.0–1.0) instead of a percentage:

Use np.quantile() with a fraction argument

import numpy as np

data = [10, 20, 30, 40, 50]
q1 = np.quantile(data, 0.25)
q3 = np.quantile(data, 0.75)
print(f'Q1 = {q1}')  # Output: Q1 = 20.0
print(f'Q3 = {q3}')  # Output: Q3 = 40.0

Quartiles and the Five-Number Summary

The three quartiles (Q1, Q2, Q3) together with the minimum and maximum form the five-number summary — a compact snapshot of any dataset's spread. You can compute all five values in a single call:

Compute the five-number summary

import numpy as np

data = [10, 20, 30, 40, 50]
minimum, q1, median, q3, maximum = np.percentile(data, [0, 25, 50, 75, 100])

print(f'Min    = {minimum}')   # Output: Min    = 10.0
print(f'Q1     = {q1}')        # Output: Q1     = 20.0
print(f'Median = {median}')    # Output: Median = 30.0
print(f'Q3     = {q3}')        # Output: Q3     = 40.0
print(f'Max    = {maximum}')   # Output: Max    = 50.0

The five-number summary is the foundation of a box plot, which you can draw with Matplotlib (see Matplotlib Histograms for related visualization techniques).

The Interquartile Range and Outlier Detection

The interquartile range (IQR) is the distance between Q1 and Q3:

IQR = Q3 − Q1

It describes the spread of the middle 50 % of the data. Because it ignores the top and bottom quarters, the IQR is robust to extreme values — making it the standard tool for rule-based outlier detection.

The Tukey fence rule flags any value more than 1.5 × IQR beyond either quartile as a potential outlier:

  • Lower fence: Q1 − 1.5 × IQR
  • Upper fence: Q3 + 1.5 × IQR

Detect outliers using the IQR method

import numpy as np

data = [5, 7, 8, 9, 10, 11, 12, 13, 14, 80]

q1 = np.percentile(data, 25)
q3 = np.percentile(data, 75)
iqr = q3 - q1

lower_fence = q1 - 1.5 * iqr
upper_fence = q3 + 1.5 * iqr

outliers = [x for x in data if x < lower_fence or x > upper_fence]

print(f'Q1 = {q1}, Q3 = {q3}, IQR = {iqr}')
# Output: Q1 = 8.25, Q3 = 12.75, IQR = 4.5

print(f'Lower fence = {lower_fence}, Upper fence = {upper_fence}')
# Output: Lower fence = 1.5, Upper fence = 19.5

print(f'Outliers: {outliers}')
# Output: Outliers: [80]

The value 80 is well beyond the upper fence of 19.5, so it is flagged as an outlier. The IQR method is widely used because it requires no assumptions about the underlying data distribution.

Interpolation Methods

When the requested percentile falls between two data points, NumPy interpolates. The method parameter (added in NumPy 1.22, replacing the older interpolation parameter) controls how this is done.

Compare interpolation methods at the 35th percentile

import numpy as np

data = [10, 20, 30, 40, 50]
# The 35th percentile falls between 20 (index 1) and 30 (index 2)

print(np.percentile(data, 35, method='linear'))    # Output: 24.0  (default)
print(np.percentile(data, 35, method='lower'))     # Output: 20
print(np.percentile(data, 35, method='higher'))    # Output: 30
print(np.percentile(data, 35, method='midpoint'))  # Output: 25.0
print(np.percentile(data, 35, method='nearest'))   # Output: 20
MethodDescriptionWhen to use
linearWeighted average of the two surrounding valuesDefault; most statistically correct
lowerReturns the lower of the two surrounding valuesInteger indices required
higherReturns the higher of the two surrounding valuesConservative upper bounds
midpointAverage of lower and higherSimple mid-range reporting
nearestNearest actual data pointWhen the result must be a real observation

For most data analysis and ML work, the default linear method is the right choice.

Finding the Percentile Rank of a Value

Sometimes you have the reverse question: given a value, what percentile is it at? Use scipy.stats.percentileofscore():

Find what percentile rank a specific value occupies

from scipy import stats

data = [10, 20, 30, 40, 50]

rank = stats.percentileofscore(data, 30)
print(rank)  # Output: 60.0

rank_of_25 = stats.percentileofscore(data, 25)
print(rank_of_25)  # Output: 40.0

A score of 30 is at the 60th percentile — meaning 60 % of the values in data are at or below 30.

Practical ML Use Case: Winsorization

Winsorization (also called clipping) caps extreme values at a chosen percentile boundary instead of removing them. This preserves the row count while limiting the influence of outliers on model training.

Clip outliers to the 10th–90th percentile range

import numpy as np

data = [10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 200]

lower = np.percentile(data, 10)
upper = np.percentile(data, 90)

clipped = np.clip(data, lower, upper)

print(f'Lower bound (10th): {lower}')  # Output: Lower bound (10th): 20.0
print(f'Upper bound (90th): {upper}')  # Output: Upper bound (90th): 100.0
print('Clipped:', list(clipped))
# Output: Clipped: [20.0, 20.0, 30.0, 40.0, 50.0, 60.0, 70.0, 80.0, 90.0, 100.0, 100.0]

Both extreme values — 10 (below the 10th percentile boundary of 20) and 200 (above the 90th percentile boundary of 100) — are capped at the fence value. Winsorization is a common preprocessing step before training linear models or neural networks, especially on financial or sensor data where extreme readings are common.

For more on feature scaling approaches that complement percentile-based clipping, see the Scale chapter.

Quick Reference

TaskFunctionExample
Single percentilenp.percentile(data, q)np.percentile(data, 75)
Multiple percentilesnp.percentile(data, [q1, q2, …])np.percentile(data, [25, 50, 75])
Quantile (0–1 scale)np.quantile(data, q)np.quantile(data, 0.75)
Five-number summarynp.percentile(data, [0,25,50,75,100])
IQRQ3 − Q1np.percentile(data, 75) - np.percentile(data, 25)
Percentile rank of a valuescipy.stats.percentileofscore(data, v)
Clip to percentile boundsnp.clip(data, lower, upper)np.clip(data, p10, p90)
  • Mean, Median, and Mode — central tendency measures; the 50th percentile is the median.
  • Standard Deviation — measure spread around the mean; complements the IQR.
  • Data Distribution — understand skew and outliers before choosing summary statistics.
  • Scale — feature scaling techniques for ML preprocessing.
  • NumPy Tutorial — foundational NumPy skills used throughout this chapter.

Conclusion

Percentiles rank values within a dataset and expose its shape in ways that mean and standard deviation cannot. With numpy.percentile(), computing Q1, Q2, Q3, and IQR takes a single line of Python. In machine learning, percentiles appear at every stage: in exploratory data analysis to spot outliers, in preprocessing to winsorize extreme values, and in evaluation to understand model accuracy across the distribution of your data. Mastering them gives you a reliable, assumption-free tool that works on any dataset regardless of its distribution.

Was this page helpful?