cassionData Analysis

Back to the lessonLesson 2 of 8Getting set up

A working environment in Python and R

The same deck as the downloads, rendered as a page. Start the slideshow to present it full screen — arrow keys or a click advance one slide, Escape leaves.

Slides · PDFSlides · PowerPoint

  1. Slide 1 / 13

    What this lesson covers

    • Why this lesson is not optional
    • Python: use uv, not the system interpreter
    • R: use Projects and renv
    • A project layout that survives a handover
    • The same first script, in both languages
    • What the two languages disagree about
    • What comes next
    Speaker notes
    Install Python and R so they still work on a bad connection, lay out a project directory that survives a handover, and run the same first script in both languages.
  2. Slide 2 / 13

    Why this lesson is not optional

    • The most common reason an M&E analysis stops being reproducible is not a statistical error.
    Speaker notes
    The most common reason an M&E analysis stops being reproducible is not a statistical error. It is that the person who wrote it installed a package one afternoon, never recorded which one, and left. Six months later the script raises an import error on a laptop in a field office with a satellite link, and the quarterly report goes back to being made by hand in a spreadsheet. Ten minutes of setup now is what prevents that.
  3. Slide 3 / 13

    Python: use uv, not the system interpreter — Shell

    # Install uv (macOS and Linux)
    curl -LsSf https://astral.sh/uv/install.sh | sh
    
    # Create a project and pin an interpreter
    uv init muac-analysis
    cd muac-analysis
    uv python install 3.13
    
    # Add what this course uses
    uv add pandas pyarrow matplotlib
    Speaker notes
    Your operating system ships a Python. Do not analyse data with it — it is there to run the operating system, and changing it can break things you did not know depended on it. uv installs an isolated Python and resolves packages fast enough to be usable on a slow connection. It also writes a lock file, which is what makes the environment reproducible on someone else's machine.
  4. Slide 4 / 13

    Python: use uv, not the system interpreter — Shell

    uv sync
    Speaker notes
    uv add writes both pyproject.toml (what you asked for) and uv.lock (exactly what was installed, down to the hash). Commit both. A colleague then reproduces your environment with one command: If you are behind a proxy or working offline, uv can install from a local wheel directory. Downloading the wheels once, onto a USB stick, and installing from it is a normal workflow in this sector and is worth setting up before you need it.
  5. Slide 5 / 13

    R: use Projects and renv — In R

    # Once per machine
    install.packages("renv")
    
    # Once per analysis, from inside an RStudio Project
    renv::init()
    
    # Add what this course uses
    install.packages(c("readr", "dplyr", "tidyr", "ggplot2", "janitor"))
    
    # Record exactly what is installed
    renv::snapshot()
    Speaker notes
    R's equivalent problem is the global library — packages installed into one shared location, invisibly shared across every analysis, and silently upgraded under you.
  6. Slide 6 / 13

    R: use Projects and renv

    • Work inside a Project. The working directory is then the project root, for everyone, always. Paths like…
    • Never write setwd(). It encodes your username into the analysis and guarantees it fails for the next person.
    Speaker notes
    renv.lock is the equivalent of uv.lock. Commit it. A colleague runs renv::restore() and gets your library, not theirs. Two habits matter as much as the tooling:
  7. Slide 7 / 13

    A project layout that survives a handover — Example

    muac-analysis/
      data/
        raw/          # exactly as it arrived. Read-only. Never edited.
        interim/      # intermediate output. Disposable.
        processed/    # analysis-ready. Regenerable from raw + code.
      scripts/
        01-read.py
        02-clean.py
        03-indicators.py
      output/
        figures/
        tables/
      README.md
    Speaker notes
    The same structure works in both languages. It is worth adopting exactly, because the value is in it being predictable rather than in it being clever.
  8. Slide 8 / 13

    A project layout that survives a handover

    A useful test: delete data/processed/ and output/ entirely, rerun your scripts, and see whether you get the same results. If you cannot bring yourself to try it, you already know the answer.
    Speaker notes
    One rule carries most of the weight: data/raw/ is read-only. If you open the export in Excel, fix three cells and save it, you have destroyed the only record of what actually arrived, and nobody — including you — can ever again tell what was original and what was a correction. Everything downstream of data/raw/ should be reproducible by deleting it and rerunning the scripts. If it is not, something is being done by hand, and that something is the part that will break.
  9. Slide 9 / 13

    The same first script, in both languages — In Python

    import pandas as pd
    
    muac = pd.read_csv("data/raw/muac-screening-artibonite-2024.v1.csv")
    
    print(muac.shape)
    print(muac.head())
    print(muac.dtypes)
    Speaker notes
    Read the register, look at its shape, and print the first few rows. Nothing more — the point is to confirm the environment works before you depend on it.
  10. Slide 10 / 13

    The same first script, in both languages — In R

    library(readr)
    library(dplyr)
    
    muac <- read_csv("data/raw/muac-screening-artibonite-2024.v1.csv")
    
    dim(muac)
    head(muac)
    glimpse(muac)
    Speaker notes
    Both should report 4,218 rows and 8 columns. If they do not, stop here — a row count that disagrees with the source is the cheapest error you will ever catch, and it gets much more expensive three scripts later.
  11. Slide 11 / 13

    What the two languages disagree about

    Concernpandasdplyr / readr
    Missing valueNaN, and None for objectsNA, typed per column
    Reading a CSVpd.read_csv guesses typesread_csv guesses and reports
    Chaining stepsMethod chaining or reassignmentThe pipe, \|>
    Grouped summarygroupby().agg()group_by() \|> summarise()
    Categoriescategory dtype, opt-inFactors, and they bite
    Speaker notes
    You will use both, so it helps to know where they differ in ways that matter. Neither is better. The one that matters is the one your team already runs, and the reason this course teaches both is that you will change teams.
  12. Slide 12 / 13

    What comes next

    • The next lesson reads the export properly — which is harder than read_csv(path), because the defaults will quietly damage identifiers, dates and the missing-value code before you have looked at anything.
    Speaker notes
    The next lesson reads the export properly — which is harder than read_csv(path), because the defaults will quietly damage identifiers, dates and the missing-value code before you have looked at anything.
  13. Slide 13 / 13

    Where this goes next

    Read the full lesson, with runnable code Back to the lesson