03-01: Mean, Median and Mode¶
A measure of central tendency answers "what is a typical value?" with a single number. There are four in common use, and choosing the wrong one is one of the easiest ways to mislead with a correct calculation.
The Arithmetic Mean¶
The sum of the values divided by how many there are.
Properties that matter later:
- The mean uses every value, so it is sensitive to extremes.
- The deviations from the mean always sum to zero:
Σ(x − x̄) = 0. This is why the variance squares them (04-01). - The mean minimizes
Σ(x − c)²over all choices ofc— it is the least-squares centre, the idea behind regression (13-02). x̄is an unbiased estimator ofμ— the foundation of Chapters 08–11.
The Median¶
The middle value when the data is sorted.
Sort the data, then:
n odd → median = the value at position (n + 1) / 2
n even → median = average of the values at positions n/2 and n/2 + 1
The median is a resistant (robust) measure: changing the largest value to any larger number does not move it at all.
The Mode¶
The value that occurs most often.
- No mode — every value occurs once.
- Unimodal — one value dominates.
- Bimodal — two values tie for most frequent (often a sign of two mixed subgroups).
- Multimodal — three or more.
The mode is the only centre available for nominal data (01-01).
The Midrange¶
Quick, but built from exactly the two most extreme values, so it is the least stable of the four. Useful as a rough check, never as the headline number.
Choosing the Right Measure¶
| Situation | Use | Why |
|---|---|---|
| Roughly symmetric, no outliers | Mean | Uses all the data; feeds into every later test |
| Skewed, or outliers present | Median | Resistant to the long tail |
| Nominal / categorical data | Mode | The only one defined |
| Ordinal data | Median or mode | Order exists, spacing does not |
| Reporting "typical income", "typical house price" | Median | Income distributions are strongly right-skewed |
| Quick range check | Midrange | Fast, crude |
Mean vs. median as a skewness diagnostic:
mean ≈ median → roughly symmetric
mean > median → right-skewed (long tail pulls the mean up)
mean < median → left-skewed (long tail pulls the mean down)
Pearson's coefficient of skewness turns that comparison into a number:
SK = 3 (x̄ − median) / s
|SK| < 1 → approximately symmetric
SK ≥ 1 → substantially right-skewed
SK ≤ −1 → substantially left-skewed
Worked Example¶
Nine annual salaries in a small firm (thousands of dollars):
n = 9, sorted already, Σx = 630
Mean x̄ = 630 / 9 = 70.0
Median = value at position (9+1)/2 = 5th = 48.0
Mode = 42 (appears twice; all others once)
Midrange = (38 + 248) / 2 = 143.0
Interpretation. The mean of 70 describes nobody: eight of the nine people earn less than it. One founder's salary of 248 drags it up. The median of 48 is the honest "typical salary". Mean (70) > median (48) confirms a strong right skew — exactly the pattern income data always shows.
Remove the 248 and recompute:
That contrast — the mean moves 15× further than the median — is the definition of resistance.
Excel¶
' ── The four measures ───────────────────────────────────────────────
=AVERAGE(A2:A10) ' mean -> 70
=MEDIAN(A2:A10) ' median -> 48
=MODE.SNGL(A2:A10) ' single mode -> 42
=MODE.MULT(A2:A10) ' ALL modes (spills; use for bimodal data)
=(MIN(A2:A10)+MAX(A2:A10))/2 ' midrange -> 143
' ── Guards and variants ─────────────────────────────────────────────
=AVERAGEIF(B2:B10, "Biology", A2:A10) ' mean of one subgroup
=AVERAGEIFS(A2:A10, B2:B10,"Biology", C2:C10,">=70")
=AVERAGEA(A2:A10) ' counts text as 0 — usually NOT what you want
=TRIMMEAN(A2:A10, 0.2) ' drops top & bottom 10% — a robust mean
=COUNT(A2:A10) ' n, numeric cells only
' ── Skewness check ──────────────────────────────────────────────────
=3*(AVERAGE(A2:A10)-MEDIAN(A2:A10))/STDEV.S(A2:A10) ' Pearson's SK
=SKEW(A2:A10) ' Excel's own (adjusted Fisher-Pearson) skewness
Note
AVERAGE ignores text and blank cells; AVERAGEA treats text as 0 and TRUE as 1. If your mean looks too low, check whether a number is stored as text (01-02).
Analysis ToolPak: Data ▸ Data Analysis ▸ Descriptive Statistics → tick Summary statistics to get mean, median, mode, standard deviation, skewness, kurtosis, range, min, max, sum, and count in one table.
R¶
salary <- c(38, 42, 42, 45, 48, 52, 55, 60, 248)
mean(salary) # 70
median(salary) # 48
range(salary) # 38 248
mean(range(salary)) # midrange -> 143
# R has no built-in mode() for statistics (mode() reports storage type),
# so define one:
stat_mode <- function(x) {
tab <- table(x)
as.numeric(names(tab)[tab == max(tab)]) # returns ALL modes
}
stat_mode(salary) # 42
# Robust variants
mean(salary, trim = 0.1) # 10% trimmed mean from each end
mean(salary, na.rm = TRUE) # ignore missing values
# Everything at once
summary(salary)
# Min. 1st Qu. Median Mean 3rd Qu. Max.
# 38.00 42.00 48.00 70.00 55.00 248.00
library(psych)
describe(salary) # n, mean, sd, median, trimmed, mad, min, max, skew, kurtosis
# Skewness diagnostics
3 * (mean(salary) - median(salary)) / sd(salary) # Pearson's SK -> 0.98
psych::skew(salary)
# By group
tapply(df$score, df$group, mean)
aggregate(score ~ group, data = df, FUN = median)
Python¶
import numpy as np
import pandas as pd
from scipy import stats
salary = pd.Series([38, 42, 42, 45, 48, 52, 55, 60, 248])
salary.mean() # 70.0
salary.median() # 48.0
salary.mode() # 0 42 (a Series — handles multimodal data)
(salary.min() + salary.max()) / 2 # midrange -> 143.0
# Robust variants
stats.trim_mean(salary, 0.1) # 10% trimmed mean
salary.mean(skipna=True) # missing values ignored by default
# Everything at once
salary.describe()
# count 9.000000
# mean 70.000000
# std 67.113709
# min 38.000000
# 25% 42.000000
# 50% 48.000000
# 75% 55.000000
# max 248.000000
# Skewness diagnostics
3 * (salary.mean() - salary.median()) / salary.std() # Pearson's SK
salary.skew() # adjusted Fisher-Pearson
# By group
df.groupby("major")["score"].mean()
df.groupby("major")["score"].agg(["mean", "median", "count"])
Quick Reference¶
| Measure | Formula | Excel | R | Python |
|---|---|---|---|---|
| Mean | Σx / n |
AVERAGE |
mean(x) |
s.mean() |
| Median | middle of sorted data | MEDIAN |
median(x) |
s.median() |
| Mode | most frequent | MODE.SNGL / MODE.MULT |
custom (table) |
s.mode() |
| Midrange | (min + max)/2 |
(MIN+MAX)/2 |
mean(range(x)) |
(s.min()+s.max())/2 |
| Trimmed mean | mean after dropping tails | TRIMMEAN |
mean(x, trim=) |
stats.trim_mean |
| Conditional mean | mean of a subgroup | AVERAGEIFS |
tapply / aggregate |
groupby().mean() |
| Skewness | 3(x̄ − med)/s |
SKEW |
psych::skew |
s.skew() |
| Full summary | — | ToolPak ▸ Descriptive Statistics | summary() / describe() |
s.describe() |
Common Mistakes¶
- Reporting the mean of strongly skewed data (salary, house price, waiting time) as "typical".
- Assuming there is always exactly one mode —
MODE.SNGLreturns only the first, hiding bimodality. - Forgetting to sort before finding a median by hand.
- Averaging averages: the mean of three class averages is not the overall mean unless the classes are the same size — that is what the weighted mean in 03-02 is for.
- Letting blank cells count as zeros (
AVERAGEA, or filling blanks with 0).
Exercises: 03-01: Exercises — Mean, Median and Mode
⬅️ Previous: 02-02: Graphical Displays ➡️ Next: 03-02: Weighted and Grouped Means