Info sheet · Statistics for Psychology & Neuroscience
Author
Andrew Bell
Published
September 22, 2026
Info sheet 0.2 (draft) · Prerequisites: the mean and variance; what it means to estimate a parameter · Give feedback ↗
Warning✎ Editing notes — to do / to check
Working notes for the author — not shown to students once collapsed; remove before publishing.
What you’ll get from this sheet
By the end you should be able to:
Say, in one sentence, what a degree of freedom is.
Explain why the sample variance divides by \(n-1\) instead of \(n\).
Work out the degrees of freedom for the tests you already use.
A degree of freedom is a piece of information that is free to vary. Rule of thumb: df = (how many numbers you have) − (how many things you estimated from them).
The idea in one line
Every time you estimate something from your data — a mean, a slope — you “use up” a piece of the information the data contained. Degrees of freedom count what’s left over: how many values were still free to vary once your estimates were pinned down.
Why \(n-1\)? The last value isn’t free
Suppose I tell you three numbers have a mean of 10. You can pick the first two freely — say 8 and 15 — but the third is now forced to be 7, because the mean is fixed. Three numbers, one constraint (the mean), so only two are free to vary. That is why the sample variance divides by \(n-1\): one degree of freedom was already spent estimating the mean.
Drag the sliders: green circles are free to vary; amber circles are fixed by the parameters you’ve already estimated.
md`**Number of observations, n** — currently **${+nObs}**`
viewof nObs =html`<input type="range" min="2" max="30" step="1" value="8" style="width:300px">`md`**Parameters estimated, p** (the mean counts as 1) — currently **${+nPar}**`
dfWidget = {const n =+nObs, p =Math.min(+nPar, n);const df = n - p;const r =13, gap =8, perRow =10, cell =2* r + gap;let s ="";for (let i =0; i < n; i++) {const free = i < df;const cx = (i % perRow) * cell + r +4;const cy =Math.floor(i / perRow) * cell + r +4; s +=`<circle cx="${cx}" cy="${cy}" r="${r}" fill="${free ?"#2ecc71":"#e67e22"}" stroke="#0d1117" stroke-width="1.5"/>`; }const rows =Math.ceil(n / perRow);const W = perRow * cell +8, H = rows * cell +8;const fig =document.createElement("figure"); fig.style.margin="0"; fig.innerHTML=`<svg viewBox="0 0 ${W}${H}" width="${Math.min(W,480)}" style="background:#f4f6f8;border-radius:8px">${s}</svg>`+`<figcaption style="margin-top:.5rem"><b style="color:#1E7A34">${df}</b> free · <b style="color:#C0501E">${p}</b> fixed → degrees of freedom = n − p = <b>${df}</b></figcaption>`;return fig;}
As you’ll see from the demo, no matter how many data points you have, the last one is always fixed once you know the mean — so with \(n\) numbers and the mean pinned down, only \(n-1\) are free to vary. That’s why the sample variance divides by \(n-1\), not \(n\).
Degrees of freedom in the tests you already know
Procedure
Degrees of freedom
Sample variance / SD
\(n - 1\)
One-sample t-test
\(n - 1\)
Independent t-test
\(n_1 + n_2 - 2\)
One-way ANOVA
between: \(k - 1\) · within: \(N - k\)
Simple regression
\(n - 2\)
Multiple regression
\(n - p - 1\)
The pattern is always the same: start with your n, subtract one for each quantity you had to estimate along the way. Notice how the one-sample t-test (\(n-1\): one mean estimated) differs from the independent two-sample t-test (\(n_1+n_2-2\): two group means estimated). ANOVA generalises this — you spend \(k-1\) df on the \(k\) group means (between) and keep \(N-k\) for the error (within) — and each predictor in a regression costs another df (\(n-2\) for a slope + intercept, \(n-p-1\) for \(p\) predictors).
How df shapes the curve — and why it matters
Degrees of freedom don’t just get reported; they set the shape of the reference distribution your test statistic is judged against. The t, F, and \(\chi^2\) distributions are really families of curves indexed by df. For the t-distribution: at low df the curve has heavier tails than the normal (extreme values are more likely by chance), so the critical value you must beat is larger; as df grows it converges on the standard normal. Drag df and watch the two-sided 5% critical value shrink toward ±1.96:
md`**Degrees of freedom** — currently **${+tdf}**`
That’s why df matters for interpretation, not just bookkeeping: the same t-statistic can be significant with 100 df but not with 5, because the bar moves. Small samples are penalised with heavier-tailed reference curves — a built-in caution against over-reading noisy data. (The χ² and F distributions change shape with their df in the same spirit: more df, more concentrated and symmetric.)
See it in code
The sample variance divides by \(n-1\) — the software is doing the degrees-of-freedom bookkeeping for you.
x= [486597];var(x) % divides by n - 1 by defaultnumel(x) -1% the degrees of freedom
Static reference — the R and Python tabs run live in the page.
Quick quiz: find the degrees of freedom
Pick a procedure and choose the right df formula:
NoteQuiz
Answer each question — the feedback appears beneath it.
dfBtn = {const scens=["Sample variance / SD of n numbers","One-sample t-test (n observations)","Independent two-sample t-test","One-way ANOVA — within-group (error) df","One-way ANOVA — between-group df","Simple linear regression (one predictor)"];const ans=["n − 1","n − 1","n₁ + n₂ − 2","N − k","k − 1","n − 2"];const why=["One mean is estimated, so one df is spent — e.g. 12 numbers → 11 df.","The one-sample t-test estimates a single mean — e.g. n = 25 → 24 df.","Two group means are estimated, one df each — e.g. 15 + 18 − 2 = 31 df.","The error df is the total minus one per group mean — e.g. 30 − 3 = 27 df.","The between df counts the k group means minus one — e.g. 3 groups → 2 df.","A slope and an intercept are estimated, so two df go — e.g. n = 20 → 18 df."];const opts=["n − 1","n₁ + n₂ − 2","k − 1","N − k","n − 2"];const wrap=document.createElement("div"); scens.forEach((scen,i)=>{const block=document.createElement("div"); block.style.cssText="margin:0 0 1rem 0";const q=document.createElement("div"); q.style.cssText="font-weight:600;margin-bottom:.35rem"; q.textContent=(i+1)+". "+scen;const row=document.createElement("div"); row.style.cssText="display:flex;gap:8px;flex-wrap:wrap;margin-bottom:.3rem";const fb=document.createElement("div"); fb.style.cssText="font-size:14px;min-height:1.2rem;color:#94a3b8"; fb.textContent="Click an answer to check."; opts.forEach(opt=>{const b=document.createElement("button"); b.textContent=opt; b.style.cssText="padding:5px 11px;border:1px solid #cbd5e1;border-radius:6px;background:#fff;cursor:pointer;font-size:14px"; b.onmouseenter=()=>b.style.background="#f1f5f9"; b.onmouseleave=()=>b.style.background="#fff"; b.onclick=()=>{ const ok=opt===ans[i]; fb.innerHTML=`<b style="color:${ok?'#1E7A34':'#c0392b'}">${ok?'✓ '+ans[i]:'✗ Not quite — '+ans[i]}.</b> <span style="color:#334">${why[i]}</span>`; }; row.appendChild(b); }); block.append(q,row,fb); wrap.appendChild(block); });return wrap;}
TipCheck your understanding
A one-way ANOVA with 4 groups and 40 observations in total. What are the between- and within-group degrees of freedom?
Between groups: \(k - 1 = 4 - 1 = \mathbf{3}\). Within groups: \(N - k = 40 - 4 = \mathbf{36}\). You’d report the test as \(F(3, 36)\).
Forgetting that every estimated parameter costs a degree of freedom. It’s why variance divides by \(n-1\) (you already spent one on the mean), and why piling predictors into a regression shrinks its residual df — eventually leaving too little information to trust the estimates.
Where this shows up next
Degrees of freedom set the shape of the t, F, and \(\chi^2\) distributions you look your test statistics up against. See the ANOVA and Regression chapters for how the df feed into the F‑ and t‑tables.