# Check and install required packages automatically if missing
library(epitools)
library(tidyverse)
library(broom)
This publication provides a step-by-step guide to calculating the Relative Risk (RR) in R using three distinct methodologies.
Relative Risk compares the probability of an outcome occurring in an exposed group versus an unexposed group:
\[RR = \frac{\text{Risk in Exposed Group}}{\text{Risk in Unexposed Group}} = \frac{A / (A + B)}{C / (C + D)}\]
We will create a standard \(2 \times 2\) contingency table.
For epidemiological packages like epitools to work
perfectly without flipping results, we structure the matrix according to
standard package conventions: * Row 1: Unexposed
(Control) * Row 2: Exposed (Treatment) * Column
1: Outcome Negative (Healthy) * Column 2:
Outcome Positive (Disease)
# Define the counts for our 2x2 table
# Row 1 (Unexposed): 80 Healthy, 20 Diseased
# Row 2 (Exposed): 60 Healthy, 40 Diseased
study_matrix <- matrix(c(80, 20,
60, 40),
nrow = 2,
byrow = TRUE)
# Assign names for visual clarity
rownames(study_matrix) <- c("Unexposed", "Exposed")
colnames(study_matrix) <- c("No Disease", "Disease")
# Print the final table
study_matrix
## No Disease Disease
## Unexposed 80 20
## Exposed 60 40
To understand how the arithmetic works behind the scenes, we extract the values directly from our matrix and apply the formula.
# Extract table cells
unexposed_healthy <- study_matrix[1, 1] # 80
unexposed_diseased <- study_matrix[1, 2] # 20
exposed_healthy <- study_matrix[2, 1] # 60
exposed_diseased <- study_matrix[2, 2] # 40
# Calculate risk per group
risk_unexposed <- unexposed_diseased / (unexposed_healthy + unexposed_diseased)
risk_exposed <- exposed_diseased / (exposed_healthy + exposed_diseased)
# Calculate Relative Risk
manual_rr <- risk_exposed / risk_unexposed
# Output results
cat("Risk in Unexposed Group:", risk_unexposed, "\n")
## Risk in Unexposed Group: 0.2
cat("Risk in Exposed Group: ", risk_exposed, "\n")
## Risk in Exposed Group: 0.4
cat("Calculated Relative Risk:", manual_rr, "\n")
## Calculated Relative Risk: 2
epitools PackageWhile manual calculation gives you the exact estimate point, it does
not provide confidence intervals or \(p\)-values. The riskratio()
function from the epitools package automates this.
We choose method = "wald" to get standard Wald
confidence intervals.
# Run the risk ratio estimation
rr_analysis <- riskratio(study_matrix, method = "wald")
# View the full output structure
print(rr_analysis)
## $data
## No Disease Disease Total
## Unexposed 80 20 100
## Exposed 60 40 100
## Total 140 60 200
##
## $measure
## NA
## risk ratio with 95% C.I. estimate lower upper
## Unexposed 1 NA NA
## Exposed 2 1.263006 3.167047
##
## $p.value
## NA
## two-sided midp.exact fisher.exact chi.square
## Unexposed NA NA NA
## Exposed 0.002145336 0.003191817 0.002028231
##
## $correction
## [1] FALSE
##
## attr(,"method")
## [1] "Unconditional MLE & normal approximation (Wald) CI"
# Extract only the Relative Risk point estimate and its 95% Confidence Intervals
rr_summary <- rr_analysis$measure
print(rr_summary)
## NA
## risk ratio with 95% C.I. estimate lower upper
## Unexposed 1 NA NA
## Exposed 2 1.263006 3.167047
Interpretation: The output shows that the exposed group has an RR of 2 (95% CI: 1.26 - 3.17). This means individuals exposed to the factor are exactly 2 times more likely to develop the disease compared to the unexposed group.
When you have real-world data, you usually need to control for
confounding variables like age or sex. Standard logistic regression
(glm with family = binomial) yields an
Odds Ratio. To get an adjusted Relative Risk, you must
fit a Log-Binomial Model using a log link function.
First, let’s transform our summary data into an individual-level data frame:
# Create individual patient data (100 unexposed, 100 exposed)
set.seed(42)
patient_data <- data.frame(
exposure = c(rep("Unexposed", 100), rep("Exposed", 100)),
disease = c(rep(0, 80), rep(1, 20), rep(0, 60), rep(1, 40)),
age = round(runif(200, min = 18, max = 65)) # Simulating a confounder
)
# Convert exposure to a factor using clean string indexing
patient_data[["exposure"]] <- factor(patient_data[["exposure"]], levels = c("Unexposed", "Exposed"))
# Fit the log-binomial regression model
log_binomial_model <- glm(disease ~ exposure + age,
data = patient_data,
family = binomial(link = "log"))
# Exponentiate the regression coefficients to convert them to Relative Risks
relative_risks <- exp(coef(log_binomial_model))
confidence_intervals <- exp(confint(log_binomial_model))
# Combine results into a neat summary table
regression_results <- cbind(RR = relative_risks, confidence_intervals)
print(regression_results)
## RR 2.5 % 97.5 %
## (Intercept) 0.3200208 0.1520058 0.6189747
## exposureExposed 1.9962886 1.2866566 3.2379459
## age 0.9887331 0.9744352 1.0035810
The estimate for exposureExposed represents your
Relative Risk adjusted for the participant’s age.
epitools) is perfect for
unadjusted analysis from raw \(2 \times
2\) summary tables.glm) is the gold standard
when analyzing raw patient data containing multiple clinical
confounders.The Relative Risk measures the risk of the outcome in the exposed group divided by the risk in the unexposed group.
# Calculate risks using your actual matrix variable name
risk_exposed <- study_matrix[2, 2] / (study_matrix[2, 1] + study_matrix[2, 2])
risk_unexposed <- study_matrix[1, 2] / (study_matrix[1, 1] + study_matrix[1, 2])
# Calculate Relative Risk (RR)
relative_risk <- risk_exposed / risk_unexposed
relative_risk
## [1] 2
Based on our fictional data, the Relative Risk is 2.