Confidence interval by hand

How sure are we about an average or a rate measured on a sample?

Lesson 24 min readFree, runs offline
On this page
  1. The problem
  2. What you will build from scratch
  3. The idea
  4. Walk through
  5. Your turn
  6. Check yourself
  7. In real job postings
  8. Next

Get the lesson files

The dataset, exercise.py, the solution and the test live in the open-source repo. You need only Python 3.9 or later.

git clone https://github.com/Ani19arya/analytics-from-scratch
cd analytics-from-scratch/phases/02-statistics-and-experiments/02-confidence-interval-by-hand
python3 test_lesson.py
Open this lesson on GitHub

The problem

Harbor Mealkits, a fictional meal delivery startup, ran an 18 order pilot in a new city and asked 400 customers whether they would reorder. Marcus, the operations lead, wants to tell the board "average order value is 56 dollars and 32% of customers would reorder" on Monday. A board member always asks the same follow up: how much could those numbers move if you measured again? You will build both intervals from the formula so you can answer with a range, not a single point.

Both files in data/ are synthetic, generated by make_data.py with a fixed seed. They are not real customers.

What you will build from scratch

  • sample_sd(values): the sample standard deviation with the n - 1 denominator.
  • critical_value(df, confidence): picks a t value from a small table for small samples, and the normal z value otherwise.
  • mean_ci(values, confidence): interval for a mean.
  • proportion_ci(successes, n, confidence): interval for a rate.
  • read_column(path, column): reads a numeric CSV column.

The idea

Any estimate from a sample has noise. A confidence interval is

estimate +/- critical value * standard error

The standard error is how much the estimate would wobble from sample to sample.

Mean. With sample mean xbar, sample standard deviation s and sample size n:

s  = sqrt( sum((x - xbar)^2) / (n - 1) )
SE = s / sqrt(n)
CI = xbar +/- t(df = n - 1) * SE

We divide by n - 1, not n, because the deviations are measured from xbar, which was fitted to the same data. That makes the plain average of squared deviations a little too small; n - 1 corrects it.

Why t and not z? With a small sample, s itself is uncertain. The t distribution has fatter tails than the normal to account for that, so its critical values are bigger. As df grows, t shrinks toward z: at 95% confidence t is 12.706 for df 1, 2.110 for df 17, 2.042 for df 30, while z is 1.96. This lesson stores t for df 1 to 30 in T_TABLE and uses z above 30, which is the usual textbook shortcut.

Proportion. With k successes out of n, p = k / n and

SE = sqrt( p * (1 - p) / n )
CI = p +/- z * SE

This is the normal approximation (often called the Wald interval). It works well when n * p and n * (1 - p) are both comfortably above about 10. Our survey has 129 yes and 271 no answers, so it qualifies.

Walk through

The standard deviation, step by step:

import math
vals = [2, 4, 4, 4, 5, 5, 7, 9]
mean = sum(vals) / len(vals)                      # 5.0
squared = sum((x - mean) ** 2 for x in vals)      # 32.0
print(math.sqrt(squared / (len(vals) - 1)))       # 2.138...

A mean interval for the numbers 1 to 10 (n = 10, df = 9, t = 2.262):

import math
vals = list(range(1, 11))
mean = sum(vals) / 10
s = math.sqrt(sum((x - mean) ** 2 for x in vals) / 9)
margin = 2.262 * s / math.sqrt(10)
print(round(mean - margin, 4), round(mean + margin, 4))   # 3.3343 7.6657

A proportion interval for 120 yes out of 400:

import math
p = 120 / 400
margin = 1.96 * math.sqrt(p * (1 - p) / 400)
print(round(p - margin, 4), round(p + margin, 4))         # 0.2551 0.3449

On the lesson data, python3 solution/solution.py prints:

  • Orders: n = 18, mean 55.89, sd 15.54, 95% CI from 48.17 to 63.62. With z instead of t the margin would be about 7.18 instead of about 7.73, a little too narrow and too confident.
  • Survey: 129 of 400 would reorder (32.25%). 95% CI from 27.67% to 36.83%. At 99% it widens to 26.23% to 38.27%.

What Marcus should say: "Average order value in the pilot was about 56 dollars, plausibly anywhere from 48 to 64. Between 28% and 37% of surveyed customers say they would reorder."

Your turn

Open exercise.py. The tables are given; write the five functions without the statistics module. Then run, from this folder:

python3 test_lesson.py

To see the reference solution pass: CHECK_SOLUTION=1 python3 test_lesson.py.

Check your numbers against the confidence interval calculator.

Check yourself

  1. What does a 95% confidence interval mean, in one sentence?
  2. Why does the interval get narrower as n grows, and by how much if you quadruple n?
  3. When should you use t instead of z?
Answers
  1. If we repeated the sampling many times and built an interval the same way each time, about 95% of those intervals would contain the true value. It is not a 95% chance that this particular interval contains it.
  2. The standard error has sqrt(n) in the denominator. Quadrupling n halves the standard error, so the interval is half as wide.
  3. For a mean when the population standard deviation is unknown and estimated from the sample, which is nearly always. The difference matters most for small samples, roughly under 30.

In real job postings

On 25 October 2026 the Real Analyst Jobs live feed had 2,848 live US analyst postings; of the 2,102 that list tools, 48% ask for Python, which is enough to compute intervals like these with no extra libraries. See Python for analyst jobs, and practise explaining intervals with the data analyst interview questions.

Next

03: A/B test from scratch

Put the skill to work

Real Analyst Jobs lists analyst roles read daily from company career pages, with the skills each posting asks for.

Browse analyst jobs

All lessons in Analytics from Scratch

Raj