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.
