Skip to main content

Section 6.6 Chi-Square Test

Now, we have done some investigation on our data through contingency tables and visualizations. It is time to run what is called a chi-square test. This allows us to see if two categorical variables are related to each other.
chisq.test(contingency_table)
Pearson's Chi-squared test

data:  contingency_table
X-squared = 7.7759, df = 2, p-value = 0.02049
Whether we performed it on our contingency table, we get:
  1. X^2- This is the test statistic. This is telling us how much different our observed is vs our expected.
  2. df - Degrees of freedom = (rows - 1)*(columns - 1). For 3 treatments and 2 outcomes, df = (3-1)*(2-1) = 2.
  3. p-value- This tells us if it is statistically significant or not.
We see that our X^2 value is 7.78, our df is 2, and our p-value is 0.0204871. Since our p-value is less than .05, we can rightly say that there is a significant relationship between treatment plans and outcomes.
Now that we know it is significant, we need to dive a little deeper. We are understanding that cranberry is looking like the leader, but we can become more solidified on that stance.
chi_square_test <- chisq.test(contingency_table)

# All the parts of the chi square can be called.
chi_square_test$statistic

chi_square_test$parameter

chi_square_test$p.value

chi_square_test$method

chi_square_test$data.name

# What our data already is
chi_square_test$observed

# What our data would look like if there was no relationship
chi_square_test$expected

# Difference between observed and expected
# Positive is more than expected
# Negative is less than expected
# Bigger number = bigger difference
# Represent how many standard deviations
chi_square_test$residuals

# Standard Residuals
# More like an actual z-score
chi_square_test$stdres
X-squared 
  7.77592 
df 
 2 
[1] 0.0204871
[1] "Pearson's Chi-squared test"
[1] "contingency_table"
               Infection
Treatment       No Yes
  Control       32  18
  Cranberry     42   8
  Lactobacillus 30  20
               Infection
Treatment             No      Yes
  Control       34.66667 15.33333
  Cranberry     34.66667 15.33333
  Lactobacillus 34.66667 15.33333
               Infection
Treatment               No        Yes
  Control       -0.4529108  0.6810052
  Cranberry      1.2455047 -1.8727644
  Lactobacillus -0.7925939  1.1917591
               Infection
Treatment              No       Yes
  Control       -1.001671  1.001671
  Cranberry      2.754595 -2.754595
  Lactobacillus -1.752924  1.752924

Rule of Thumb:.

Think of standardized residuals like z-scores: values greater than +2 or less than -2 are the ’statistically interesting’ parts of your table that are driving your p-value.
We can also visualize our observed versus our expected counts, as visualizations are key to understanding our data.
# 1. Extract observed and expected counts from our test object
obs_exp_data <- data.frame(
  Treatment = rep(rownames(chi_square_test$observed), 2),
  Infection = rep(colnames(chi_square_test$observed), each = 3),
  Observed = as.vector(chi_square_test$observed),
  Expected = as.vector(chi_square_test$expected)
)

# 2. Pivot the data to a 'long' format for ggplot
plot_data <- obs_exp_data |>
  pivot_longer(cols = c(Observed, Expected),
               names_to = "Type",
               values_to = "Counts")

# 3. Create the plot
ggplot(plot_data, aes(x = Treatment, y = Counts, fill = Type)) +
  geom_bar(stat = "identity", position = "dodge", alpha = 0.8) +
  facet_wrap(~Infection) +
  scale_fill_manual(values = c("Expected" = "grey70", "Observed" = "#CC0000")) +
  labs(
    title = "Observed vs. Expected Infection Counts",
    subtitle = "The grey bars show what we would expect by random chance alone",
    x = "Treatment Group",
    y = "Number of Participants"
  ) +
  theme_minimal()
A faceted bar chart with two panels (No and Yes infection) showing observed (red) and expected (grey) counts for each treatment group. The Cranberry group shows the largest deviation from expected in the Yes panel.
Figure 6.6.1. Comparison of observed vs. expected counts across treatment groups, faceted by infection outcome. The grey bars represent the expected distribution if there were no relationship between treatment and infection; deviations from grey indicate cells driving the significant chi-square result.
Our deep dive uncovered some very important things about our experiment:
  • Expected: all of the values were different from what we the actual observations were. If there was no relationship between the two variables, it was expected that each treatment would have about 35 people not infected, and 15 people infected
  • Residuals/stdres: this is where we really start to tie everything together. With the residuals, we are looking for if it is positive/negative, and then strength in relation to the other. Cranberry if the only one of the three where there are less people infected than anticipated, almost 2 standard deviations less than expected. Both other treatments have more people infected than expected.
    • Note: Standardized residuals behave like z-scores β€” values beyond Β±2 suggest cells contributing most strongly to the overall χ² statistic.
We tie this information together to get a very strong case for cranberry. There is just one piece of the puzzle left to bring this home.