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.20

The 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% CI

Read 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
Back to top