T-Tests: Independent and Paired

1 What is a t-test?

A t-test is a statistical test that helps us determine if there’s a significant difference between the means of two groups. Think of it as answering questions like “Do these two groups really differ, or could the difference just be due to random chance?”

There are two main types:

  • Independent t-test: Compares means from two separate, unrelated groups (e.g., comparing heights of cats vs. dogs)
  • Paired t-test: Compares means from the same group measured twice, or matched pairs (e.g., measuring blood pressure before and after medication in the same patients)

Key assumptions: Both tests assume your data is approximately normally distributed, though t-tests are fairly robust to violations of this assumption, especially with larger sample sizes.

1.1 Understanding t.test() Arguments

The t.test() function in R has several important arguments:

  • x: A numeric vector of data values (or a formula for the formula method)
  • y: An optional numeric vector of data values (for two-sample tests)
  • alternative: Specifies the alternative hypothesis - “two.sided” (default), “less”, or “greater”
  • mu: The true value of the mean (or difference in means) under the null hypothesis. Default is 0
  • paired: Logical value indicating whether to perform a paired t-test. Default is FALSE
  • var.equal: Logical value indicating whether to assume equal variances. Default is FALSE (uses Welch’s t-test)
  • conf.level: Confidence level for the confidence interval. Default is 0.95 (95%)
  • formula: For formula method, use the format outcome ~ group
  • data: The data frame containing the variables (when using formula method)

For most basic comparisons, you’ll primarily use the formula method with the paired argument when needed.

2 Independent T-Test

When to use it: Use an independent t-test when you have two separate groups and want to know if their means differ significantly.

Example scenario: Let’s compare the bill length of Adelie penguins vs. Chinstrap penguins from the Palmer Archipelago. We’ll use the palmerpenguins package, which contains real data collected by Dr. Kristen Gorman.

2.1 Visualizing the Data

Show the code
library(tidyverse)
library(palmerpenguins)

penguins %>%
  filter(species %in% c("Adelie", "Chinstrap")) %>%
  drop_na(bill_length_mm) %>%
  group_by(species) %>%
  mutate(mean_bill = mean(bill_length_mm)) %>%
  ungroup() %>%
  ggplot(aes(x = bill_length_mm, fill = species)) +
  geom_density(alpha = 0.6) +
  geom_vline(aes(xintercept = mean_bill, color = species),
             linewidth = 1, linetype = "dashed") +
  annotate("text", x = 39, y = 0.09,
           label = "Mean", size = 4, fontface = "bold") +
  annotate("text", x = 49, y = 0.09,
           label = "Mean", size = 4, fontface = "bold") +
  labs(title = "Distribution of Penguin Bill Length by Species",
       x = "Bill Length (mm)",
       y = "Density",
       fill = "Species",
       color = "Species") +
  theme_minimal() +
  theme(legend.position = "bottom")
1
Load the tidyverse package for data manipulation and plotting
2
Load the palmerpenguins package containing our penguin data
3
Filter to only Adelie and Chinstrap species (t-test compares exactly two groups)
4
Remove any rows with missing bill length values
5
Group by species to calculate means within each group
6
Create a new column with the mean bill length for each species
7
Ungroup to return to normal data structure
8
Set up the plot with bill length on x-axis and fill color by species
9
Create density curves with transparency (alpha) so they overlap nicely
10
Add vertical dashed lines at the mean for each species
11
Make the mean lines thicker and dashed for visibility
12
Add text labels to identify the mean lines for each species
13
Add clear labels for title and axes
14
Use a clean, minimal theme for better readability

2.2 Performing the Test

Show the code
penguins %>%
  filter(species %in% c("Adelie", "Chinstrap")) %>%
  drop_na(bill_length_mm) %>%
  t.test(bill_length_mm ~ species, data = .)
1
Filter to just two species for comparison
2
Remove missing values to avoid errors in the t-test
3
Use formula notation (outcome ~ group) where the dot passes the piped data

    Welch Two Sample t-test

data:  bill_length_mm by species
t = -21.865, df = 106.97, p-value < 2.2e-16
alternative hypothesis: true difference in means between group Adelie and group Chinstrap is not equal to 0
95 percent confidence interval:
 -10.952948  -9.131917
sample estimates:
   mean in group Adelie mean in group Chinstrap 
               38.79139                48.83382 

2.3 Interpreting the Results

The output shows several key pieces of information:

  • t-statistic: How many standard errors the means are apart. Larger absolute values indicate more different groups.
  • p-value: If less than 0.05, we reject the null hypothesis that the means are equal. This suggests a statistically significant difference.
  • 95% confidence interval: Range where we’re 95% confident the true difference in means lies.
  • Sample means: The average bill length for each species.

For our penguins: If p < 0.05, we can conclude that Adelie and Chinstrap penguins have significantly different bill lengths. The confidence interval tells us the likely range of that difference in millimeters. Looking at our density plot, we can see how the distributions are quite separated, with the means falling in distinctly different locations.

3 Paired T-Test

When to use it: Use a paired t-test when your data points are naturally paired - either the same subjects measured twice, or matched subjects measured once each.

Example scenario: Let’s examine the classic sleep dataset (built into R), which shows the effect of two different sleep drugs on 10 patients. Each patient received both drugs at different times, making this a perfect paired scenario.

3.1 Step 1: Prepare the Data

Show the code
sleep_wide <- sleep %>%
  pivot_wider(names_from = group,
              values_from = extra,
              names_prefix = "drug_")

sleep_wide
1
Take values from the ‘group’ column (1 and 2) to create new column names
2
Fill those new columns with values from the ‘extra’ column (hours of extra sleep)
3
Add “drug_” prefix to create clear column names: drug_1 and drug_2
# A tibble: 10 × 3
   ID    drug_1 drug_2
   <fct>  <dbl>  <dbl>
 1 1        0.7    1.9
 2 2       -1.6    0.8
 3 3       -0.2    1.1
 4 4       -1.2    0.1
 5 5       -0.1   -0.1
 6 6        3.4    4.4
 7 7        3.7    5.5
 8 8        0.8    1.6
 9 9        0      4.6
10 10       2      3.4

3.2 Visualizing the Paired Data

Show the code
sleep %>%
  mutate(group = paste("Drug", group)) %>%
  group_by(group) %>%
  mutate(mean_extra = mean(extra)) %>%
  ungroup() %>%
  ggplot(aes(x = extra, fill = group)) +
  geom_density(alpha = 0.6) +
  geom_vline(aes(xintercept = mean_extra, color = group),
             linewidth = 1, linetype = "dashed") +
  annotate("text", x = 0.8, y = 0.32,
           label = "Mean", size = 4, fontface = "bold") +
  annotate("text", x = 2.3, y = 0.32,
           label = "Mean", size = 4, fontface = "bold") +
  labs(title = "Distribution of Extra Sleep by Drug",
       x = "Extra Sleep (hours)",
       y = "Density",
       fill = "Treatment",
       color = "Treatment") +
  theme_minimal() +
  theme(legend.position = "bottom")
1
Create clearer labels by adding “Drug” before the group numbers
2
Group by drug to calculate means within each treatment
3
Create a new column with the mean extra sleep for each drug
4
Ungroup to return to normal data structure
5
Set up the plot with extra sleep on x-axis and fill by drug group
6
Create overlapping density curves with transparency
7
Add vertical dashed lines showing the mean for each drug
8
Add text annotations to label the mean lines
9
Add clear labels and use minimal theme

3.3 Step 2: Perform the Paired T-Test

Show the code
t.test(sleep_wide$drug_1, sleep_wide$drug_2, paired = TRUE)
1
Compare drug_1 and drug_2 as paired samples from the same individuals

    Paired t-test

data:  sleep_wide$drug_1 and sleep_wide$drug_2
t = -4.0621, df = 9, p-value = 0.002833
alternative hypothesis: true mean difference is not equal to 0
95 percent confidence interval:
 -2.4598858 -0.7001142
sample estimates:
mean difference 
          -1.58 

3.4 Interpreting the Results

The paired t-test output is similar to the independent t-test but with important differences:

  • t-statistic: Tests if the mean difference between paired observations is zero.
  • p-value: If less than 0.05, there’s a significant difference between the two conditions.
  • 95% confidence interval: Range for the true mean difference (not the difference between means!).
  • Mean of differences: Average change from condition 1 to condition 2.

For our sleep data: We’re testing whether the two drugs produce different amounts of extra sleep in the same individuals. The paired design is more powerful because it accounts for person-to-person variability - some people naturally sleep more than others, but we’re interested in whether each person sleeps differently on the two drugs. The density plot helps us visualize the overall distributions, though remember that the paired test is actually looking at the differences within each person, not just the overall distributions.

4 Key Takeaway

Independent vs. Paired - Choose wisely!

  • Different subjects in each group → Independent t-test
  • Same subjects measured twice OR matched pairs → Paired t-test
  • Using the wrong test can lead to incorrect conclusions or reduced statistical power!