Code: style used in this chapter
import matplotlib.pyplot as plt
from matplotlib.axes import Axes
from statly import style
style.use()The right test follows from three questions: what kind of outcome, how many groups or what kind of predictor, and are the units paired or independent. The answer is rarely a single test; it is a test plus an effect size plus an interval.
import matplotlib.pyplot as plt
from matplotlib.axes import Axes
from statly import style
style.use()TREE = [
(
"A number",
style.BLUE,
[
("one group against a fixed value", "one-sample t / Wilcoxon signed-rank (3.4)"),
("two separate groups", "Welch's t / Mann-Whitney (3.4)"),
("the same units twice", "paired t / Wilcoxon signed-rank, sign test (3.4)"),
("three or more groups", "ANOVA, Welch's ANOVA / Kruskal-Wallis (3.5)"),
("two factors", "two-way ANOVA (3.5), regression (4.2)"),
("another number", "correlation, regression / Spearman, Kendall (3.6, 4.1)"),
],
),
(
"Yes / no, or categories",
style.CORAL,
[
("one share against a value", "z-test for a share / binomial test (3.1)"),
("two separate groups", "two-proportion z-test / Fisher's exact test (3.4)"),
("the same units twice", "McNemar's test (3.4)"),
("several groups or categories", "chi-square test / Fisher's exact test (3.5)"),
("against a given distribution", "chi-square goodness of fit (3.5)"),
("with numeric predictors", "logistic regression (4.4)"),
],
),
(
"A count",
style.GOLD,
[
("with or without predictors", "Poisson, negative binomial regression (4.6)"),
],
),
(
"Time until an event",
style.GREEN,
[
("two or more groups", "log-rank test (9.4)"),
("with predictors", "Cox regression (9.5)"),
],
),
(
"Values in time order",
style.PURPLE,
[
("is it stationary?", "Dickey-Fuller, KPSS (9.1)"),
("is anything left in the residuals?", "Ljung-Box (9.2)"),
],
),
]
def plot_tree(ax: Axes) -> None:
"""Outcome kinds on the left, designs in the middle, tests on the right, joined by lines."""
leaves = sum(len(branches) for _, _, branches in TREE)
y = leaves
for outcome, color, branches in TREE:
top, bottom = y, y - len(branches) + 1
middle = (top + bottom) / 2
ax.text(
0,
middle,
outcome,
ha="left",
va="center",
fontsize=10,
fontweight="bold",
color=color,
)
for design, test in branches:
ax.plot([0.27, 0.32], [middle, y], color=color, lw=1, alpha=0.6)
ax.text(0.33, y, design, ha="left", va="center", fontsize=9)
ax.plot([0.645, 0.67], [y, y], color=color, lw=1, alpha=0.6)
ax.text(0.68, y, test, ha="left", va="center", fontsize=9, color=color)
y -= 1
y -= 0.6
ax.set(xlim=(0, 1.24), ylim=(y, leaves + 1))
ax.set_axis_off()
fig, ax = plt.subplots(figsize=(10, 7.4))
plot_tree(ax)
plt.show()
Three more questions sharpen the choice:
Most of the tests on the map are special cases of regression (Part 4). A t-test is a regression on a 0/1 group indicator; ANOVA is a regression on several indicators; a correlation test is a regression slope test; the chi-square test for a 2 × 2 table matches a logistic regression with one yes/no predictor. Seeing them as models has two advantages: you can add more predictors (adjust for confounders, Chapter 4.2), and you get estimates with intervals, not only p-values.
| Test | The same as |
|---|---|
| one-sample t-test | regression with only an intercept |
| two-sample t-test (Student’s) | regression on one 0/1 predictor |
| one-way ANOVA | regression on group indicators |
| two-way ANOVA | regression on two factors and their interaction |
| correlation test | slope test in a simple regression |
| chi-square test of a table | logistic or Poisson regression on the categories |
| log-rank test | Cox regression on a group indicator |
A test result is incomplete without the size of the effect and its uncertainty. Report, in this order:
For example: Home owners spent on average 159 more per month on their credit cards than renters (95% interval 6 to 312; Welch’s t = 2.1, df = 54, p = 0.04; Cohen’s d = 0.5). A reader can see the direction, the size, how uncertain it is, and how surprising it would be if nothing were going on.
Next: Part 4, regression, where tests and intervals meet models.