Cheatsheet
Everything the course uses, with no explanation
For the explanations, see the R primers, the epidemiology primers and the R primer reference.
Epidemiological measures
The 4 cells of a 2×2 table. The third is named cc because c() is a function.
| Disease | No disease | Total | |
|---|---|---|---|
| Exposed | a | b | a + b |
| Unexposed | cc | d | cc + d |
| Measure | Formula | Range | Units |
|---|---|---|---|
| Prevalence | cases / population at one point in time | 0 to 1 | none |
| Risk (cumulative incidence) | new cases / at risk at start | 0 to 1 | needs a time period |
| Incidence rate | new cases / person-time | 0 upward | per person-time |
| Risk ratio | (a/(a+b)) / (cc/(cc+d)) |
0 upward | none |
| Risk difference | a/(a+b) - cc/(cc+d) |
−1 to 1 | none |
| Odds ratio | (a*d) / (b*cc) |
0 upward | none |
| NNT or NNH | 1 / abs(RD) |
1 upward | needs a time period |
| Attributable fraction, exposed | (RR - 1) / RR |
up to 1; negative if protective | none |
| Population attributable fraction | (risk_total - risk_unexposed) / risk_total |
up to 1; negative if protective | none |
a <- 90; b <- 910; cc <- 30; dd <- 970
risk_exposed <- a / (a + b)
risk_unexposed <- cc / (cc + dd)
risk_exposed / risk_unexposed # RR 3.00
risk_exposed - risk_unexposed # RD 0.06
1 / abs(risk_exposed - risk_unexposed) # NNH 16.7 (harmful exposure)
(a * dd) / (b * cc) # OR 3.20The fourth cell is dd, not d, because d is used below for a dataset.
With confidence intervals:
library(epitools)
# epitools wants the unexposed row first and the non-case column first.
# It does NOT reorder for you; pass rev= if your table is the other way round.
tab <- matrix(c(dd, cc, b, a), nrow = 2, byrow = TRUE)
riskratio(tab, method = "wald")
oddsratio(tab, method = "wald")
riskratio(tab)$measure # the estimate and its 95% CIRead the table epitools prints back before you trust the number.
Which measure for which design
| Design | You may compute |
|---|---|
| Cohort | risk, rate, RR, RD, OR |
| Case-control | OR (what it estimates depends on how controls were sampled) |
| Cross-sectional | prevalence, prevalence ratio, prevalence OR |
| Trial | risk, rate, RR, RD, NNT |
R basics
x <- c(34, 51, 22, 67, 45, 19, 58, NA) # a vector, with one value missing
length(x); class(x) # how many, what type
sum(x, na.rm = TRUE) # 296
mean(x, na.rm = TRUE) # 42.3
median(x, na.rm = TRUE); sd(x, na.rm = TRUE)
min(x, na.rm = TRUE); max(x, na.rm = TRUE); range(x, na.rm = TRUE)
mean(x) # NA - one value is unknown, so the mean is unknown
sum(is.na(x)) # 1
sum(x >= 45, na.rm = TRUE) # 4 - a count
mean(x >= 45, na.rm = TRUE) # 0.571 - a proportion
round(mean(x, na.rm = TRUE), 1)Looking at a dataset
nrow(d); ncol(d); dim(d)
names(d)
str(d)
glimpse(d) # dplyr
summary(d)
head(d, 10)
table(d$district)
table(d$district, useNA = "ifany")
table(d$exposed, d$disease)dplyr
library(dplyr)
d |> filter(age >= 50)
d |> filter(age >= 50, sex == "Female") # comma means AND
d |> filter(district %in% c("Kolar", "Hassan"))
d |> select(id, age, sbp)
d |> select(-dbp)
d |> rename(bp = sbp)
d |> mutate(bmi_cat = if_else(bmi >= 25, "overweight", "normal"))
d |> mutate(band = case_when(
age < 40 ~ "under 40",
age < 60 ~ "40-59",
.default = "60+"
))
d |> arrange(age)
d |> arrange(desc(age))
d |> count(district)
d |> count(district, sort = TRUE)
d |>
group_by(district) |>
summarise(
n = n(),
mean = round(mean(age), 1),
risk = round(mean(event), 3)
)filter() silently drops rows where the condition is NA. Count rows before and after.
Put n() in every summarise().
ggplot2
library(ggplot2)
ggplot(d, aes(x = age, y = sbp)) + geom_point()
ggplot(d, aes(x = sbp)) + geom_histogram(binwidth = 10)
ggplot(d, aes(x = district, y = sbp)) + geom_boxplot()
ggplot(d, aes(x = district)) + geom_bar()
ggplot(d, aes(x = district, y = n)) + geom_col() # when you have the counts
ggplot(d, aes(x = date, y = cases)) + geom_line()Inside aes() means the property comes from a column. Outside aes() means a fixed setting.
ggplot(d, aes(x = age, y = sbp, colour = smoker)) +
geom_point(size = 2, alpha = 0.6) +
facet_wrap(~ district) +
labs(title = "...", x = "...", y = "...", colour = "...", caption = "...") +
theme_minimal()Layers join with +, not |>.
Tables for a paper
library(gtsummary)
d |>
select(age, sex, smoker, sbp, event) |>
tbl_summary(by = event) |>
add_p() |>
add_overall()glm(event ~ smoker + age + sex, data = d, family = binomial) |>
tbl_regression(exponentiate = TRUE)exponentiate = TRUE turns log-odds into odds ratios. Without it the column is not an OR.
Keyboard shortcuts in RStudio
| Shortcut | Does |
|---|---|
| Ctrl+Enter | run the current line |
| Ctrl+Shift+M | insert the pipe |
| Ctrl+Shift+F10 | restart R |
| Tab | complete a name |
| F1 on a function | open its help |
On macOS, use Cmd in place of Ctrl.
Getting help inside R
?mean # help for one function
??"risk ratio" # search all help
args(round) # what arguments it takes
sessionInfo() # your R version and loaded packages