Skip to main content
Back to module
Regression & Experimental Design · Statistical Consulting

Statistical software and reproducibility

Reading1hLesson 3 of 3 in this module

Compare R and Python for statistics and rerun an analysis reproducibly in a second tool.

Why this matters

A statistical result is only as trustworthy as your ability to produce it again. Reviewers, auditors and future colleagues will ask for it, and so will you, six months later, when new data arrive or a number in the report looks odd. Reproducibility is also how errors get caught: a famous 2013 re-analysis of an influential economics paper found a spreadsheet error simply because the original authors shared their file. This lesson covers the main statistical software tools and the habits that make an analysis rerunnable.

The main tools

ToolStrengthsTypical users
RWidest range of statistical methods; lme4, emmeans, ggplot2, the tidyverse; R Markdown / QuartoStatisticians, biostatistics, academic research
Pythonpandas, statsmodels, scipy, scikit-learn, matplotlib; one language from data cleaning to productionData science, ML, engineering, OR
SASLong history in pharma and government; validated proceduresClinical trials, regulated industries
JMP, Minitab, Design-ExpertPoint-and-click DOE and quality toolsProcess engineers, Six Sigma, labs
Stata, SPSSSurvey and social-science analysesEconomics, public health, social sciences

You do not need all of them. Be fluent in one of R or Python, able to read the other, and comfortable reading output from the point-and-click tools your collaborators use. Most methods in this course exist in both:

TaskRPython
Linear modellm(y ~ x1 + x2)smf.ols("y ~ x1 + x2", df).fit()
GLMglm(y ~ x, family = poisson)smf.glm("y ~ x", df, family=sm.families.Poisson()).fit()
ANOVA tableanova(model) / car::Anovaanova_lm(model, typ=2)
Mixed modellme4::lmer(y ~ x + (1 | g))smf.mixedlm("y ~ x", df, groups=df["g"]).fit()
Tukey HSDTukeyHSD(aov(...))pairwise_tukeyhsd(y, group)

Defaults differ. R's anova() gives sequential (Type I) sums of squares; statsmodels' anova_lm(typ=2) gives Type II. For unbalanced data these can disagree. Contrast coding, optimisers and degrees-of-freedom methods for mixed models also differ. When two tools give different answers, it is usually a default, and you should be able to find which one.

Habits of a reproducible analysis

  1. Raw data is read-only. Never edit the original file. All cleaning happens in code, so every change is recorded.
  2. One script (or notebook) runs everything, from raw data to every number and figure in the report. If a number in the report was typed by hand, it can drift from the analysis.
  3. Fix random seeds for randomisation, simulation, bootstrapping and train/test splits, and record them.
  4. Record versions. In Python, pip freeze > requirements.txt or a pyproject.toml; in R, renv::snapshot(). Note the language version too.
  5. Use version control (Git) for code and the report. Commit messages explain why things changed.
  6. Literate documents (Quarto, R Markdown, Jupyter) mix code, output and text so the report regenerates from data. Restart and run all before sharing a notebook; out-of-order cells are a common source of irreproducible results.
  7. Organise the project predictably:
project/
  data/raw/          original files, never edited
  data/processed/    written by code only
  src/ or R/         analysis code
  reports/           Quarto / notebook that builds the report
  requirements.txt   or renv.lock
  README.md          how to rerun, in three lines

Cross-checking in a second tool

A strong check on an important result is to rerun it independently: a colleague reproduces it from the methods section alone, or you reproduce it in a second tool. For the catalyst ANOVA from module 2:

from scipy import stats
print(stats.f_oneway([82, 85, 88, 84, 86], [90, 92, 89, 93, 91], [84, 83, 86, 85, 82]))
# F_onewayResult(statistic=21.5, pvalue=0.000108...)
d <- data.frame(y = c(82,85,88,84,86, 90,92,89,93,91, 84,83,86,85,82),
                catalyst = rep(c("A","B","C"), each = 5))
summary(aov(y ~ catalyst, data = d))   # F value 21.5

Free ways to try both without installing anything: Google Colab for Python and webR or Posit Cloud (free tier) for R. Free tiers and their limits change; check the provider's page before relying on one.

Common mistakes

  • Copying numbers by hand from output into a report.
  • "It works on my machine": no record of package versions.
  • Unseeded randomness, so the bootstrap interval changes every run.
  • Hidden state in notebooks (cells run out of order, variables defined in deleted cells).
  • Overwriting raw data while cleaning.
  • Trusting one tool's default without knowing what it is.

Quick recap

  • Know R or Python well and read the other; know how their defaults differ.
  • Raw data read-only, one script end to end, seeds, versions, Git, literate reports.
  • Cross-check important results in a second tool or by a colleague.

Try it

In the Do tab you will rerun an analysis from this course in a second tool (R or Python), record the environment and confirm the numbers match.

Also in this lesson: