Back to the lesson·Lesson 2 of 8·Getting 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.
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.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.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 matplotlibSpeaker 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.uvinstalls 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.Python: use uv, not the system interpreter — Shell
uv syncSpeaker notes
uv addwrites bothpyproject.toml(what you asked for) anduv.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,uvcan 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.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.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.lockis the equivalent ofuv.lock. Commit it. A colleague runsrenv::restore()and gets your library, not theirs. Two habits matter as much as the tooling: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.mdSpeaker 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.A project layout that survives a handover
A useful test: delete
data/processed/andoutput/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 ofdata/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.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.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.What the two languages disagree about
Concern pandas dplyr / readr Missing value NaN, andNonefor objectsNA, typed per columnReading a CSV pd.read_csvguesses typesread_csvguesses and reportsChaining steps Method chaining or reassignment The pipe, \|>Grouped summary groupby().agg()group_by() \|> summarise()Categories categorydtype, 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.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 thanread_csv(path), because the defaults will quietly damage identifiers, dates and the missing-value code before you have looked at anything.- The next lesson reads the export properly — which is harder than