Statistics: percentile, median, std, var
Reviewed & published by Brayan K
Descriptive statistics summarize a dataset's center and spread, and NumPy gives you fast built-ins — mean, median, std, var, and percentile — that work on whole arrays or along any axis.
Part of the free NumPy course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
You'll compute centers and spread, control the divisor with ddof, read cut points with percentile and quantile, and measure relationships with corrcoef and cov.
What You'll Learn in This Lesson
- Center with mean and median
- Spread with std and var
- The ddof argument (population vs sample)
- Cut points with percentile and quantile
- Summarizing along an axis
- Relationships with corrcoef and cov
1 Center, Spread, and ddof
np.mean gives the average, np.median the middle value (robust to outliers), np.std the standard deviation, and np.var the variance. By default NumPy uses the population formula (divide by n). Pass ddof=1 for the sample formula (divide by n-1), which most statistics tools use.
import numpy as np
a = np.array([2, 4, 4, 4, 5, 5, 7, 9])
print(np.mean(a)) # 5.0
print(np.median(a)) # 4.5
print(np.std(a)) # 2.0 (population)
print(np.var(a)) # 4.0 (population)
# Sample versions divide by n-1
print(round(np.std(a, ddof=1), 4)) # 2.1381
print(round(np.var(a, ddof=1), 4)) # 4.5714
# ✅ Expected output:
# 5.0
# 4.5
# 2.0
# 4.0
# 2.1381
# 4.57142 Percentiles, Quantiles, and axis
A percentile is the value below which a given share of the data falls. np.percentile(a, 50) is the median; np.percentile(a, [25, 50, 75]) returns the quartiles in one call. np.quantile is identical but takes fractions from 0 to 1. Every statistic here accepts an axis argument to work down columns or across rows.
import numpy as np
data = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
print(np.percentile(data, 50)) # 5.5 (median)
print(np.percentile(data, 25)) # 3.25
print(np.percentile(data, [25, 50, 75])) # [3.25 5.5 7.75]
print(np.quantile(data, 0.5)) # 5.5
# Per-column and per-row stats on a 2D array
m = np.array([[1, 2, 3], [4, 5, 6]])
print(np.mean(m, axis=0)) # [2.5 3.5 4.5]
print(np.median(m, axis=1)) # [2. 5.]
# ✅ Expected output:
# 5.5
# 3.25
# [3.25 5.5 7.75]
# 5.5
# [2.5 3.5 4.5]
# [2. 5.]3 Correlation and Covariance
np.corrcoef measures how strongly two variables move together on a scale from -1 to 1; np.cov gives the unscaled covariance. Both return a matrix: the diagonal is each variable with itself and the off-diagonal is the relationship between them. A correlation of exactly 1 means a perfect straight-line relationship.
import numpy as np
x = np.array([1, 2, 3, 4, 5])
y = np.array([2, 4, 6, 8, 10]) # exactly twice x
print(np.corrcoef(x, y))
# [[1. 1.]
# [1. 1.]] perfect positive correlation
print(np.cov(x, y))
# [[ 2.5 5. ]
# [ 5. 10. ]]
# ✅ Expected output:
# [[1. 1.]
# [1. 1.]]
# [[ 2.5 5. ]
# [ 5. 10. ]]The off-diagonal 1 in the correlation matrix confirms y is a perfect linear function of x — exactly what you expect when y = 2x.
🎯 YOUR TURN: Fill in the Blanks
Replace each ___ so the program prints the mean and the median (the 50th percentile).
import numpy as np
v = np.array([10, 20, 30, 40, 50])
print(np.___(v)) # fill in: mean -> 30.0
print(np.___(v, 50)) # fill in: percentile -> 30.0
# Expected output:
# 30.0
# 30.0Expected output: 30.0 then 30.0. (Answers: mean, percentile.)
⚠️ Common Errors & Quick Reference
❌ Forgetting ddof=1 for sample statistics
NumPy defaults to the population formula, so its std/var differ from pandas or Excel.
✅ Fix: pass ddof=1 when your data is a sample of a larger population.
❌ Mixing up percentile and quantile scales
percentile wants 0–100, quantile wants 0–1; swapping them gives wrong results.
✅ Fix: use np.percentile(a, 90) or np.quantile(a, 0.9) — not quantile(a, 90).
| Task | Code |
|---|---|
| Average | np.mean(a) |
| Middle value | np.median(a) |
| Sample spread | np.std(a, ddof=1) |
| Quartiles | np.percentile(a, [25, 50, 75]) |
| Correlation | np.corrcoef(x, y) |
🎯 Mini Challenge: Summarize a Score Table
For a 3-student by 3-subject score table, compute each subject's mean and sample standard deviation (down the columns), plus the overall quartiles.
import numpy as np
scores = np.array([[70, 80, 90],
[60, 75, 85],
[88, 92, 79]])
# Per-subject mean and sample std (down columns)
print(np.mean(scores, axis=0).round(2)) # [72.67 82.33 84.67]
print(np.std(scores, axis=0, ddof=1).round(2)) # [14.19 8.74 5.51]
# Overall quartiles across all scores
print(np.percentile(scores, [25, 50, 75])) # [75. 80. 88.]
# ✅ Expected output:
# [72.67 82.33 84.67]
# [14.19 8.74 5.51]
# [75. 80. 88.]❓ Frequently Asked Questions
Lesson complete — statistics unlocked!
You can now describe data with mean, median, std, and var, choose population vs sample with ddof, read cut points with percentile/quantile, and measure relationships with corrcoef and cov.
Practice quiz
What does np.std compute by default (ddof=0)?
- The sample standard deviation
- The population standard deviation
- The variance
- The median
Answer: The population standard deviation. By default NumPy divides by n, giving the population standard deviation.
Which call gives the sample (n-1) standard deviation?
- np.std(a, ddof=1)
- np.std(a)
- np.std(a, ddof=0)
- np.var(a)
Answer: np.std(a, ddof=1). ddof=1 divides by n-1, the sample (Bessel-corrected) formula.
How is the median computed in NumPy?
- np.mean(a)
- np.std(a)
- np.median(a)
- np.var(a)
Answer: np.median(a). np.median returns the middle value, which is robust to outliers.
Which expression returns the median using percentile?
- np.percentile(a, 100)
- np.percentile(a, 25)
- np.percentile(a, 0)
- np.percentile(a, 50)
Answer: np.percentile(a, 50). The 50th percentile is the median.
What scale does np.quantile take for its q argument?
- A fraction from 0 to 1
- A number from 0 to 100
- A percentage string
- Any integer
Answer: A fraction from 0 to 1. np.quantile takes 0 to 1, so the median is np.quantile(a, 0.5).
On a 2D array, which axis gives one statistic per column?
- axis=1
- axis=0
- axis=-1
- axis=2
Answer: axis=0. axis=0 collapses the rows, producing one result per column.
What does np.var measure?
- The square root of the std
- The middle value
- The average squared deviation from the mean
- The maximum
Answer: The average squared deviation from the mean. Variance is the mean of squared differences from the mean; std is its square root.
What range does a Pearson correlation from np.corrcoef fall in?
- -1 to 1
- 0 to 1
- 0 to 100
- -100 to 100
Answer: -1 to 1. np.corrcoef returns correlations on a scale from -1 to 1.
np.percentile(a, [25, 50, 75]) returns what?
- A single number
- The mean
- The three quartiles in one call
- An error
Answer: The three quartiles in one call. Passing a list returns several cut points at once: the quartiles.
Why might NumPy's std differ from pandas or Excel by default?
- NumPy rounds differently
- NumPy uses ddof=0 (population) while they use ddof=1
- NumPy ignores some values
- NumPy sorts first
Answer: NumPy uses ddof=0 (population) while they use ddof=1. NumPy defaults to the population formula; pass ddof=1 to match sample-based tools.
Continue this course
- Previous: ufunc Methods (reduce, accumulate, outer)
- Next: Linear Algebra: solve, svd, eig — Solve systems and decompose matrices with numpy.linalg
- Quick reference: NumPy cheat sheet
Frequently asked questions
What is the difference between np.std and np.var?
Variance (np.var) is the average of the squared differences from the mean, and standard deviation (np.std) is the square root of the variance. They measure the same spread, but std is in the original units while var is in squared units. NumPy computes the population versions by default; pass ddof=1 to get the sample versions that divide by n-1.
What does the ddof argument do?
ddof stands for delta degrees of freedom and controls the divisor in variance and standard deviation. With the default ddof=0, NumPy divides by n (the population formula). With ddof=1 it divides by n-1 (the sample, or Bessel-corrected, formula) which gives an unbiased estimate when your data is a sample drawn from a larger population. Statistics packages usually default to ddof=1, so set it explicitly to match.
What is the difference between np.percentile and np.quantile?
They compute the same thing; the only difference is the scale of the input. np.percentile takes a number from 0 to 100, so the median is np.percentile(a, 50). np.quantile takes a fraction from 0 to 1, so the median is np.quantile(a, 0.5). Both accept a list to get several cut points at once and both support an axis argument for row- or column-wise results.