Learning Objectives
By the end of this lab, you will be able to:
- Run each Unit 5 test in Python (
scipy.stats,statsmodels) and R (basestatsfunctions) - Follow the six-step procedure from 5.2 Steps in Hypothesis Testing with software doing the arithmetic
- Check assumptions (normality, equal variances, expected counts) before trusting a result
- Report a simple effect size alongside the p-value
- Avoid the common p-value misinterpretations listed in the ASA statement on p-values
Why Use Software?
The theory notes in this unit teach you to compute every statistic by hand, which is what the exam expects. In a ministry, municipality or donor project, the same tests are run in software: it is faster, it gives exact p-values instead of table look-ups, and it leaves a script that an auditor can re-run. This lab repeats each Unit 5 test in code so you can check hand calculations and use the tools at work.
Setup
- Python: install the libraries once with
pip install numpy scipy statsmodels. Outputs below were computed with Python 3.11, SciPy 1.17.1 and statsmodels 0.15.0. - R: every function used here (
t.test,prop.test,chisq.test,kruskal.test,wilcox.test,pnorm) is in base R’sstatspackage, so nothing needs installing. The outputs shown in this lab were computed in Python; with the options given, the R calls compute the same test statistics and p-values, although R’s print-out looks different. Differences in defaults between the two are flagged where they matter.
All datasets in this lab are hypothetical, constructed for teaching. They are not official statistics of any office.
Start every Python session with:
import numpy as np
from scipy import stats
from statsmodels.stats.proportion import proportions_ztest
The Six Steps, in Code
| Step | By hand (Unit 5 notes) | In software |
|---|---|---|
| 1. State $H_0$ and $H_1$ | Write them | Choose alternative= (two-sided, greater, less) |
| 2. Choose $\alpha$ | Usually 0.05 | Store alpha = 0.05 |
| 3. Test statistic | Formula | Function returns statistic |
| 4. Critical value/p-value | Table | Function returns pvalue |
| 5. Decision | Compare | pvalue < alpha |
| 6. Conclusion | Words in context | Still your job |
Software never does Step 6. A p-value is not a policy recommendation.
Test 1: One-Sample z-Test (σ Known)
Theory: 5.3 Large Sample Test for Single Mean
Scenario. We reproduce Example 1 from note 5.2: a government office claims mean processing time is 30 minutes. A sample of $n = 64$ cases has $\bar{x} = 32$ with known $\sigma = 8$.
Steps 1–2: $H_0: \mu = 30$, $H_1: \mu \neq 30$, $\alpha = 0.05$.
Steps 3–4 (Python). SciPy has no one-line z-test from summary statistics, so compute it directly:
n, xbar, sigma, mu0 = 64, 32, 8, 30
z = (xbar - mu0) / (sigma / np.sqrt(n))
p = 2 * stats.norm.sf(abs(z)) # sf = 1 - cdf, the upper-tail area
print(f"z = {z:.2f}, p = {p:.4f}")
z = 2.00, p = 0.0455
R:
n <- 64; xbar <- 32; sigma <- 8; mu0 <- 30
z <- (xbar - mu0) / (sigma / sqrt(n))
p <- 2 * pnorm(-abs(z))
c(z = z, p = p)
| Step 5: $p = 0.0455 < 0.05$ (equivalently $ | z | = 2.00 > 1.96$): reject $H_0$. The hand calculation in note 5.2 gave $p = 0.0456$ because it used the rounded table value 0.9772. |
Step 6: At the 5% level, the sample suggests mean processing time differs from the claimed 30 minutes. With $\bar{x} = 32$, the difference is about two minutes; whether that matters is a management judgement, not a statistical one.
Test 2: One-Sample t-Test (σ Unknown, Small n)
Theory: 5.7 Small Sample Test
Scenario. A Kathmandu ward office’s citizen charter says a recommendation letter takes no more than 30 minutes. A citizens’ group times 12 randomly chosen visits (minutes):
34, 29, 41, 36, 31, 38, 27, 35, 40, 33, 37, 32
Steps 1–2: $H_0: \mu = 30$, $H_1: \mu > 30$ (right-tailed), $\alpha = 0.05$.
Python:
times = np.array([34, 29, 41, 36, 31, 38, 27, 35, 40, 33, 37, 32])
print(f"mean = {times.mean():.2f}, sd = {times.std(ddof=1):.2f}")
res = stats.ttest_1samp(times, popmean=30, alternative="greater")
print(f"t = {res.statistic:.3f}, df = {res.df}, p = {res.pvalue:.4f}")
print(f"Shapiro-Wilk p = {stats.shapiro(times).pvalue:.3f}")
mean = 34.42, sd = 4.27
t = 3.580, df = 11, p = 0.0022
Shapiro-Wilk p = 0.996
ddof=1 makes NumPy divide by $n - 1$, giving the sample standard deviation $s$ used in the notes.
R:
times <- c(34, 29, 41, 36, 31, 38, 27, 35, 40, 33, 37, 32)
t.test(times, mu = 30, alternative = "greater")
shapiro.test(times)
Assumption check. With $n = 12$ the t-test needs approximately normal data. The Shapiro–Wilk test gives no evidence against normality ($p = 0.996$); a quick histogram or Q–Q plot should agree.
Step 5: $t = 3.580 > t_{0.05,11} = 1.796$ and $p = 0.0022 < 0.05$: reject $H_0$.
Step 6: There is sufficient evidence that mean service time exceeds the charter’s 30 minutes. Effect size: Cohen’s $d = (\bar{x} - \mu_0)/s = 4.42/4.27 \approx 1.03$, a large gap relative to day-to-day variation, about 4.4 minutes on average.
Test 3: Two Independent Samples — Pooled vs Welch t-Test
Theory: 5.7 Small Sample Test (pooled variance and Welch sections)
Scenario. Birth-registration processing times (minutes) at two ward offices, 10 random cases each:
- Ward 4:
22, 25, 19, 28, 24, 21, 26, 23, 20, 27 - Ward 10:
30, 18, 41, 26, 35, 22, 44, 29, 33, 38
Steps 1–2: $H_0: \mu_{10} = \mu_4$, $H_1: \mu_{10} \neq \mu_4$, $\alpha = 0.05$.
Python:
ward4 = np.array([22, 25, 19, 28, 24, 21, 26, 23, 20, 27])
ward10 = np.array([30, 18, 41, 26, 35, 22, 44, 29, 33, 38])
print(f"means: {ward4.mean():.1f}, {ward10.mean():.1f}; sds: {ward4.std(ddof=1):.2f}, {ward10.std(ddof=1):.2f}")
pooled = stats.ttest_ind(ward10, ward4, equal_var=True)
welch = stats.ttest_ind(ward10, ward4, equal_var=False)
print(f"pooled: t = {pooled.statistic:.3f}, df = {pooled.df:.0f}, p = {pooled.pvalue:.4f}")
print(f"welch: t = {welch.statistic:.3f}, df = {welch.df:.2f}, p = {welch.pvalue:.4f}")
print(f"Levene p = {stats.levene(ward10, ward4).pvalue:.3f}")
means: 23.5, 31.6; sds: 3.03, 8.26
pooled: t = 2.911, df = 18, p = 0.0093
welch: t = 2.911, df = 11.37, p = 0.0137
Levene p = 0.013
R:
ward4 <- c(22, 25, 19, 28, 24, 21, 26, 23, 20, 27)
ward10 <- c(30, 18, 41, 26, 35, 22, 44, 29, 33, 38)
t.test(ward10, ward4, var.equal = TRUE) # pooled
t.test(ward10, ward4) # Welch: R's default
var.test(ward10, ward4) # F-test for equal variances
Watch the defaults. R’s t.test uses Welch unless you set var.equal = TRUE; SciPy’s ttest_ind uses the pooled test unless you set equal_var=False. Always state which version you ran.
Assumption check. Ward 10’s standard deviation (8.26) is almost three times Ward 4’s (3.03). Levene’s test ($p = 0.013$) and the F-test (variance ratio 7.45, $p = 0.006$ computed in SciPy) both reject equal variances, so Welch is the right choice here, as note 5.7 recommends when SDs clearly differ.
Step 5: Welch $p = 0.0137 < 0.05$: reject $H_0$. (The pooled test gives the same decision, but its $p$ is too optimistic because its degrees of freedom assume equal variances.)
Step 6: Mean processing times differ between the wards; Ward 10 is slower by about 8 minutes on average and far less predictable. The variability itself may be the bigger service problem. Effect size: Cohen’s $d$ using the pooled SD is about 1.30.
Test 4: Paired t-Test
Theory: 5.8 Paired t-Test
Scenario. Ten ward officers take a records-management test (out of 100) before and after a two-day training course.
| Officer | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
|---|---|---|---|---|---|---|---|---|---|---|
| Before | 62 | 55 | 70 | 48 | 66 | 58 | 73 | 51 | 60 | 64 |
| After | 68 | 59 | 74 | 55 | 65 | 66 | 78 | 57 | 67 | 70 |
Steps 1–2: with $d = \text{after} - \text{before}$, $H_0: \mu_d = 0$, $H_1: \mu_d > 0$, $\alpha = 0.05$.
Python:
before = np.array([62, 55, 70, 48, 66, 58, 73, 51, 60, 64])
after = np.array([68, 59, 74, 55, 65, 66, 78, 57, 67, 70])
d = after - before
print(f"mean diff = {d.mean():.1f}, sd diff = {d.std(ddof=1):.2f}")
res = stats.ttest_rel(after, before, alternative="greater")
print(f"t = {res.statistic:.3f}, df = {res.df}, p = {res.pvalue:.6f}")
print(f"Shapiro-Wilk on differences p = {stats.shapiro(d).pvalue:.3f}")
w = stats.wilcoxon(after, before, alternative="greater")
print(f"Wilcoxon signed-rank p = {w.pvalue:.4f}")
mean diff = 5.2, sd diff = 2.53
t = 6.500, df = 9, p = 0.000056
Shapiro-Wilk on differences p = 0.034
Wilcoxon signed-rank p = 0.0020
R:
before <- c(62, 55, 70, 48, 66, 58, 73, 51, 60, 64)
after <- c(68, 59, 74, 55, 65, 66, 78, 57, 67, 70)
t.test(after, before, paired = TRUE, alternative = "greater")
shapiro.test(after - before)
wilcox.test(after, before, paired = TRUE, alternative = "greater")
Assumption check. The paired t-test assumes the differences are roughly normal. Here Shapiro–Wilk gives $p = 0.034$, mostly because officer 5 scored one point lower after training while everyone else improved by 4–8 points. With $n = 10$, a sensible response is to run the non-parametric Wilcoxon signed-rank test as a robustness check. It agrees ($p = 0.0020$). Because several differences are tied, R’s wilcox.test switches to a normal approximation and prints a warning, so its p-value will be slightly different from SciPy’s (SciPy’s own normal approximation with continuity correction gives $p \approx 0.0039$); the decision is the same.
Step 5: $t = 6.500 > t_{0.05,9} = 1.833$, $p < 0.001$: reject $H_0$.
Step 6: Scores rose by 5.2 points on average after training. This shows a change, not that the training caused it: without a comparison group, practice on the same test could explain part of the gain.
Test 5: One-Proportion z-Test
Theory: 5.5 Large Sample Test for Single Proportion
Scenario. A municipality’s target is that more than 70% of service users are satisfied. A random exit survey of 200 users finds 156 satisfied ($\hat{p} = 0.78$). This is Problem 2 from note 5.5.
Steps 1–2: $H_0: p = 0.70$, $H_1: p > 0.70$, $\alpha = 0.05$. Conditions: $np_0 = 140 \ge 10$ and $n(1-p_0) = 60 \ge 10$.
Python:
z, p = proportions_ztest(count=156, nobs=200, value=0.70, alternative="larger", prop_var=0.70)
print(f"z = {z:.3f}, p = {p:.4f}")
z_default, _ = proportions_ztest(count=156, nobs=200, value=0.70, alternative="larger")
print(f"without prop_var: z = {z_default:.3f}")
z = 2.469, p = 0.0068
without prop_var: z = 2.731
A trap in the defaults. The textbook test uses $p_0$ in the standard error: $\sqrt{p_0(1-p_0)/n}$. By default statsmodels uses the sample proportion $\hat{p}$ instead, which gives a different $z$ (2.731). Setting prop_var=0.70 reproduces the textbook statistic.
R:
prop.test(156, 200, p = 0.70, alternative = "greater", correct = FALSE)
R reports a chi-square statistic $X^2 = z^2 = 2.469^2 \approx 6.095$ with the same one-sided p-value (0.0068). Set correct = FALSE; R’s default applies Yates’ continuity correction, which the hand formula does not.
Step 5: $z = 2.469 > 1.645$, $p = 0.0068$: reject $H_0$.
Step 6: The survey supports the claim that more than 70% of users are satisfied. The exit survey only reaches people who completed their visit; anyone who gave up and left is missing from the sample.
Test 6: Two-Proportion z-Test
Theory: 5.6 Large Sample Test for Two Proportions
Scenario. Two municipalities piloted online applications for business registration. In Municipality A, 132 of 200 applicants completed the process online ($\hat{p}_1 = 0.660$); in Municipality B, 105 of 190 did ($\hat{p}_2 = 0.553$).
Steps 1–2: $H_0: p_1 = p_2$, $H_1: p_1 \neq p_2$, $\alpha = 0.05$.
Python:
z, p = proportions_ztest(count=[132, 105], nobs=[200, 190])
print(f"z = {z:.3f}, p = {p:.4f}")
z = 2.171, p = 0.0300
For two samples, proportions_ztest uses the pooled proportion $\bar{p} = (132 + 105)/(200 + 190) = 0.608$ by default, matching the formula in note 5.6.
R:
prop.test(c(132, 105), c(200, 190), correct = FALSE)
R prints $X^2 = z^2 \approx 4.712$ with the same two-sided p-value.
| Step 5: $ | z | = 2.171 > 1.96$, $p = 0.030$: reject $H_0$. |
Step 6: Online completion rates differ between the two pilots by about 10.7 percentage points (0.660 − 0.553). The test cannot tell us why: differences in internet access, applicant types or help-desk support are all plausible and need investigation.
Test 7: Chi-Square Test of Independence
Theory: 5.9 Chi-Square Test for Independence
Scenario. A district administration office surveys 200 service users about the channel they used and their satisfaction:
| Channel | Satisfied | Neutral | Dissatisfied | Total |
|---|---|---|---|---|
| Online | 48 | 22 | 10 | 80 |
| Counter | 52 | 38 | 30 | 120 |
| Total | 100 | 60 | 40 | 200 |
Steps 1–2: $H_0$: satisfaction is independent of channel. $H_1$: they are associated. $\alpha = 0.05$.
Python:
table = np.array([[48, 22, 10],
[52, 38, 30]])
chi2, p, dof, expected = stats.chi2_contingency(table)
print(f"chi2 = {chi2:.3f}, df = {dof}, p = {p:.4f}")
print(expected)
cramers_v = np.sqrt(chi2 / (table.sum() * (min(table.shape) - 1)))
print(f"Cramer's V = {cramers_v:.2f}")
chi2 = 6.694, df = 2, p = 0.0352
[[40. 24. 16.]
[60. 36. 24.]]
Cramer's V = 0.18
R:
tbl <- matrix(c(48, 22, 10,
52, 38, 30), nrow = 2, byrow = TRUE)
chisq.test(tbl)
chisq.test(tbl)$expected
Both SciPy and R apply Yates’ correction only to 2×2 tables, so for this 2×3 table they give the same $\chi^2$.
Assumption check. All expected counts are at least 5 (smallest is 16), so the chi-square approximation is fine.
Step 5: $\chi^2 = 6.694 > \chi^2_{0.05,2} = 5.991$, $p = 0.035$: reject $H_0$.
Step 6: Satisfaction is associated with service channel; online users were more often satisfied (48 of 80 = 60%) than counter users (52 of 120 ≈ 43%). Cramér’s $V = 0.18$ indicates a weak association. Users chose their channel themselves, so younger or better-connected citizens may be over-represented online; this is an association, not proof that moving services online raises satisfaction.
Test 8: Chi-Square Goodness of Fit
Theory: 5.10 Chi-Square Goodness of Fit
Scenario. A municipal grievance desk records 240 complaints over several weeks. Is the workload evenly spread across the six working days (Sunday–Friday)?
| Day | Sun | Mon | Tue | Wed | Thu | Fri |
|---|---|---|---|---|---|---|
| Observed | 52 | 38 | 35 | 41 | 30 | 44 |
| Expected | 40 | 40 | 40 | 40 | 40 | 40 |
Steps 1–2: $H_0$: complaints are equally likely on each day. $H_1$: they are not. $\alpha = 0.05$.
Python:
observed = np.array([52, 38, 35, 41, 30, 44])
res = stats.chisquare(observed) # equal expected counts by default
print(f"chi2 = {res.statistic:.2f}, p = {res.pvalue:.4f}")
chi2 = 7.25, p = 0.2027
R:
observed <- c(52, 38, 35, 41, 30, 44)
chisq.test(observed, p = rep(1/6, 6))
Check by hand: $\chi^2 = \frac{12^2 + 2^2 + 5^2 + 1^2 + 10^2 + 4^2}{40} = \frac{290}{40} = 7.25$ with $df = 6 - 1 = 5$.
Step 5: $\chi^2 = 7.25 < \chi^2_{0.05,5} = 11.07$, $p = 0.20$: fail to reject $H_0$.
Step 6: These data do not provide sufficient evidence that complaints are unevenly spread across days. This does not prove the workload is even; Sunday is the busiest day in this sample, and a longer record could reveal a real pattern. Staffing can still respond to it on practical grounds.
Test 9: Kruskal–Wallis Test
Theory: 5.11 Kruskal-Wallis Test
Scenario. Waiting times (minutes) for land-revenue services at three service centres, five randomly selected visits each:
- Centre A:
12, 15, 14, 10, 18 - Centre B:
20, 25, 22, 19, 24 - Centre C:
16, 13, 21, 17, 15
The samples are small and we do not want to assume normality, so we compare the centres with ranks.
Steps 1–2: $H_0$: the three centres have the same distribution of waiting times. $H_1$: at least one differs. $\alpha = 0.05$.
Python:
a = [12, 15, 14, 10, 18]
b = [20, 25, 22, 19, 24]
c = [16, 13, 21, 17, 15]
res = stats.kruskal(a, b, c)
print(f"H = {res.statistic:.3f}, p = {res.pvalue:.4f}")
ranks = stats.rankdata(a + b + c)
print("rank sums:", ranks[:5].sum(), ranks[5:10].sum(), ranks[10:].sum())
H = 8.931, p = 0.0115
rank sums: 21.5 63.0 35.5
R:
waits <- c(12, 15, 14, 10, 18, 20, 25, 22, 19, 24, 16, 13, 21, 17, 15)
centre <- factor(rep(c("A", "B", "C"), each = 5))
kruskal.test(waits ~ centre)
Matching the hand formula. With $N = 15$ and rank sums $R_A = 21.5$, $R_B = 63$, $R_C = 35.5$:
\[H = \frac{12}{15(16)}\left[\frac{21.5^2}{5} + \frac{63^2}{5} + \frac{35.5^2}{5}\right] - 3(16) = 8.915\]Software reports 8.931 because the value 15 appears twice (in A and C), and both SciPy and R apply the tie correction described in note 5.11 automatically.
Step 5: $H = 8.931 > \chi^2_{0.05,2} = 5.991$, $p = 0.012$: reject $H_0$.
Step 6: Waiting times differ across centres; Centre B has the highest ranks. Kruskal–Wallis says only that some difference exists. To find which pairs differ, a follow-up (post-hoc) comparison with a correction for multiple testing is needed.
What a p-Value Is — and Is Not
In 2016 the American Statistical Association (ASA) published a formal statement on p-values (Wasserstein & Lazar, 2016) with six principles. Paraphrased for PA practice:
- A p-value measures how incompatible the data are with a specified model (here, $H_0$ plus the test’s assumptions).
- It is not the probability that $H_0$ is true, nor the probability that “the data were produced by chance alone”. “p = 0.0137, so there is a 1.37% chance the wards are the same” is wrong.
- Decisions should not rest only on whether p crosses 0.05. Test 8’s $p = 0.20$ and a $p$ of 0.049 are not opposite truths.
- Report fully and transparently. If you ran ten tests and report only the one with $p < 0.05$, the p-value is misleading. Say how many analyses you ran.
- A p-value does not measure the size or importance of an effect. With very large samples, tiny differences become “significant”. This is why each test above reports a difference, $d$, or Cramér’s $V$.
- By itself, a p-value is weak evidence. A large p-value does not show $H_0$ is true; in Test 8 we said “insufficient evidence”, not “complaints are even”.
Checklist Before You Report a Test
| Check | Question |
|---|---|
| Design | Random sample? Independent or paired observations? |
| Assumptions | Normality (t-tests), equal variances (pooled t), expected ≥ 5 (χ²) |
| Software defaults | Pooled vs Welch? Continuity correction? Which SE for proportions? |
| Effect size | How big is the difference, in minutes, rupees or percentage points? |
| Plain-language result | Would an Executive Officer understand Step 6 without statistics? |
Summary
| Test | Python | R | Result in this lab |
|---|---|---|---|
| One-sample z (σ known) | stats.norm.sf by formula |
pnorm by formula |
z = 2.00, p = 0.0455 |
| One-sample t | stats.ttest_1samp |
t.test(x, mu = ) |
t = 3.580, p = 0.0022 |
| Two-sample t | stats.ttest_ind(equal_var=False) |
t.test(x, y) (Welch default) |
Welch p = 0.0137 |
| Paired t | stats.ttest_rel |
t.test(x, y, paired = TRUE) |
t = 6.500, p < 0.001 |
| One proportion | proportions_ztest(..., prop_var=p0) |
prop.test(..., correct = FALSE) |
z = 2.469, p = 0.0068 |
| Two proportions | proportions_ztest([x1, x2], [n1, n2]) |
prop.test(c(), c(), correct = FALSE) |
z = 2.171, p = 0.0300 |
| χ² independence | stats.chi2_contingency |
chisq.test(matrix) |
χ² = 6.694, p = 0.0352 |
| χ² goodness of fit | stats.chisquare |
chisq.test(x, p = ) |
χ² = 7.25, p = 0.2027 |
| Kruskal–Wallis | stats.kruskal |
kruskal.test |
H = 8.931, p = 0.0115 |
Practice Exercises
Exercise 1
A pension office’s standard is 9 working days to settle a claim. A random sample of 8 claims took 9, 11, 8, 12, 10, 13, 9, 11 days. Test at $\alpha = 0.05$ whether mean settlement time differs from 9 days, in Python and R.
Answer / solution sketch
`stats.ttest_1samp([9, 11, 8, 12, 10, 13, 9, 11], 9)` and `t.test(c(9, 11, 8, 12, 10, 13, 9, 11), mu = 9)`. $\bar{x} = 10.375$, $s = 1.685$, $t = 2.308$, $df = 7$, $p = 0.0543$. Since $p > 0.05$, **fail to reject $H_0$**. The sample average is 1.4 days above the standard, but with only 8 claims the evidence is not strong enough at 5%. A p-value of 0.054 is not meaningfully different from 0.046 (ASA principles 3 and 6): report the estimate and collect more data rather than declaring "no difference".Exercise 2
In a health-insurance enrolment drive, 68 of 120 households in Ward 3 enrolled, compared with 52 of 115 in Ward 7. Is the difference in enrolment rates significant at $\alpha = 0.05$?
Answer / solution sketch
`proportions_ztest([68, 52], [120, 115])` or `prop.test(c(68, 52), c(120, 115), correct = FALSE)`. $\hat{p}_1 = 0.567$, $\hat{p}_2 = 0.452$, $z = 1.755$, $p = 0.0792$. **Fail to reject $H_0$** at 5%: the 11.5-point gap could plausibly arise by sampling variation with these sample sizes.Exercise 3
A training institute expects its four regional centres to receive equal numbers of applications. Observed: 18, 30, 22, 30 (total 100). Test at $\alpha = 0.05$.
Answer / solution sketch
`stats.chisquare([18, 30, 22, 30])` or `chisq.test(c(18, 30, 22, 30), p = rep(1/4, 4))`. Expected 25 each; $\chi^2 = 4.32$, $df = 3$, $p = 0.229$; critical value 7.815. **Fail to reject $H_0$**: no sufficient evidence that applications are unevenly distributed.Exercise 4
Which statements are correct interpretations of $p = 0.03$ in Test 6? Correct the wrong ones.
(a) There is a 3% probability that the two municipalities have the same completion rate. (b) If the true completion rates were equal (and the test’s assumptions hold), a difference at least as large as the one observed would occur in about 3% of samples. (c) The difference between the municipalities is large and important.
Answer / solution sketch
Only **(b)** is correct. (a) confuses the p-value with the probability that $H_0$ is true (ASA principle 2). (c) confuses statistical significance with size or importance (principle 5); the size is the 10.7-point gap, and its importance depends on policy goals and cost.Exercise 5
Name the test (and the Python function) for each situation:
(a) Comparing average waiting times at four passport-office counters, with skewed data and small samples. (b) Checking whether the gender of applicants is associated with the type of permit requested. (c) Comparing staff absence days in the same 15 offices before and after a new attendance system.
Answer / solution sketch
(a) Kruskal–Wallis, `stats.kruskal`. (b) Chi-square test of independence, `stats.chi2_contingency`. (c) Paired t-test, `stats.ttest_rel` (or Wilcoxon signed-rank, `stats.wilcoxon`, if the differences are clearly non-normal).References
- Wasserstein, R. L., & Lazar, N. A. (2016). The ASA statement on p-values: Context, process, and purpose. The American Statistician, 70(2), 129–133. doi.org/10.1080/00031305.2016.1154108. ASA press release with the six principles: amstat.org
- SciPy documentation:
ttest_ind,chi2_contingency,kruskal,wilcoxon - statsmodels documentation:
proportions_ztest - R documentation (stats package):
t.test,prop.test,chisq.test,kruskal.test,wilcox.test
Next Topic
Apply these tools to the capstone cases: Capstone Case 01: Service Time Claim and Capstone Case 02: Training Uptake. Try solving each by hand first, then confirm your answer in Python or R.

