A distribution describes where the values of a variable fall and how often. A percentile is a position in that distribution: the 90th percentile of help-desk response times is the time below which 90% of responses fall. Percentiles describe skewed data, such as response times, prices and file sizes, far better than a single average:
import numpy as np
minutes = np.array([1, 2, 3, 4, 20])
print(np.percentile(minutes, [50, 90])) # median and 90th percentileThis lesson covers distribution shape, calculating percentiles and quartiles with NumPy and the statistics module, why different tools can return slightly different answers, what to do about unusual observations, and how distributions change over time. The examples analyse response times at a library help desk.
Distribution shape
Three questions describe a distribution's shape:
- Centre: where is a typical value? (median)
- Spread: how far apart are typical values? (interquartile range, standard deviation)
- Shape: is it symmetric or skewed, with a long tail on one side? Does it have one peak or several (multimodal)?
Response times are usually right-skewed: most questions are answered in a few minutes, a few take much longer, and nothing takes less than zero. In right-skewed data the mean sits above the median, pulled up by the tail. Two help desks can share the same mean while one answers almost everyone within 5 minutes and the other answers half instantly and half after 20 minutes.
A histogram (see data visualization) shows the shape at a glance; percentiles summarise it in numbers. Report both centre and tail: "median 3 minutes, 90% within 14 minutes" tells a reader much more than "average 6 minutes".
Percentiles
The p-th percentile is the value below which p% of the data falls. Quartiles are the 25th, 50th (median) and 75th percentiles, and the interquartile range (IQR = Q3 − Q1) covers the middle half of the data:
import numpy as np
from statistics import quantiles
times = np.array([1, 2, 2, 3, 3, 4, 5, 7, 12, 25])
q1, median, q3 = np.percentile(times, [25, 50, 75])
print(q1, median, q3, q3 - q1) # 2.25 3.5 6.5 4.25
print(quantiles(times.tolist(), n=4)) # [2.0, 3.5, 8.25]With small samples, the 25th percentile usually falls between two data points, and tools must choose how to interpolate. NumPy's default method="linear" and the statistics module's default method="exclusive" use different rules, which is why the two lines above disagree on Q1 and Q3. Neither is wrong. Pick one method, name it in your report, and use the same method when comparing periods. NumPy supports several ("lower", "higher", "nearest", "midpoint", "median_unbiased" and more), and pandas' quantile() uses linear interpolation by default.
Outlier meaning
An unusually large or small observation can be:
- a data error: a timer left running overnight, a unit mix-up, a duplicated record;
- a real but rare event: a complicated research question that genuinely took an hour.
The 1.5 × IQR rule flags values above Q3 + 1.5 × IQR or below Q1 − 1.5 × IQR as worth checking. It's a screening tool, not a verdict.
q1, q3 = np.percentile(times, [25, 75])
limit = q3 + 1.5 * (q3 - q1)
print(times[times > limit]) # [25]Investigate before deciding. Deleting errors is right; deleting real long waits would hide exactly the problem a help-desk manager needs to see. When you do exclude values, report how many and why. Percentiles and medians are robust, meaning one extreme value barely moves them, so you can often keep outliers and still describe the typical case honestly.
Changing populations
Distributions aren't fixed. Response times change when staffing changes, when a new booking system launches, or simply between term time and holidays. A percentile calculated last spring may not describe this autumn.
spring = np.array([2, 3, 3, 4, 5, 6, 8])
autumn = np.array([3, 4, 6, 7, 9, 12, 18])
for label, data in [("spring", spring), ("autumn", autumn)]:
print(label, np.percentile(data, [50, 90]).round(1).tolist())Compare comparable periods (the same weeks of different terms, not a quiet week against an exam week) and check whether the measurement itself changed, for instance a new definition of when a question counts as "answered".
For machine learning, a shift between the training data's distribution and live data is called drift. A model trained on spring response times may systematically under-predict autumn ones. Monitoring the percentiles of key features over time is a simple, effective early warning.
Independent practice and a worked check
Task: report help-desk median and a high percentile, naming the calculation method and investigating unusually long observations.
import numpy as np
minutes = np.array([2, 3, 3, 4, 4, 5, 6, 6, 8, 9, 11, 45])
method = "linear"
p50, p90 = np.percentile(minutes, [50, 90], method=method)
q1, q3 = np.percentile(minutes, [25, 75], method=method)
long_ones = minutes[minutes > q3 + 1.5 * (q3 - q1)]
print(f"median {p50:.1f} min, 90th percentile {p90:.1f} min ({method} interpolation, n={len(minutes)})")
print("to investigate:", long_ones.tolist())This prints median 5.5 min, 90th percentile 10.8 min (linear interpolation, n=12) and flags the 45-minute response. Before removing it, check the ticket: if it was a complex request, keep it and mention it. For the worked check, percentile calculations differ between tools because they can use different interpolation conventions.
Reference and next practice
NumPy's percentile documentation lists every method, and Python's statistics.quantiles explains its defaults. Continue with linear regression and revisit summary statistics for ML. Practise with the Python exercises and Python quiz.
Data Distribution and Percentiles Summary
- Distribution shape: A distribution describes where values occur and how frequently, including skew and multiple clusters.
- Percentiles: A percentile summarizes a position within an ordered numeric distribution.
- Outlier meaning: An unusual observation may be an error or an important real event.
- Changing populations: A distribution can shift as users, processes or measurement rules change.
Data Distribution and Percentiles Examples
Each example shows the code, the output it produces and what each part does.
Data Distribution and Percentiles in a small program
This needs NumPy installed in your virtual environment. Note the second result:
import numpy as np
minutes = np.array([1, 2, 3, 4, 20])
print(float(np.percentile(minutes, 50)))
print(float(np.percentile(minutes, 90)))3.0
13.600000000000001Line-by-line explanation
- Line 3The 50th percentile of five values is the middle one, 3.
- Line 4The 90th percentile lies 60% of the way from 4 to 20 under linear interpolation: 4 + 0.6 × 16 = 13.6. Binary floating point prints it as 13.600000000000001; round it for display with
round(value, 1).
Comparing percentile methods and checking outliers
import numpy as np
from statistics import quantiles, median, mean
times = np.array([1, 2, 2, 3, 3, 4, 5, 7, 12, 25])
for method in ["linear", "lower", "nearest", "median_unbiased"]:
q1, q3 = np.percentile(times, [25, 75], method=method)
print(f"{method:<16} Q1={round(float(q1), 2):<5} Q3={round(float(q3), 2)}")
q1, q3 = np.percentile(times, [25, 75])
limit = q3 + 1.5 * (q3 - q1)
print("flag above", limit, "->", times[times > limit].tolist())
print("mean", mean(times.tolist()), "median", median(times.tolist()))
print("p90 linear:", round(float(np.percentile(times, 90)), 1))linear Q1=2.25 Q3=6.5
lower Q1=2.0 Q3=5.0
nearest Q1=2.0 Q3=7.0
median_unbiased Q1=2.0 Q3=7.42
flag above 12.875 -> [25]
mean 6.4 median 3.5
p90 linear: 13.3Line-by-line explanation
- Lines 6 to 8The same data gives different quartiles depending on the interpolation method.
- Lines 10 to 12The 1.5 × IQR rule flags only the 25-minute response for investigation.
- Line 13The mean is nearly double the median, confirming the right skew.
Common Data Distribution and Percentiles Mistakes
Deleting outliers automatically
q1, q3 = np.percentile(times, [25, 75])
times = times[times <= q3 + 1.5 * (q3 - q1)] # long waits silently vanishflagged = times[times > q3 + 1.5 * (q3 - q1)]
print(f"{len(flagged)} unusually long responses to investigate: {flagged.tolist()}")Comparing percentiles calculated with different methods
last_term = statistics.quantiles(old, n=4)[2] # exclusive method
this_term = np.percentile(new, 75) # linear method
print("Q3 changed by", this_term - last_term)last_term = np.percentile(old, 75)
this_term = np.percentile(new, 75) # same method for both
print("Q3 changed by", this_term - last_term)Data Distribution and Percentiles in Real Projects
Percentiles in practice
Service-level targets are often written as percentiles: "95% of support tickets answered within 4 hours", "99th percentile API latency under 300 ms". Percentiles reveal the experience of the slowest users, which averages hide. Salary surveys, house-price reports and growth charts for children all report percentiles because those distributions are skewed.
Monitoring dashboards track p50, p90 and p99 over time to spot regressions and drift. When they shift, the first questions are the ones from this lesson: did the population change, did the measurement change, or are the unusual values real problems?
Data Distribution and Percentiles FAQ
How do I calculate a percentile in Python?
With NumPy, np.percentile(data, 90) returns the 90th percentile, and a list such as [25, 50, 75] returns several at once. Without NumPy, statistics.quantiles(data, n=100) returns all percentile cut points. pandas offers series.quantile(0.9).
What is the difference between a percentile and a quartile?
Quartiles are three specific percentiles: Q1 is the 25th, Q2 (the median) the 50th and Q3 the 75th. They split sorted data into four equal-sized parts.
Why do NumPy and the statistics module give different quartiles?
They use different default interpolation rules when a percentile falls between two data points: NumPy uses linear, while statistics.quantiles uses exclusive. Both are valid; specify the same method whenever you compare results.
What does the 95th percentile mean?
95% of the observations are at or below that value and 5% are above it. For response times, it describes how long the slowest 1 in 20 users wait, which is why it's popular in service-level targets.
What is a skewed distribution?
One with a longer tail on one side. Right-skewed data, common for times, prices and incomes, has a few large values that pull the mean above the median. The median and percentiles describe such data better than the mean alone.
Data Distribution and Percentiles Exercises
Answer each one and check it instantly. If you get stuck, open the hint before the answer.
Why can percentile calculations differ between tools?
Which review concern is valid for data distribution and percentiles?
Data Distribution and Percentiles Quiz
2 questions to check what you learned.
Why can percentile calculations differ between tools?
- Percentiles are unrelated to ordering
- They can use different interpolation conventions
- Python ignores the distinction
Which statement correctly describes outlier meaning?
- An unusual observation may be an error or an important real event.
- Only the example output matters, not the rule
- Every operation has the same behavior