Index Ai Academy
Phase 2 · Math, when you need it · Probability & statistics

Samples and confidence

Estimate from a sample and say how sure you are.

About 30 minutes · A free account opens the whole lesson

Create a free account Try part of it here

Already have an account? Sign in to open this lesson

Why it matters

Almost every number you get from data is a guess. A conversion rate comes from last week's visitors. An eval score comes from 50 test questions. A satisfaction score comes from 200 survey replies. Measure again on different people or questions and you'd get a slightly different number. This lesson shows you how big that wobble is. Then "the new prompt scored 84% vs 80%" becomes either "that's a real improvement" or "that's within the noise of 50 questions". It's the most useful statistics habit for anyone shipping AI features.

What you'll be able to do

  • Explain why an estimate from a sample varies, and how much (the standard error)
  • Compute a 95% confidence interval for a mean and for a rate
  • Use the bootstrap to get an interval for any statistic
  • Work out how many observations you need for a given precision

What it covers

  1. Samples vary
  2. How much do estimates wobble?
  3. Confidence intervals
  4. The bootstrap: intervals for anything
  5. How much data do you need?
  6. Worked example: an email open rate

Samples vary

When you cook soup, you don't drink the whole pot to check the salt. You taste one spoonful. If the soup is well stirred, the spoonful tells you about the pot. But two spoonfuls never taste exactly the same.

Data works the same way. Three words name the parts:

  • The population is everything you care about: the whole pot. For a shop, that's all future visitors.
  • The sample is the part you actually measured: the spoonful. Say, last week's 2,000 visitors.
  • An estimate is a number worked out from the sample, like the conversion rate (the share of visitors who buy). It stands in for the true value in the population.

Take another sample and the estimate comes out a bit different. That's normal. The useful question is how different it could be. The widget below lets you see it.

Try it now

Each run is 1,000 experiments. Each one measures the conversion rate from n visitors. Raise the visitors per experiment and watch the spread of measured rates shrink.

Quick check
In the widget, you raise the visitors per experiment from 500 to 2,000. What happens to the spread of measured rates?
  1. It gets narrower: about half as wide
  2. It gets wider, because there are more visitors
  3. It shrinks to zero
  4. It stays the same
Show the answer

It gets narrower: about half as wide

More visitors per experiment means each measured rate lands closer to the true rate. Four times the visitors makes the spread about half as wide. You'll see why next.

How much do estimates wobble?

The typical size of that wobble has a name: the standard error, or SE. It is the standard deviation of the estimate. You met standard deviation in an earlier lesson: the usual distance of a value from the average. Here the "values" are the estimates you'd get from many different samples.

You only have one sample, so you can't run it a thousand times. Luckily, two short formulas give the standard error from the sample you have.

The standard error of an average

SE(xˉ)=sn\text{SE}(\bar{x}) = \frac{s}{\sqrt{n}}

Here xˉ\bar{x} (say "x-bar") is the average of your sample. The letter ss is the sample's standard deviation, the n−1n - 1 version from earlier. The letter nn is how many observations you have.

In plain words: take the spread of the individual values and divide it by the square root of how many you measured. More data, smaller wobble.

Worked example. You time 100 deliveries. They vary with a standard deviation of 20 minutes. The square root of 100 is 10. So the average delivery time wobbles by about 20 ÷ 10 = 2 minutes.

import math

s, n = 20, 100              # spread of single deliveries, number of deliveries
print(s / math.sqrt(n))     # standard error of the average
It runs right here in your browser, with nothing to install.

It prints 2.0. Single deliveries vary by 20 minutes, but the average of 100 is far steadier.

The standard error of a rate

A rate is a share, such as "80 of 100 people clicked". It has its own formula:

SE(p^)=p^(1−p^)n\text{SE}(\hat{p}) = \sqrt{\frac{\hat{p}(1 - \hat{p})}{n}}

Here p^\hat{p} (say "p-hat") is the rate you measured, written as a decimal: 80% is 0.8.

In plain words: multiply the rate by one minus the rate. Divide by the number of people. Take the square root.

Worked example. 80 of 100 people click, so p^\hat{p} is 0.8. Then 0.8 × 0.2 = 0.16. Divide by 100 to get 0.0016. The square root is 0.04. The click rate wobbles by about 4 percentage points.

import math

p_hat, n = 80 / 100, 100
print(round(math.sqrt(p_hat * (1 - p_hat) / n), 4))

It prints 0.04.

The square root is the catch

Both formulas divide by n\sqrt{n}, the square root of the amount of data. That has a big effect on cost. To halve the wobble, you need four times as much data, not twice as much. The square root of 4 is 2, so four times the data only halves the error.

Go deeper Why the square root?

When you average nn independent values, their random ups and downs partly cancel. The variance (the square of the spread) of the average is the variance of one value divided by nn. The standard error is the square root of that variance, so you divide the spread by n\sqrt{n}. A rate is an average too: an average of 1s (clicked) and 0s (didn't). One 0-or-1 value has variance p(1−p)p(1 - p), which is where the rate formula comes from.

Quick check
What does this print?
import math
sd = 10
n = 100
print(sd / math.sqrt(n))
  1. 0.1
  2. 100
  3. 1.0
  4. 10.0
Show the answer

1.0

The square root of 100 is 10, so 10 / 10 = 1.0. The wobble is the spread divided by the square root of the sample size.

Confidence intervals

A map app doesn't promise you'll arrive at exactly 6:14. It says "6:10 to 6:20". A range is more honest than one exact number. A confidence interval does the same for an estimate.

With enough data, estimates like averages and rates roughly follow a bell curve around the true value. This fact is called the central limit theorem. So the true value is usually within about two standard errors of your estimate. A 95% confidence interval is

estimate±1.96×SE\text{estimate} \pm 1.96 \times \text{SE}

In plain words: start at your estimate. Go 1.96 standard errors down for the low end and 1.96 standard errors up for the high end. The ± sign means "plus or minus".

Worked example. The click rate was 0.8 with a standard error of 0.04. Then 1.96 × 0.04 is about 0.078. The interval runs from 0.8 − 0.078 to 0.8 + 0.078: about 72% to 88%.

se = 0.04
print(round(0.8 - 1.96 * se, 3), round(0.8 + 1.96 * se, 3))

It prints 0.722 0.878.

What does "95%" mean exactly? Imagine repeating the whole study many times, building an interval each time. About 95% of those intervals would contain the true value. In practice, read it as the range of values that fit your data. Put another way: the data are consistent with a true rate anywhere in that range, and the method captures the true rate about 95% of the time.

Go deeper Where 1.96 comes from

On a normal bell curve, 95% of values fall within 1.96 standard deviations of the middle. The estimate follows a bell curve whose spread is the standard error. So 95% of the time, the estimate lands within 1.96 standard errors of the truth. That makes the reverse true as well: the truth is within 1.96 standard errors of the estimate. Some people round 1.96 to 2. For a 90% interval you'd use 1.645 instead.

Here is the same recipe on real-sized numbers: a conversion rate and an eval score.

import numpy as np

conversions, visitors = 64, 2000
p_hat = conversions / visitors
se = np.sqrt(p_hat * (1 - p_hat) / visitors)
low, high = p_hat - 1.96 * se, p_hat + 1.96 * se
print(f"conversion rate {p_hat:.2%}, 95% CI {low:.2%} to {high:.2%}")

# An eval: 42 of 50 test questions correct
p_hat, n = 42 / 50, 50
se = np.sqrt(p_hat * (1 - p_hat) / n)
print(f"eval accuracy {p_hat:.0%}, 95% CI {p_hat - 1.96 * se:.0%} to {p_hat + 1.96 * se:.0%}")

CI is short for confidence interval. The eval interval runs from about 74% to 94%. That's 20 points wide. Now say a new prompt scores 88% on the same 50 questions. It sits inside that range, so it isn't clearly better. With only 50 questions, you can only spot big differences. That's why serious evals use hundreds of examples.

Quick check
An estimate is 50% with a standard error of 5 percentage points. Roughly what is the 95% confidence interval?
  1. About 40% to 60%
  2. About 49% to 51%
  3. About 0% to 100%
  4. About 45% to 55%
Show the answer

About 40% to 60%

1.96 × 5 is about 10 points. Go 10 down and 10 up from 50%.

The bootstrap: intervals for anything

The formulas cover averages and rates. But often you want an interval for something else. That might be a median, which is the middle value, or a ratio. It might be the 90th percentile: the value that 90% of results fall below. It might be an F1 score, which is a way to grade a classifier, a model that sorts things into groups. For those, use the bootstrap.

Picture your 300 receipts in a hat. Draw one, write down its amount, and put it back. Repeat 300 times. Putting it back is called sampling with replacement. Some receipts get drawn twice, some not at all. The result is a new, slightly different pile of 300 receipts: a resample.

The recipe:

  1. Make a resample.
  2. Work out your statistic on it, such as the median.
  3. Repeat a couple of thousand times.
  4. Sort the results and keep the middle 95%. That range is your interval.
import numpy as np

rng = np.random.default_rng(0)
order_values = rng.exponential(60, size=300)          # skewed, like real order values

boot = [np.median(rng.choice(order_values, size=len(order_values), replace=True)) for _ in range(2000)]
low, high = np.percentile(boot, [2.5, 97.5])
print(f"median order value {np.median(order_values):.2f}, 95% CI {low:.2f} to {high:.2f}")

The 2.5 and 97.5 percentiles cut off the lowest 2.5% and the highest 2.5% of results. What's left is the middle 95%. Notice the interval isn't centered on the median. Order values are lopsided, and the bootstrap picks that up on its own.

Why does it work? Your sample is your best picture of the population. Drawing from it again imitates going out and collecting another sample. It needs no formula, which makes it the everyday tool for eval metrics.

Go deeper Why put each receipt back?

Without replacement, drawing 300 receipts from 300 gives you the same receipts in a new order. The median wouldn't change at all, so you'd learn nothing about the wobble. Putting each one back lets every resample differ, the way a fresh sample from the real population would.

Quick check
You want a 95% interval for the median delivery time. There's no simple formula for it. What do you do?
  1. Bootstrap: resample with replacement, take the median each time, keep the middle 95%
  2. Use 1.96 × s / √n around the median
  3. Report the median on its own
  4. Take the fastest and slowest delivery as the interval
Show the answer

Bootstrap: resample with replacement, take the median each time, keep the middle 95%

The bootstrap works for any statistic you can compute. The s / √n formula is for averages, not medians.

How much data do you need?

You can also run the interval backwards. Decide how precise you want to be, then work out how much data that takes.

The margin of error is how far the interval reaches each side of the estimate: half its width. Call it mm. Let pp be the rate you expect to see, as a decimal:

n≈1.962 p(1−p)m2n \approx \frac{1.96^2\, p(1 - p)}{m^2}

The ≈ sign means "about equal to".

In plain words: multiply 1.96 squared by the rate and by one minus the rate. Divide by the margin squared. Always round up to a whole number.

Worked example. You expect about half of people to say yes, so pp is 0.5. You want to be within 5 points, so mm is 0.05. That's 3.8416 × 0.25 ÷ 0.0025 = 384.16. Round up: you need 385 people.

import math

print(math.ceil(1.96 ** 2 * 0.5 * (1 - 0.5) / 0.05 ** 2))

It prints 385. math.ceil always rounds up. Rounding down would leave you a little short of the precision you asked for.

The same formula works for a shop. To estimate a conversion rate near 4% within ±0.5 percentage points, you need about 5,900 visitors. Within ±1 point, you need about 1,500. Doubling the margin cut the data needed to a quarter: the square root rule again.

Quick check
Your eval's 95% interval for accuracy is 81% to 89% with 400 questions. Roughly how many questions would halve its width?
  1. About 1,600
  2. About 4,000
  3. About 800
  4. About 200
Show the answer

About 1,600

Width shrinks like 1/√n, so halving it needs 4× the data: 4 × 400 = 1,600.

Worked example

Worked example: an email open rate

You send a campaign to 1,000 people and 220 open it. Report the open rate honestly: the estimate, its standard error and a 95% interval. Then work out how many emails you'd need to pin it down to within ±1 percentage point.

import math

opened, sent = 220, 1000
p_hat = opened / sent
se = math.sqrt(p_hat * (1 - p_hat) / sent)
print(f"open rate {p_hat:.1%}, SE {se:.2%}")
print(f"95% CI {p_hat - 1.96 * se:.1%} to {p_hat + 1.96 * se:.1%}")
print("emails for +/-1 point:", math.ceil(1.96 ** 2 * p_hat * (1 - p_hat) / 0.01 ** 2))
In the lesson you can change this and run it.

The open rate is 22.0% with a standard error of about 1.3 points. The 95% interval is 19.4% to 24.6%, so the margin is about ±2.6 points. To get it down to ±1 point you'd need 6,593 emails. If a colleague reports "22% opened", you can now add "give or take about 2.6 points".

Practice what you just read

  • 7 code examples you can edit and run
  • a practice exercise that checks your code
  • a 5-question quiz
  • 5 review cards for spaced repetition

Create a free account

Try a quiz question

What does a 95% confidence interval of 3.1% to 4.5% for a conversion rate mean?

  1. The data are consistent with a true rate anywhere in that range; the method captures the true rate 95% of the time
  2. 95% of visitors convert at a rate between 3.1% and 4.5%, and the other 5% fall outside it
  3. The measured rate will land in that range on 95% of days, as long as nothing about the shop changes
  4. There's a 95% chance the sample was wrong, so the true rate is probably somewhere else entirely

Answer it at the end of the lesson to see if you're right, and why.

Before this lesson