The normal distribution
Last updated
Measure the systolic blood pressure of ten thousand adults at a Klang Valley clinic, draw the histogram, and a familiar shape appears: one hump in the middle, falling away evenly on each side. Many biological measurements look like this. Adult height, birth weight, blood pressure, and the logarithm of many lab values all trace roughly the same bell. That shape has an exact mathematical form called the normal distribution, and it sits behind most of the statistics in this course. This lesson is about what the curve looks like, how to turn it into probabilities, how to read its tables and percentage points, and why so much of medical statistics leans on it.
Two things make the normal distribution worth a whole lesson. It describes the spread of real measurements well, and it has a single standard form you can look up once and reuse for any mean and any spread. Get comfortable reading areas under it now, and confidence intervals, P-values, and reference ranges later all become the same calculation in a new costume.
What is the normal distribution? Shape and properties
The normal curve is smooth, symmetric, and bell-shaped. Two numbers fix it completely: the mean , which sets where the peak sits, and the standard deviation , which sets how wide the bell spreads. Change and the whole curve slides left or right along the axis. Change and the curve gets taller and narrower (small ) or shorter and wider (large ). The centre and the spread are all you need to draw it.
A few properties follow from that shape, and they matter for everything below.
- It is symmetric about . The mean, the median, and the mode all sit at the same central point.
- It has one peak at the mean and tails that fall away on both sides. The tails get vanishingly thin but never reach zero, so in theory any value is possible.
- The total area under the curve is exactly 1. That area is the whole population, so an area is a proportion, and a proportion is a probability.
- It is set by two numbers only. Once you know and , the curve is determined.
The height of the curve at any value comes from one equation. Most readers never use it directly, because software and tables do the work, but here it is for reference.
The part that does the work is : the further is from the mean, the larger that squared distance, and the smaller the height. That is the bell falling away on both sides. You will not plug numbers into this by hand. What you do need is the area under it, and for that you change units.
Key term
The normal distribution is a symmetric bell-shaped curve fixed by its mean and standard deviation . The area under the whole curve is 1, so the area between any two values is the proportion of the population that falls there.
What is the standard normal deviate z?
There is one normal curve for blood pressure in mmHg, another for birth weight in grams, another for height in cm. Tabulating all of them is hopeless. The trick is that every normal curve becomes the same curve once you rescale it. Subtract the mean and divide by the standard deviation, and you measure each value by how many standard deviations it sits from the mean.
The result is the standard normal deviate, also called the SND or the z-score. A value one standard deviation above the mean has ; one below has ; a value at the mean has . Whatever the original units, has no units. It follows the standard normal distribution, the special normal curve with mean 0 and standard deviation 1.
This is the move that makes the normal distribution usable. You convert your measurement to a z-score, read the area for that z from one table, and convert back if you need the original units. Inverting the formula gives the way back:
Standardising does not change the picture, only the labels on the axis. The figure below draws the SBP curve once and puts two axes on it: the original measurement in mmHg along the bottom, and the matching z value along the top. A blood pressure of 143 mmHg sits at , 158 mmHg at . Reading off the top axis is the same as standardising in your head.
Draw the SBP curve with the original mmHg axis on the bottom and the z axis on top.
mu <- 128 sigma <- 15
# add a top axis at mu + z*sigma for z = -3..3
x <- seq(80, 176, length.out = 400)
plot(x, dnorm(x, mu, sigma), type = "l",
xlab = "Systolic BP (mmHg)", ylab = "Density")
axis(3, at = mu + (-3:3) * sigma, labels = -3:3)
mtext("z (standard normal deviate)", side = 3, line = 2.2)
abline(v = mu, lty = 3)Draw the SBP curve with the original mmHg axis on the bottom and the z axis on top.
import numpy as np from scipy.stats import norm import matplotlib.pyplot as plt mu, sigma = 128, 15
# add a twin x-axis labelled in z
x = np.linspace(80, 176, 400)
fig, ax = plt.subplots()
ax.plot(x, norm.pdf(x, mu, sigma))
ax.set_xlabel("Systolic BP (mmHg)"); ax.set_ylabel("Density")
ax2 = ax.twiny()
ax2.set_xlim(ax.get_xlim())
zt = np.array([-3, -2, -1, 0, 1, 2, 3])
ax2.set_xticks(mu + zt * sigma)
ax2.set_xticklabels(zt)
ax2.set_xlabel("z (standard normal deviate)")
plt.show()Key term
The standard normal deviate is the number of standard deviations a value lies from the mean, . It turns any normal distribution into the single standard normal curve, which has mean 0 and standard deviation 1.
What do areas under the curve mean, and how do you read them?
The proportion of a population in some range equals the area under the normal curve over that range. Equivalently, it is the probability that one randomly chosen person falls in that range. Three jobs cover almost everything: the area above a value, the area below a value, and the area between two values. Symmetry does most of the work, because the area below always equals the area above .
Run the calculations on systolic blood pressure (SBP) in a population of Malaysian adults. Take it as approximately normal with mean mmHg and standard deviation mmHg. The clinical threshold for stage 2 hypertension is 140 mmHg.
Worked example 1: how many adults are above 140 mmHg?
- Convert 140 to a z-score: .
- Look up the area above . It is 0.2119.
- So about 21.2% of adults have an SBP above 140 mmHg.
The first figure shades that upper tail: the area to the right of 140 mmHg. Lead with the picture, then read the number off the code.
Draw the SBP curve, shade the upper tail above 140 mmHg, and compute its area.
mu <- 128 sigma <- 15
z <- # standardise 140 # area above 140 = ?
x <- seq(80, 176, length.out = 400)
plot(x, dnorm(x, mu, sigma), type = "l",
xlab = "Systolic BP (mmHg)", ylab = "Density")
xs <- seq(140, 176, length.out = 100)
polygon(c(140, xs, 176), c(0, dnorm(xs, mu, sigma), 0),
col = "grey80", border = NA)
abline(v = 140, lty = 2)
z <- (140 - mu) / sigma # 0.80
pnorm(z, lower.tail = FALSE) # area above 140
# 0.2119Draw the SBP curve, shade the upper tail above 140 mmHg, and compute its area.
import numpy as np from scipy.stats import norm import matplotlib.pyplot as plt mu, sigma = 128, 15
z = # standardise 140 # area above 140 = ?
x = np.linspace(80, 176, 400)
y = norm.pdf(x, mu, sigma)
plt.plot(x, y)
plt.fill_between(x[x >= 140], y[x >= 140], alpha=0.3)
plt.axvline(140, linestyle="--")
plt.xlabel("Systolic BP (mmHg)"); plt.ylabel("Density")
plt.show()
z = (140 - mu) / sigma # 0.80
print(round(norm.sf(z), 4)) # area above 140
# 0.2119Now the lower tail. What proportion sit below 110 mmHg? The z-score is . By symmetry the area below equals the area above , which is 0.1151. So 11.5% fall below 110 mmHg. This time the shaded region is the left tail.
Shade the lower tail below 110 mmHg and compute its area.
mu <- 128 sigma <- 15
# area below 110 = ?
x <- seq(80, 176, length.out = 400)
plot(x, dnorm(x, mu, sigma), type = "l",
xlab = "Systolic BP (mmHg)", ylab = "Density")
xs <- seq(80, 110, length.out = 100)
polygon(c(80, xs, 110), c(0, dnorm(xs, mu, sigma), 0),
col = "grey80", border = NA)
abline(v = 110, lty = 2)
pnorm(110, mu, sigma) # area below 110
# 0.1151Shade the lower tail below 110 mmHg and compute its area.
import numpy as np from scipy.stats import norm import matplotlib.pyplot as plt mu, sigma = 128, 15
# area below 110 = ?
x = np.linspace(80, 176, 400)
y = norm.pdf(x, mu, sigma)
plt.plot(x, y)
plt.fill_between(x[x <= 110], y[x <= 110], alpha=0.3)
plt.axvline(110, linestyle="--")
plt.xlabel("Systolic BP (mmHg)"); plt.ylabel("Density")
plt.show()
print(round(norm.cdf(110, mu, sigma), 4)) # area below 110
# 0.1151Example
For the proportion between 110 and 140 mmHg, take the whole curve (area 1) and subtract the two tails: . About 67.3% of adults sit between 110 and 140 mmHg. The pattern for any "between" question is the same: one minus the two tails.
The middle figure shades that band directly, so you can see the 67.3% as the area between the two cut-offs rather than as a subtraction.
Shade the area between 110 and 140 mmHg and compute it.
mu <- 128 sigma <- 15
# area between 110 and 140 = ?
x <- seq(80, 176, length.out = 400)
plot(x, dnorm(x, mu, sigma), type = "l",
xlab = "Systolic BP (mmHg)", ylab = "Density")
xs <- seq(110, 140, length.out = 100)
polygon(c(110, xs, 140), c(0, dnorm(xs, mu, sigma), 0),
col = "grey80", border = NA)
abline(v = c(110, 140), lty = 2)
pnorm(140, mu, sigma) - pnorm(110, mu, sigma) # area between
# 0.6730Shade the area between 110 and 140 mmHg and compute it.
import numpy as np from scipy.stats import norm import matplotlib.pyplot as plt mu, sigma = 128, 15
# area between 110 and 140 = ?
x = np.linspace(80, 176, 400)
y = norm.pdf(x, mu, sigma)
plt.plot(x, y)
band = (x >= 110) & (x <= 140)
plt.fill_between(x[band], y[band], alpha=0.3)
plt.axvline(110, linestyle="--"); plt.axvline(140, linestyle="--")
plt.xlabel("Systolic BP (mmHg)"); plt.ylabel("Density")
plt.show()
print(round(norm.cdf(140, mu, sigma) - norm.cdf(110, mu, sigma), 4))
# 0.6730What are the normal tables, and how do you read them?
Before software was on every desk, you read these areas from a printed table, and the table still helps you picture what the functions return. A standard normal table gives the area in one tail for each value of . The rows give to one decimal place, and the columns give the second decimal. To find the area above , go to row 0.8 and column 0.00.
| z | .00 | .01 | .02 | .03 | .04 | .05 |
|---|---|---|---|---|---|---|
| 0.8 | 0.2119 | 0.2090 | 0.2061 | 0.2033 | 0.2005 | 0.1977 |
| 0.9 | 0.1841 | 0.1814 | 0.1788 | 0.1762 | 0.1736 | 0.1711 |
| 1.0 | 0.1587 | 0.1562 | 0.1539 | 0.1515 | 0.1492 | 0.1469 |
| 1.1 | 0.1357 | 0.1335 | 0.1314 | 0.1292 | 0.1271 | 0.1251 |
| 1.2 | 0.1151 | 0.1131 | 0.1112 | 0.1093 | 0.1075 | 0.1056 |
Each cell is the area in the upper tail, that is the proportion of the population beyond that z. Row 0.8 and column .00 gives 0.2119, the figure from worked example 1. Row 1.2 and column .05 gives 0.1056, which you will use for birth weight below. The table only lists positive z. For a negative z, use symmetry: the area below equals the area above in the same cell.
You can also read the table backwards. Start with a tail area and find the z that produces it. Scan the body of a fuller table for 0.05 and you land near : about 5% of the population lies beyond 1.64 standard deviations above the mean. That backwards reading is how you find the value that only the top 5% exceed, which we use next.
Tip
Some books print the area below z instead of above. Always check the small diagram at the top of the table to see which tail is shaded. In R and Python you set it directly: pnorm(z) and norm.cdf(z) give the area below; pnorm(z, lower.tail = FALSE) and norm.sf(z) give the area above.
What is the 68-95-99.7 rule?
Some z-scores come up so often they are worth memorising. Because the curve is fixed, the proportion within a given number of standard deviations of the mean is always the same, whatever the measurement.
- About 68% of the population lies within 1 standard deviation of the mean (between and ). The exact figure is 68.27%.
- About 95% lies within 2 standard deviations. The exact figure is 95.45%.
- About 99.7% lies within 3 standard deviations, exactly 99.73%.
The figure below shades the three bands on the standard normal curve at once: the dark inner band is within 1 SD, the next is within 2 SD, and the outer is within 3 SD. The nested shading is the rule made visible.
Draw the standard normal curve with the +/- 1, 2, 3 SD bands shaded.
z <- seq(-4, 4, length.out = 400)
# shade -k..k for k = 3, 2, 1
plot(z, dnorm(z), type = "l",
xlab = "z (standard deviations from mean)", ylab = "Density")
shades <- c("grey85", "grey70", "grey50")
for (k in c(3, 2, 1)) {
xs <- seq(-k, k, length.out = 200)
polygon(c(-k, xs, k), c(0, dnorm(xs), 0),
col = shades[k], border = NA)
}
lines(z, dnorm(z))
abline(v = c(-3, -2, -1, 1, 2, 3), lty = 3)Draw the standard normal curve with the +/- 1, 2, 3 SD bands shaded.
import numpy as np from scipy.stats import norm import matplotlib.pyplot as plt z = np.linspace(-4, 4, 400)
# shade -k..k for k = 3, 2, 1
y = norm.pdf(z)
plt.plot(z, y)
for k, a in zip([3, 2, 1], [0.2, 0.35, 0.55]):
band = (z >= -k) & (z <= k)
plt.fill_between(z[band], y[band], alpha=a, color="steelblue")
for v in [-3, -2, -1, 1, 2, 3]:
plt.axvline(v, linestyle=":", linewidth=0.8)
plt.xlabel("z (standard deviations from mean)"); plt.ylabel("Density")
plt.show()This is the 68-95-99.7 rule, and it is the reason the standard deviation is such a useful summary of spread. For the SBP example (mean 128, SD 15), roughly 68% of adults fall between 113 and 143 mmHg, and roughly 95% between 98 and 158 mmHg. A reading three standard deviations out, below 83 or above 173 mmHg, is rare: about 3 people in 1,000.
Try it
Areas under the normal curve
A cutoff of mmHg sits SD from the mean, so about of adults fall below it: the shaded area. Slide to 140 mmHg and you see the 78.8% below, leaving the 21.2% above that worked example 1 found.
Standardise to a z-score and any "how many below, above, or between" question becomes an area under this one curve. That is the whole job of the normal table.
Watch out
The "95% within 2 SD" line is a rounded version. The value that traps exactly 95%, with 2.5% in each tail, is , not 2. The exactly-99% value is , not 3. Use 1.96 and 2.58 in real reference ranges and confidence intervals; use the round numbers only for a quick mental picture.
Confirm the 68-95-99.7 percentages, then find the exact z values for 95% and 99%.
within <- c(1, 2, 3)
prob <- # area between -within and +within
prob <- pnorm(within) - pnorm(-within) round(prob * 100, 2) # 68.27 95.45 99.73 qnorm(0.975) # exact 95% two-sided point 1.959964 qnorm(0.995) # exact 99% two-sided point 2.575829
Confirm the 68-95-99.7 percentages, then find the exact z values for 95% and 99%.
import numpy as np from scipy.stats import norm within = np.array([1, 2, 3])
prob = # area between -within and +within
prob = norm.cdf(within) - norm.cdf(-within) print(np.round(prob * 100, 2)) # [68.27 95.45 99.73] print(round(norm.ppf(0.975), 4)) # 1.96 print(round(norm.ppf(0.995), 4)) # 2.5758
A patient's systolic blood pressure converts to a z-score of +2.0 against the reference population. Roughly what fraction of that population has a higher blood pressure than this patient?
What are percentage points and reference ranges?
Reading the table backwards gives the percentage points of the normal distribution: the z value that cuts off a stated tail area. The two-sided 5% point is 1.96, because 5% of the curve lies beyond 1.96 SD from the mean, split as 2.5% in each tail. The two-sided 1% point is 2.58. The two-sided 10% point is 1.64. These three numbers run through the rest of the course, so they are worth knowing on sight.
The points just described are two-sided percentage points: they count extreme values in both tails at once. The two-sided 5% point of 1.96 puts 2.5% in the upper tail and 2.5% in the lower tail. Some tables instead give one-sided percentage points, which count one tail only. The rule connecting them is short: a one-sided a% point equals a two-sided 2a% point. So 1.96 is the one-sided 2.5% point and the two-sided 5% point at the same time, and 1.64 is the one-sided 5% point and the two-sided 10% point. Decide which tail your question is about before you read a value. A "top 5% only" cut-off is one-sided and uses 1.64; a symmetric 95% range is two-sided and uses 1.96.
The figure makes the difference concrete. The two grey tails together are the two-sided 5% beyond 1.96. The single dotted line at 1.64 marks the one-sided 5% point: 5% of the curve lies above it on that one side alone.
Shade the two-sided 5% tails at +/- 1.96 and mark the one-sided 5% point 1.64.
z <- seq(-4, 4, length.out = 400)
# shade beyond -1.96 and +1.96; add a line at 1.64
plot(z, dnorm(z), type = "l", xlab = "z", ylab = "Density") right <- seq(1.96, 4, length.out = 100) polygon(c(1.96, right, 4), c(0, dnorm(right), 0), col = "grey70", border = NA) left <- seq(-4, -1.96, length.out = 100) polygon(c(-4, left, -1.96), c(0, dnorm(left), 0), col = "grey70", border = NA) lines(z, dnorm(z)) abline(v = c(-1.96, 1.96), lty = 2) # two-sided 5% abline(v = 1.64, lty = 3) # one-sided 5% text(1.96, 0.06, "1.96 (two-sided 5%)", pos = 4, cex = 0.8) text(1.64, 0.20, "1.64 (one-sided 5%)", pos = 2, cex = 0.8)
Shade the two-sided 5% tails at +/- 1.96 and mark the one-sided 5% point 1.64.
import numpy as np from scipy.stats import norm import matplotlib.pyplot as plt z = np.linspace(-4, 4, 400)
# shade beyond -1.96 and +1.96; add a line at 1.64
y = norm.pdf(z)
plt.plot(z, y)
plt.fill_between(z[z >= 1.96], y[z >= 1.96], alpha=0.4, color="grey")
plt.fill_between(z[z <= -1.96], y[z <= -1.96], alpha=0.4, color="grey")
plt.axvline(1.96, linestyle="--"); plt.axvline(-1.96, linestyle="--")
plt.axvline(1.64, linestyle=":")
plt.text(2.0, 0.06, "1.96 (two-sided 5%)")
plt.text(-3.9, 0.20, "1.64 (one-sided 5%)")
plt.xlabel("z"); plt.ylabel("Density")
plt.show()Percentage points let you build a reference range: the band of values that a stated proportion of a healthy population falls inside. The 95% reference range runs from to .
For SBP that is , which gives 98.6 to 157.4 mmHg. A reading inside that band is unremarkable; one outside it is in the most extreme 5% of the population. Swap in 1.64 for a 90% range or 2.58 for a 99% range.
Worked example 2: birth weight and low birth weight
Birth weight at a Malaysian maternity unit is approximately normal with mean g and standard deviation g. Low birth weight is defined as under 2500 g. Two questions: what proportion of babies are low birth weight, and what is the 95% reference range for birth weight?
- Standardise 2500 g: .
- The area below equals the area above . Row 1.2, column .05 of the table gives 0.1056.
- So about 10.6% of babies are low birth weight.
- For the 95% reference range: , which is 2216 g to 3784 g.
You would expect 95% of babies to weigh between roughly 2.2 and 3.8 kg, and about 1 in 9 to fall under the low birth weight line. If a clinic in a poorer district reports far more than 10.6% low birth weight, that gap is worth investigating rather than waving away as chance.
Find the proportion of low birth weight babies and the 95% reference range.
mu <- 3000 # mean birth weight (g) sigma <- 400 # standard deviation (g)
z <- # standardise 2500 # proportion below 2500 = ?
z <- (2500 - mu) / sigma # -1.25 pnorm(z) # proportion below 2500 g # 0.1056 mu + c(-1, 1) * 1.96 * sigma # 95% reference range # 2216 3784
Find the proportion of low birth weight babies and the 95% reference range.
import numpy as np from scipy.stats import norm mu, sigma = 3000, 400
z = # standardise 2500 # proportion below 2500 = ?
z = (2500 - mu) / sigma # -1.25 print(round(norm.cdf(z), 4)) # 0.1056 ref = mu + np.array([-1, 1]) * 1.96 * sigma print(ref) # [2216. 3784.]
The percentage point also answers "what value does only the top 5% exceed?". This is a one-sided question, so it uses 1.64. Using with , the SBP exceeded by just 5% of adults is mmHg. Read a tail area as a z, then convert the z back to your own units.
Why does the normal distribution matter in practice?
The first reason is the one this lesson has shown: many measurements are roughly normal, so the curve gives a fast, honest summary. From a mean and a standard deviation alone you can state reference ranges and the proportion above or below any cut-off, without listing every individual.
The deeper reason is the central limit theorem. It says that the sampling distribution of a mean is approximately normal once the sample is not too small, even when the individual measurements are not normal at all. Triceps skinfold thickness is right-skewed, yet the mean of 30 of them behaves normally. In most settings a sample of about 15 or more is enough. This is why normal-based methods reach far beyond variables that happen to look bell-shaped.
That theorem is the engine under most of what follows. Confidence intervals use 1.96 standard errors because the sampling distribution is normal. P-values come from normal tail areas. Methods for proportions and rates, which you meet later, lean on normal approximations too.
Z-scores also do direct clinical work in growth and reference charts. Paediatric growth standards express a child's weight-for-age, height-for-age, or weight-for-height as a z-score against reference values for that age and sex, so the analysis runs on the z-scores rather than the raw kilograms. Take a 12-month-old boy who weighs 8.5 kg, where the reference weight-for-age is a mean of 9.6 kg with a standard deviation of 1.1 kg. His z-score is , one standard deviation below the median, which is well inside the normal range. A z below -2 (the one-sided 2.5% point) flags underweight and prompts a closer look. Because the number is unit-free, a paediatrician in Kota Bharu and one in Geneva read it the same way.
Watch out
Not every variable is normal. Hospital length of stay, viral load, and CD4 counts are usually right-skewed, with a long upper tail. Forcing a normal reference range on skewed data produces a lower limit below zero, which is meaningless for a count or a duration. Check the shape first (Chapter 12 covers how), and consider a log transformation before reaching for normal methods.
A study reports a mean fasting glucose with a standard error, and builds a 95% confidence interval for the population mean using ±1.96 standard errors, even though individual glucose readings in the sample are clearly right-skewed. Is that defensible?
Common mistakes
- Forgetting to standardise. The tables and the 1.96 rule are for the standard normal curve. You must convert your value to first. Reading a raw blood pressure of 140 straight off a z-table is meaningless.
- Dividing by the variance instead of the standard deviation. The z formula divides by , not . With SD 15, that is dividing by 15, not 225. A quick check: a z-score for a typical value should land between about −3 and +3.
- Mixing up the tail. "Above 140" is the upper area; "below 110" is the lower area. For a negative z, the area you want is usually the one your table does not print, so use symmetry. Confusing the two turns a 2% answer into a 98% answer.
- Confusing one-sided and two-sided points. A symmetric 95% range uses the two-sided 5% point 1.96; a one-tailed "top 5% only" cut-off uses the one-sided 5% point 1.64. Reach for 1.96 when the question has two tails and 1.64 when it has one.
- Using 2 where you need 1.96. The 68-95-99.7 rule is a memory aid. A reported 95% reference range or confidence interval uses 1.96; the two-standard-deviation version actually covers 95.45%.
- Assuming normality without looking. Skewed measurements like length of stay or viral load are not normal. A normal reference range on them can dip below zero, a sign you applied the wrong model.
Tips
- Memorise three percentage points: 1.64 (two-sided 10%, one-sided 5%), 1.96 (two-sided 5%), and 2.58 (two-sided 1%). They reappear in every confidence interval and significance test ahead.
- When a question gives you a value and asks for a proportion, go forwards: standardise to z, then read the area. When it gives a proportion and asks for a value, go backwards: read the z for that area, then use .
- Sketch the curve and shade the area you want before you compute. A 30-second drawing catches almost every tail and symmetry error.
- Let software handle the lookups.
pnormandqnormin R,norm.cdfandnorm.ppfin Python, replace the printed table and avoid interpolation slips. Keep the table in mind only to picture what they return. - The standard deviation drives the spread of individuals; the standard error drives the spread of the mean. Reference ranges use the SD, confidence intervals use the SE. The next lesson builds on that difference.