Four Ways to Work with R Code

SPEA V706 — Statistics for Research in Public Affairs

Coady Wing

The Plan

  • The same analysis can be run four ways
  • From the console, one big script, notebook, to a main.r pipeline
  • Each way has its own strengths and weaknesses

Reproducibility is an important goal

  • Could someone else reproduce this result from scratch? Could you, a year from now?
  • Reproducible means: fresh session, run the code, get the identical numbers

Way 1: The Console

Type a line, hit enter, see the result. Repeat.

dt <- fread(here("raw_data", "wage.csv"))
dt[, mean(wage)]
feols(log(wage) ~ educ, data = dt)
  • Great for exploring — poke at the data, test an idea, check a value
  • Nothing is saved. Close RStudio and the steps are gone
  • You cannot reproduce what you did, because there is no record of it

Way 2: One Big Script

Move the good lines into a saved .r file and run it top to bottom.

# analysis.r — everything, in order
dt <- fread(here("raw_data", "wage.csv"))
dt[, lwage := log(wage)]
# ... 300 more lines ...
est <- feols(lwage ~ educ + exper, data = dt)
  • Now it is saved, ordered, and rerunnable. A real step up from the console
  • It grows. At 500 lines you cannot find anything and is hard to debug

Way 3: Notebooks

Quarto, R Markdown, or Jupyter — code, prose, and output woven together.

## Returns to Education

We estimate a wage regression.

```{r}
est <- feols(lwage ~ educ, data = dt)
etable(est)
```

The coefficient on `educ` is about 0.08.
  • Code, its output, and your writing live in one document that renders to HTML or PDF
  • Seems Ideal for reports, teaching, and anything a human needs to read alongside results
  • These slides are a notebook

Notebooks: The Fine Print

  • Hidden state: you can run cells out of order and get numbers your saved file can’t reproduce
  • Awkward as the home for a big multi-stage pipeline: one giant document gets unwieldy
  • Best use: a communication layer that sits on top of a pipeline

Way 4: main.r + Numbered Scripts

Split the work into small scripts, each doing one job. One file runs them in order.

# main.r — reproduce everything from scratch
library(here)

source(here("code", "01_clean_data.r"))
source(here("code", "02_make_panel.r"))
source(here("code", "03_estimation.r"))
source(here("code", "04_figures.r"))

message("main.r complete")
  • Each numbered script has one responsibility and a header saying its input and output
  • main.r is the recipe: run it in a fresh session and the whole analysis rebuilds
  • This is the research standard

Why the Pipeline Wins for Research

  • One job per script means you can find and fix the cleaning without touching estimation
  • Numbered order is optional but makes the flow of data obvious: 01 feeds 02 feeds 03
  • ** main.r** builds and rebuilds every number in the paper

The Four Styles

Saved? Rerun cleanly? Reproducible? Best for
1. Console no no no exploring, quick checks
2. One script yes partly partly small one-off tasks
3. Notebook yes if you render yes, if disciplined reports, teaching
4. Pipeline yes yes yes research, replication
  • Way 4 is the destination for analysis. Way 3 is how you present it