Skip to main content

Section 6.4 Contingency Tables

When there are only categorical variables, we need to create what are called contingency table (otherwise known as frequency tables). We first touched upon contingency tables in SubsectionΒ 2.6.1, where we used the table() command from base r and the count() function from dplyr/tidyverse. In addition, the the xtabs command from the stats package can also be used. It is personal preference on which you decide to personally use.
First, we check the balance of our groups to ensure the randomization worked and to see the overall infection rate. We can start with using table().
# All three are at the same frequency
table(infection$Treatment)
Control     Cranberry Lactobacillus 
           50            50            50
Using the count() function, we can perform essentially the same thing.
# Showing there are more people that were not infected vs infected
infection |> count(Infection)
# A tibble: 2 Γ— 2
  Infection     n
  <chr>     <int>
1 No          104
2 Yes          46
Now, we combine these two variables to see how infection status is distributed across the different treatments. While table() works, we will use xtabs() for a cleaner, formula-based approach.
library(knitr)

# Create the table using the xtabs command
contingency_table <- xtabs(~Treatment + Infection, data = infection)

kable(contingency_table, caption = "Contingency table displaying the frequency of infection status across treatment groups.")
Table: Contingency table displaying the frequency of infection status across treatment groups.

|              | No| Yes|
|:-------------|--:|---:|
|Control       | 32|  18|
|Cranberry     | 42|   8|
|Lactobacillus | 30|  20|
In R formulas, the variable before the + becomes the rows, and the variable after the + becomes the columns. If we reverse the formula, we transpose the table.
# Reversing the formula to see the change in orientation
reverse_table <- xtabs(~Infection + Treatment, data = infection)

kable(reverse_table, caption = "Contingency table displaying the same infection data with rows and columns reversed to illustrate how formula order affects table orientation.")
Table: Contingency table displaying the same infection data with rows and columns reversed to illustrate how formula order affects table orientation.

|    | Control| Cranberry| Lactobacillus|
|:---|-------:|---------:|-------------:|
|No  |      32|        42|            30|
|Yes |      18|         8|            20|
Now through any of the ways (table or xtabs), we are able to see that Cranberry has the lowest number infected out of the three treatments. What if we want to understand this from a percentage standpoint?
Let’s find out.
We will call on the help of the janitor package ([D.1.12]), specifically the tabyl(), adorn_totals(), adorn_percentages(), adorn_pct_formatting(), and adorn_ns() functions.
library(janitor)

c_table <- infection |>
  tabyl(Treatment, Infection) |>         # Makes a contingency table
  adorn_totals("row") |>                 # Adds totals for each treatment
  adorn_percentages("row") |>            # Adds row percentages
  adorn_pct_formatting(digits = 1) |>    # Makes it readable (adds % signs)
  adorn_ns()                              # Combines counts + percentages

kable(c_table, caption = "Distribution of infection status within each treatment group, reported as row percentages with counts (n).")
Table: Distribution of infection status within each treatment group, reported as row percentages with counts (n).

|Treatment     |No          |Yes        |
|:-------------|:-----------|:----------|
|Control       |64.0% ( 32) |36.0% (18) |
|Cranberry     |84.0% ( 42) |16.0% ( 8) |
|Lactobacillus |60.0% ( 30) |40.0% (20) |
|Total         |69.3% (104) |30.7% (46) |
From a percentage standpoint, we see that 84% of people who were given cranberries were not infected! That is much higher than either other treatment options, and the total percentage of people who were not infected as well.
It seems that cranberry is taking an early lead in terms of which treatment is the most impactful. We have some preliminary numbers, so now we can visualize.