Running Welch’s t-test, reading the output, and writing it up
2026-09-10
Note
✅ Key idea from Lecture 09
Every box is checked. Today we actually run the test, decode what R hands back, and turn it into a sentence a reader can trust.
t.test() outputTip
🖐 Try it yourself
By the end you will have a complete, reportable t-test result and a publication-style figure to go with it — whatever the test says.
References:
Both are in the course readings/ folder.
Today’s naming:
_model_plotThis lecture runs in two short chunks. After each chunk you switch to the activity and type the code yourself into your R script.
For every code block, do three things:
Note
✅ Why bother?
Guessing “above or below 0.05” before you see t.test() output forces you to reason about the test instead of just reading a number off the screen — that habit is what makes a p-value meaningful instead of magic.
# A tibble: 2 × 5
shade n mean_mass sd_mass se_mass
<chr> <int> <dbl> <dbl> <dbl>
1 shady 28 0.523 0.148 0.028
2 sunny 25 0.505 0.21 0.042
Levene's Test for Homogeneity of Variance (center = median)
Df F value Pr(>F)
group 1 2.9667 0.09105 .
51
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
var.equal = FALSE)Tip
If your Activity 09 numbers don’t match exactly, that’s fine — small rounding differences don’t change the conclusion.
We will cover: running Welch’s t.test(), reading every line of the output, and making a formal reject / fail-to-reject decision.
🛑 After this chunk: Activity Parts 1–3 (run, decode, decide).
Note
🔮 Predict first: Write down a guess for the p-value before you run t.test() — above or below 0.05? Then see how close you were.
Welch Two Sample t-test
data: mass_g by shade
t = 0.35579, df = 42.527, p-value = 0.7238
alternative hypothesis: true difference in means between group shady and group sunny is not equal to 0
95 percent confidence interval:
-0.08392774 0.11987117
sample estimates:
mean in group shady mean in group sunny
0.5230357 0.5050640
Key arguments:
| argument | what it does |
|---|---|
mass_g ~ shade |
compare mass_g between levels of shade |
var.equal = FALSE |
use Welch’s correction |
alternative = "two.sided" |
two-tailed test |
The result is a model object. We decode each line of the output on the next slide.
t.test() Outputt-statistic : 0.356
df (Welch) : 42.53
p-value : 0.724
95% CI : -0.084 to 0.12 g
Mean shady : 0.523 g
Mean sunny : 0.505 g
Line by line:
| output | meaning |
|---|---|
t |
our calculated t-statistic |
df |
Welch-Satterthwaite df (non-integer is normal!) |
p-value |
probability of this result if H₀ is true |
95% CI |
plausible range for the true difference in means |
mean of shady/sunny |
the two group means |
If the 95% CI includes zero, “no difference” is one of the plausible values — consistent with a p above 0.05.
# State the decision formally --------------------------
# if/else: R checks the condition and runs one of two blocks
# We will learn these formally in the functions lecture
p_val <- leaf_ttest_model$p.value
alpha <- 0.05
if (p_val < alpha) {
cat("p =", signif(p_val, 3), "< α =", alpha, "\n")
cat("Decision: REJECT H₀\n")
cat("Conclusion: mean leaf mass differs between sides.\n")
} else {
cat("p =", signif(p_val, 3), ">= α =", alpha, "\n")
cat("Decision: FAIL TO REJECT H₀\n")
cat("Conclusion: no evidence that mean leaf mass differs between sides.\n")
}p = 0.724 >= α = 0.05
Decision: FAIL TO REJECT H₀
Conclusion: no evidence that mean leaf mass differs between sides.
Important
What the p-value means:
If H₀ were true (no real difference), we would get a t-statistic at least this large p × 100% of the time just by chance.
We set α = 0.05 before the test. If p < α, we reject H₀; otherwise we fail to reject it.
What “fail to reject” does NOT mean:
🛑 Do Activity Parts 1–3 now
Run the test, decode t / df / p / CI, and state your decision in formal language. Predict the p-value first.
We will cover: embedding the test result in a boxplot and writing a scientific results sentence.
🛑 After this chunk: Activity Parts 4–5 (plot and the results sentence).
# Final boxplot with all points -----------------------
leaf_box_10_plot <- leaf_df %>%
ggplot(aes(x = shade, y = mass_g, fill = shade)) +
geom_boxplot(alpha = 0.5, outlier.shape = NA) +
geom_point(
position = position_jitter(width = 0.15, seed = 42),
alpha = 0.6,
size = 2.5
) +
labs(
title = "Leaf Mass by Shade",
subtitle = paste0(
"Welch's t-test: t = ",
round(leaf_ttest_model$statistic, 2),
", p = ",
signif(leaf_ttest_model$p.value, 2)
),
x = "Shade",
y = "Leaf Mass (g)"
) +
theme_minimal() +
theme(legend.position = "none")
leaf_box_10_plot
Including the test result in the figure:
subtitle pulls t and p directly from the model objectTip
Embedding test statistics in the plot subtitle saves you from copying numbers by hand — and avoids typos in your report.
# Build the results sentence from the model object -----
t_val <- round(leaf_ttest_model$statistic, 2)
df_val <- round(leaf_ttest_model$parameter, 1)
p_val2 <- signif(leaf_ttest_model$p.value, 2)
heavier <- if (leaf_ttest_model$estimate[1] > leaf_ttest_model$estimate[2]) "shady" else "sunny"
lighter <- if (heavier == "shady") "sunny" else "shady"
cat("--- Results sentence ---\n")--- Results sentence ---
Mean leaf mass did not differ significantly between sides
(Welch's t-test: t(42.5) = 0.36, p = 0.72).
Mean ± SE: shady = 0.523 ± 0.028 g, sunny = 0.505 ± 0.042 g.
Standard format:
“[Finding] (Welch’s t-test: t(df) = X.XX, p = X.XXX; mean ± SE: group1 = X.X ± X.X units, group2 = X.X ± X.X units).”
Always include:
A non-significant result is still a result — report it plainly (“did not differ significantly”), never as “proved there is no difference.”
Never report “p = 0.000” — write “p < 0.001” instead.
Your plot is now in your figures/ folder with the test statistics embedded in the subtitle — ready for a lab report or paper.
Tip
dpi = 300 is publication quality. Use it for any figure that will appear in a paper, poster, or formal report.
🛑 Go to Activity 10 — Parts 4–5
Build the figure with the statistics embedded in the subtitle, then write your results sentence. Predict what the subtitle will say before you run it.
Concepts:
R skills:
t.test(y ~ group, data, var.equal = FALSE, alternative = "two.sided")model$statistic, model$p.value, model$conf.int — extract resultspaste0(...) in labs(subtitle = ) — embed test statistics in figuresReferences:
Up next — Lecture 11:
lm()