Compute a 95% CI as mean ± t_crit × SE, where SE = s/√n (ddof=1) and t_crit = scipy.stats.t.ppf(0.975, df=n−1) is hardcoded as a literal so both halves use the identical critical value. Two loops for mean and sample std; then CI = mean ± t_crit × SE. Library: scipy.stats.t.interval(0.95, df, loc=mean, scale=SE).

By hand

Sample [4,7,2,9,5,9], n=6. Mean=6.0, s=√8≈2.828427, SE≈1.154701, df=5. t_crit = 2.5705818356 (scipy.stats.t.ppf(0.975, 5)). Margin = t_crit × SE ≈ 2.9683. CI: (6.0−2.9683, 6.0+2.9683) = (3.0317, 8.9683).

naive.py
Replay: real traced execution (multi-file project)
import math
sample = [4, 7, 2, 9, 5, 9]
n = len(sample)
total = 0.0
for v in sample:
    total = total + v
mean = total / n
sq_diff = 0.0
for v in sample:
    sq_diff = sq_diff + (v - mean) ** 2
s = math.sqrt(sq_diff / (n - 1))
se = s / math.sqrt(n)
df = n - 1
t_crit = 2.570581835636314  # scipy.stats.t.ppf(0.975, df=5)
margin = t_crit * se
lower = mean - margin
upper = mean + margin
print('RESULT:', (round(lower, 4), round(upper, 4)))
  1. import math

    1import math2sample = [4, 7, 2, 9, 5, 9]
  2. sample ← [4, 7, 2, 9, 5, 9]

    1import math2sample = [4, 7, 2, 9, 5, 9]3n = len(sample)
    values this step[4, 7, 2, 9, 5, 9]sample
  3. n ← 6

    2sample = [4, 7, 2, 9, 5, 9]3n = len(sample)4total = 0.0
    values this step6n
  4. total ← 0.0

    3n = len(sample)4total = 0.05for v in sample:
    values this step0.0total
  5. v ← 4, total ← 4.0

    pass 1 of 6
    4total = 0.05for v in sample:6    total = total + v7mean = total / n
    values this step4v0.0 4.0total
    All 6 passes — pass 1 is the card above
    passvtotal
    140.0 4.0
    24 74.0 11.0
    37 211.0 13.0
    42 913.0 22.0
    59 522.0 27.0
    65 927.0 36.0
  6. for v in sample:

    4total = 0.05for v in sample:6    total = total + v
  7. mean ← 6.0

    6    total = total + v7mean = total / n8sq_diff = 0.0
    values this step6.0mean
  8. sq_diff ← 0.0

    7mean = total / n8sq_diff = 0.09for v in sample:
    values this step0.0sq_diff
  9. v ← 4, sq_diff ← 4.0

    pass 1 of 6
    8sq_diff = 0.09for v in sample:10    sq_diff = sq_diff + (v - mean) ** 211s = math.sqrt(sq_diff / (n - 1))
    values this step9 4v0.0 4.0sq_diff
    All 6 passes — pass 1 is the card above
    passvsq_diff
    19 40.0 4.0
    24 74.0 5.0
    37 25.0 21.0
    42 921.0 30.0
    59 530.0 31.0
    65 931.0 40.0
  10. for v in sample:

    8sq_diff = 0.09for v in sample:10    sq_diff = sq_diff + (v - mean) ** 2
  11. s ← 2.8284271247461903

    10    sq_diff = sq_diff + (v - mean) ** 211s = math.sqrt(sq_diff / (n - 1))12se = s / math.sqrt(n)
    values this step2.8284271247461903s
  12. se ← 1.1547005383792517

    11s = math.sqrt(sq_diff / (n - 1))12se = s / math.sqrt(n)13df = n - 1
    values this step1.1547005383792517se
  13. df ← 5

    12se = s / math.sqrt(n)13df = n - 114t_crit = 2.570581835636314  # scipy.stats.t.ppf(0.975, df=5)
    values this step5df
  14. t_crit ← 2.570581835636314

    13df = n - 114t_crit = 2.570581835636314  # scipy.stats.t.ppf(0.975, df=5)15margin = t_crit * se
    values this step2.570581835636314t_crit
  15. margin ← 2.968252229557177

    14t_crit = 2.570581835636314  # scipy.stats.t.ppf(0.975, df=5)15margin = t_crit * se16lower = mean - margin
    values this step2.968252229557177margin
  16. lower ← 3.031747770442823

    15margin = t_crit * se16lower = mean - margin17upper = mean + margin
    values this step3.031747770442823lower
  17. upper ← 8.968252229557176

    16lower = mean - margin17upper = mean + margin18print('RESULT:', (round(lower, 4), round(upper, 4)))
    values this step8.968252229557176upper
  18. stdout ← RESULT: (3.0317, 8.9683)

    17upper = mean + margin18print('RESULT:', (round(lower, 4), round(upper, 4)))
    values this stepRESULT: (3.0317, 8.9683)stdout

With the library

scipy.stats.t.interval(0.95, df, loc=mean, scale=SE) computes the same interval using the same t critical value internally. The snapshot shows t_crit explicitly so the match is verifiable.

library.py
import math
import numpy as np
from scipy.stats import t
from dalib.display import set_display
set_display()

sample = [4, 7, 2, 9, 5, 9]
n = len(sample)
mean = float(np.mean(sample))
s = float(np.std(sample, ddof=1))
se = s / math.sqrt(n)
df = n - 1
t_crit = float(t.ppf(0.975, df))
lo, hi = t.interval(0.95, df, loc=mean, scale=se)
print('mean:', mean, ' SE:', round(se, 6))
print('t_crit (df=5):', round(t_crit, 10))
print('RESULT:', (round(float(lo), 4), round(float(hi), 4)))
mean: 6.0  SE: 1.154701
t_crit (df=5): 2.5705818356
RESULT: (3.0317, 8.9683)

Honesty

This lesson shows the computation exactly, on a tiny pinned sample. The arithmetic is correct and reproducible, but with a sample this small the result is not a valid statistical finding — it demonstrates the mechanism, not evidence. Real inference needs an adequate sample size and assumption checks (e.g. independence and normality or large n for the CLT); the p-value / interval here should be read as "how the formula is computed," not as a conclusion about a population.

Implementation notes

  • The t_crit literal 2.570581835636314 equals scipy.stats.t.ppf(0.975, 5) to full float64 precision — this is why parity holds.
  • Interpretation: "95% of intervals constructed this way will contain the true population mean." NOT "95% probability the true mean is in this specific interval."
  • Width scales with 1/√n (via SE) and with df (wider for small samples due to higher t_crit). At large n, t_crit approaches the normal z=1.96.
  • Cross-reference: standard-error (this chapter) for the SE computation; z-scores (ch02) for the standardization concept underlying the t statistic.