std & var: Measuring Consistency
Measure how spread out scores are with standard deviation and variance — population vs sample, the ddof parameter, and finding the most consistent player.
Watch the lesson
1 video on CodeWithMunnaX
Two batters can have exactly the same average and still be completely different players. One scores 48–52 every match; the other scores 0, 10, 100, 5, 135. The average hides this. To measure consistency you need a measure of spread — and the two standard ones are variance and standard deviation.
Definition
Variance (
var) is the average of the squared distances of each value from the mean. Standard deviation (std) is the square root of the variance, which brings the spread back into the original units (runs). A low std means values sit close to the mean (consistent); a high std means they are scattered (inconsistent).
- Distance from the mean — for each score,
score - mean. Some are positive, some negative. - Squared — squaring makes every distance positive and punishes big misses more.
- Square root — variance is in "runs²", which is hard to picture;
std = sqrt(var)is back in runs.
The formulas (for n values with mean μ):
text
variance = sum( (x - μ)² ) / (n - ddof)
std = sqrt(variance)Syntax
python
np.std(a, axis=None, ddof=0, keepdims=False) a.std(axis=None, ddof=0)
np.var(a, axis=None, ddof=0, keepdims=False) a.var(axis=None, ddof=0)| Parameter | Meaning | Default |
|---|---|---|
a | input array | — required |
axis | None = whole array, 0 = per column, 1 = per row | None |
ddof | "Delta Degrees of Freedom" — the divisor is n - ddof | 0 |
keepdims | keep the reduced axis with size 1 | False |
Population vs sample — what is ddof?
| Population std | Sample std | |
|---|---|---|
| When | your data is the whole group (all 10 matches Virat played) | your data is a sample used to estimate a bigger group |
| Divide by | n | n - 1 (Bessel's correction) |
| NumPy | a.std() → ddof=0 (default) | a.std(ddof=1) |
| Pandas default | — | df.std() uses ddof=1 |
Dividing by n - 1 makes the sample result slightly bigger, which corrects for the fact that a small sample usually underestimates the true spread.
Note: this is a classic surprise: NumPy's
std()and Pandas'.std()give different answers on the same numbers, because NumPy defaults toddof=0and Pandas toddof=1. Passddofexplicitly when the difference matters.
Example — same average, different consistency
This is the "measuring consistency" example from the course notebook:
python
import numpy as np
player_a = np.array([50, 48, 52, 49, 51])
player_b = np.array([0, 10, 100, 5, 135])
print("Player A:", player_a)
print(" mean =", player_a.mean(), " std =", round(float(player_a.std()), 2))
print("Player B:", player_b)
print(" mean =", player_b.mean(), " std =", round(float(player_b.std()), 2))text
Player A: [50 48 52 49 51]
mean = 50.0 std = 1.41
Player B: [ 0 10 100 5 135]
mean = 50.0 std = 56.3How it works: both means are 50.0. Player A's scores are within about 1–2 runs of 50, so std ≈ 1.41. Player B's scores are 50 runs away on average, so std ≈ 56.3. A captain picks A for a tight chase and B as a high-risk, high-reward gamble.
Example — computing it by hand (to see what std really is)
python
import numpy as np
x = np.array([50, 48, 52, 49, 51])
mean = x.mean()
deviations = x - mean
squared = deviations ** 2
print("deviations:", deviations)
print("squared :", squared)
print("variance :", squared.mean(), " np.var:", x.var())
print("std :", np.sqrt(squared.mean()), " np.std:", x.std())
print("sample var (ddof=1):", x.var(ddof=1))
print("sample std (ddof=1):", x.std(ddof=1))text
deviations: [ 0. -2. 2. -1. 1.]
squared : [0. 4. 4. 1. 1.]
variance : 2.0 np.var: 2.0
std : 1.4142135623730951 np.std: 1.4142135623730951
sample var (ddof=1): 2.5
sample std (ddof=1): 1.5811388300841898How it works: the squared deviations add to 10. Population variance divides by 5 → 2.0; sample variance divides by 4 → 2.5. The std is just the square root of each.
Example — consistency report for the squad
python
import numpy as np
players = ["Virat", "Rohit", "Hardik", "Shubman"]
scores = np.array([
[72, 45, 88, 31, 64],
[56, 0, 74, 88, 32],
[45, 32, 0, 67, 18],
[33, 61, 45, 0, 77],
])
means = scores.mean(axis=1)
stds = scores.std(axis=1)
for name, m, s in zip(players, means, stds):
print(f"{name:<8} avg {m:5.1f} std {s:5.1f}")
print("Most consistent :", players[stds.argmin()])
print("Least consistent:", players[stds.argmax()])text
Virat avg 60.0 std 20.0
Rohit avg 50.0 std 31.2
Hardik avg 32.4 std 22.9
Shubman avg 43.2 std 26.2
Most consistent : Virat
Least consistent: RohitHow it works: axis=1 gives one std per player (row). argmin/argmax return the position of the smallest/largest std, which we use to look up the player's name.
Common mistakes
- ❌ Judging players only by average. ✅ Same mean does not mean same behaviour — always check std alongside the mean.
- ❌ Expecting NumPy and Pandas std to match. ✅ NumPy uses
ddof=0, Pandas usesddof=1; set it explicitly. - ❌ Comparing a variance with a mean ("var is 800, mean is 50"). ✅ Variance is in squared units; compare the std with the mean.
- ❌
a.std(ddof=1)on a single value →nanplus a warning (divide by 0). ✅ A sample std needs at least 2 values.
Comparison — var vs std
var | std | |
|---|---|---|
| Units | squared (runs²) | original (runs) |
| Relationship | var = std ** 2 | std = sqrt(var) |
| Easy to interpret? | not really | yes — "typical distance from the average" |
| Used in | maths/ML formulas | reports, dashboards |
Interview tip
Q: What is the difference between np.std(x) and np.std(x, ddof=1)?
A: The first is the population standard deviation (divides by n); the second is the sample standard deviation (divides by n − 1, Bessel's correction). Use ddof=1 when your data is a sample from a larger population — it's also what Pandas and most statistics textbooks use by default.
Key points to remember
- Variance = average squared distance from the mean; standard deviation = square root of the variance.
- Low std = consistent (values near the mean); high std = inconsistent (values spread out).
- Two players with the same mean can have very different std — always look at both.
- NumPy's default ddof=0 gives the population std (divide by n); ddof=1 gives the sample std (divide by n - 1).
- Pandas .std() defaults to ddof=1, so its answer differs from NumPy's default.
- std is in the original units (runs); var is in squared units — report std.
- Use axis=1 for per-player spread and axis=0 for per-match spread.
Try it yourself
Same mean, different std
Population vs sample (ddof)
Most consistent player
Practice: which match was most inconsistent?
Revision Flashcards
Tap a card to flip it and see the answer.
