Cheatsheet

Everything you need for these two days, on one page

Keep this open in a second tab.

Setup

library(tidyverse)     # dplyr, ggplot2, readr, tidyr, stringr, forcats
library(gtsummary)

students <- read_csv("data/meded_students.csv")
osce     <- read_csv("data/osce_stations.csv")

Look at your data

Function Shows
glimpse(df) Types and first values, use this most
str(df) Structure, base R version
head(df, 10) First rows
names(df) Column names
nrow(df) / ncol(df) Dimensions
summary(df) Descriptives per column
count(df, var) Frequency table
skimr::skim(df) Everything, prettily

dplyr

df |> filter(score > 70, sex == "Female")   # rows; comma = AND
df |> filter(batch %in% c("2023", "2024"))  # set membership
df |> select(id, score, arm)                # columns
df |> select(starts_with("q"))              # helpers
df |> arrange(desc(score))                  # sort
df |> mutate(pct = 100 * score / max_score) # new column
df |> rename(new_name = old_name)
df |> distinct()                            # drop duplicate rows
df |> slice_head(n = 5)

df |>
  group_by(arm) |>
  summarise(
    n    = n(),
    mean = mean(score, na.rm = TRUE),
    sd   = sd(score,   na.rm = TRUE),
    .groups = "drop"
  )

Conditional recoding

df |> mutate(pass = if_else(score >= 50, "Yes", "No"))

df |> mutate(band = case_when(
  score >= 75 ~ "Distinction",
  score >= 50 ~ "Pass",
  .default    = "Fail"
))

Joins and reshaping

left_join(a, b, by = "student_id")     # keep all of a
inner_join(a, b, by = "student_id")    # keep matches only

long  |> pivot_wider(names_from = domain, values_from = score)
wide  |> pivot_longer(cols = q1:q5, names_to = "item", values_to = "response")

Always check nrow() after a join.

ggplot2

ggplot(df, aes(x = var1, y = var2, colour = group)) +
  geom_point() +
  facet_wrap(~ site) +
  labs(title = "...", x = "...", y = "...", colour = "...") +
  theme_minimal()
Geom For
geom_histogram(binwidth = 5) One continuous variable
geom_density() Smoothed distribution
geom_boxplot() Continuous by category
geom_jitter(width = .15, alpha = .3) Raw points on top of a boxplot
geom_point() Two continuous variables
geom_smooth(method = "lm") Fitted line
geom_col() Bars from values you computed
geom_bar() Bars from counts R computes
ggsave("output/fig1.png", width = 7, height = 4.5, dpi = 300, bg = "white")

Remember: inside aes() = mapped to a variable; outside = fixed.

gtsummary

df |>
  select(arm, age, sex, score) |>
  tbl_summary(
    by = arm,
    label     = list(age ~ "Age (years)"),
    statistic = all_continuous() ~ "{mean} ({sd})",
    digits    = all_continuous() ~ 1,
    missing   = "ifany"
  ) |>
  add_p() |>
  add_overall() |>
  bold_labels() |>
  modify_caption("**Table 1.** Characteristics.")

lm(score ~ arm + age, data = df) |>
  tbl_regression(exponentiate = FALSE) |>
  add_glance_table(include = c(nobs, r.squared))

Quarto

---
title: "My analysis"
format:
  html: {toc: true}
  docx: default
execute: {echo: false, warning: false}
---

```{r}
#| label: fig-gain
#| fig-cap: "Gain by arm."
#| echo: false
```

Mean gain was `r knitr::inline_expr("round(mean(df$gain, na.rm = TRUE), 1)")`.
See @fig-gain.
Chunk option Effect
echo: false Hide code
eval: false Don’t run
include: false Run silently
fig-cap: / tbl-cap: Captions
label: fig-x / tbl-x Cross-references

Keyboard shortcuts

Shortcut Does
Ctrl/Cmd + Enter Run current line
Ctrl/Cmd + Shift + K Render
Ctrl/Cmd + Shift + F10 Restart R
Alt + - Insert <-
Ctrl/Cmd + Shift + M Insert the native pipe
Ctrl/Cmd + Shift + C Comment / uncomment
Tab Autocomplete
Ctrl/Cmd + Shift + P Command palette
Back to top