Why R and Python, and running them in your browser
Last updated
This course teaches you to do medical statistics in two languages, R and Python, because the people who hire analysts in health settings use both. R was written by statisticians, and most new statistical and epidemiological methods appear as an R package first. Python is a general-purpose language that runs the data pipelines, machine learning, and production systems around the analysis. You do not have to pick a side. By the end you will read and write both, and reach for whichever fits the task in front of you.
Start here with no assumptions. You have never opened R or Python, you do not need to install anything, and you can run every code block on this page right now.
Why this course uses both
The two languages overlap on the basics and diverge on the hard tasks. A short map of where each one earns its keep:
| Language | Built for | Strongest at | Where you meet it |
|---|---|---|---|
| R | statistics and data analysis | concise regression, survival, and epidemiology packages (epiR, survival) | clinical trials, cohort studies, journal papers |
| Python | general programming | machine learning, data engineering, automation, dashboards | hospital data systems, ML models, glue code |
A practical way to think about it: when your job is to estimate a risk ratio, fit a survival model, or reproduce a method from a paper, R usually gets you there in fewer lines. When your job is to pull records from a database, clean a messy export, or serve a prediction, Python is the steadier choice. Both compute a mean the same way, so the gap only shows up on the harder work.
A one-line orientation to each
R is a language and environment for statistics and graphics. You type a command, it computes, it prints the answer. Everything is built around vectors of numbers and tables of data, which is exactly the shape of a dataset.
Python is a general-purpose programming language with libraries that add the data tools. For analysis you load numpy for arrays of numbers, pandas for tables, and scipy for statistical tests. The same Python also writes web servers and trains models, which is why it spreads well beyond statistics.
Running code with no install
Normally you would download R or Python and set up an editor before writing a line. This course skips that. The code blocks on this page run inside your browser. R runs through WebR, and Python runs through Pyodide, both compiled to execute on the page itself. Nothing installs, nothing uploads, and your code never leaves the browser tab.
Each block has three controls. Run executes the code and shows the output below it. You can edit the code directly, then run it again to see what changed. Reset puts the original code back when an experiment goes sideways. Where a topic works in both languages, an R | Python switcher at the top of the block lets you flip between the two versions. Try changing a number and re-running. That is how you learn this, by poking at it.
Tip
The first time you run an R or Python block, the browser downloads the language engine, so it can take a few seconds. After that, every run is quick. If a block seems to hang on its first run, give it a moment rather than clicking Run again and again.
Variables and assignment
A variable is a name you attach to a value so you can use it again. Storing one patient's systolic blood pressure looks like this. In R you assign with the arrow <-. In Python you assign with a single equals sign =. The idea is identical: put the value on the right into the name on the left.
Store one patient's systolic blood pressure in a variable, then print it.
# one patient's systolic blood pressure (mmHg)
sbp <- # fill in the reading
sbp <- 128 sbp # [1] 128
Store one patient's systolic blood pressure in a variable, then print it.
# one patient's systolic blood pressure (mmHg)
sbp = # fill in the reading
sbp = 128 print(sbp) # 128
Vectors and arrays: several patients at once
Medical data is rarely a single number. You measure the same thing across many patients and want to hold all the readings together. R calls an ordered set of values a vector, built with c() (short for combine). Python's numpy gives you an array, built with np.array() from a plain list written in square brackets. Both are the natural container for one column of a dataset, such as the systolic readings of six patients at a Klinik Kesihatan.
Hold six systolic readings in one vector, then report how many readings there are and their average.
sbp <- c(128, 142, 135, 119, 150, 131)
n <- # how many readings?
n <- length(sbp) avg <- mean(sbp) c(n = n, mean = avg) # n mean # 6.0 134.1667
Hold six systolic readings in one array, then report how many readings there are and their average.
import numpy as np sbp = np.array([128, 142, 135, 119, 150, 131])
n = # how many readings?
n = len(sbp) avg = np.mean(sbp) print(n, round(avg, 4)) # 6 134.1667
Calling functions and reading their arguments
You just called three functions in each language: c(), length(), and mean() in R, with np.array(), len(), and np.mean() as the Python counterparts. A function takes one or more inputs, called arguments, and returns a result. You write the function name, then the arguments in round brackets. mean(sbp) passes the vector sbp as the single argument to mean, and gets back the average.
Functions often accept more than one argument. R's mean() has an na.rm argument that tells it to ignore missing values, which you pass by name as mean(sbp, na.rm = TRUE). Reading which arguments a function accepts is most of the skill, and the language will tell you if you ask.
Getting help
When you forget how a function works, ask the language directly. In R, type a question mark before the name: ?mean opens its help page, listing every argument and what the function returns. To see just the argument list, args(mean) prints the signature. In Python the docstring carries the same information. help(np.mean) prints it, and np.mean.__doc__ holds the raw text. Reading the help is normal working practice, not a sign you forgot something.
Inspect a function's arguments without leaving your code.
# show the argument list of a built-in function
args(mean)
args(mean) # function (x, ...) # NULL
Read the start of a function's docstring, the same text help() would show.
import numpy as np
help(np.mean)
print(np.mean.__doc__[:90]) # Compute the arithmetic mean along the specified axis.
Comments, and code you can re-read
Anything after # on a line is a comment. Both languages ignore it when they run. Comments are notes to the next person who reads the code, usually you in three months. Write the why, not the obvious what. A line that reads sbp <- c(128, 142, 135) # systolic, mmHg, morning clinic tells a reader the units and the source, which the bare numbers do not. Clear names help just as much. sbp beats x once you have five variables in play.
You want to store a patient's heart rate of 88 in a variable called hr. Which line is correct in R, and which in Python?
<-, while Python assigns with a single =. The double equals == is a comparison (is this value equal to that one?) in both languages, so hr == 88 asks a question rather than storing a value. Mixing up = and == is one of the most common errors when you start.Worked example: mean and standard deviation of clinic readings
Put the pieces together on a realistic task. Six patients attend a Klinik Kesihatan morning clinic, and you record their systolic blood pressure. You want two summaries: the average reading, and how far the readings spread around it. That spread is the standard deviation, the typical distance of a reading from the mean, written .
R has sd() built in, and it uses the sample formula that divides by . numpy's np.std() divides by by default, so you pass ddof=1 to get the sample standard deviation that matches R. With that one setting the two languages agree.
From the six readings, compute the mean and the sample standard deviation.
sbp <- c(128, 142, 135, 119, 150, 131)
avg <- # fill in s <- # fill in
avg <- mean(sbp) s <- sd(sbp) round(c(mean = avg, sd = s), 2) # mean sd # 134.17 10.87
From the six readings, compute the mean and the sample standard deviation.
import numpy as np sbp = np.array([128, 142, 135, 119, 150, 131])
avg = # fill in s = # fill in
avg = np.mean(sbp) s = np.std(sbp, ddof=1) print(round(avg, 2), round(s, 2)) # 134.17 10.87
Watch out
R's sd() and numpy's np.std() do not return the same number by default. sd() divides by (the sample standard deviation), while np.std() divides by . On these six readings that is the difference between 10.87 and 9.92. Pass ddof=1 to numpy whenever you want the sample standard deviation that R and most statistics textbooks use.
Common mistakes
- Using
=where R expects the arrow. At the top levelx = 5happens to work, but the course style isx <- 5, and inside a function call=means "set this argument", not "assign a variable". Keep<-for assignment and you avoid the ambiguity. - Confusing
=with==. A single=stores a value; a double==tests whether two values are equal. Writingif (hr = 88)when you meantif (hr == 88)is a classic bug in both languages. - Forgetting
ddof=1in numpy.np.std()andnp.var()divide by by default, so they return the population figure. R and most teaching use the sample version. Setddof=1when you compare results across the two languages. - Counting with the wrong tool.
length()in R andlen()in Python count how many readings you have.mean()tells you the average, not the count. Reaching for the wrong one returns a number that looks plausible but answers a different question.
Tips
- Run every block on this page, then change a number and run it again. Reading code teaches less than breaking it and watching what happens.
- Keep one mental translation table:
<-maps to=,c()maps tonp.array(),length()maps tolen(),mean()maps tonp.mean(). Most basics differ only in spelling. - Name variables for what they hold.
sbporsystolicreads better thanx, and your future self will thank you. - When a function surprises you, read its help (
?namein R,help()in Python) before searching the web. The answer is usually in the first paragraph. - Load numpy once at the top of a Python block with
import numpy as np. R'smean()andsd()are built in and need no import.
A nurse hands you systolic readings for 40 patients and asks two things: what is the average, and how many did you measure? In R, which two functions answer those questions?
mean() adds the readings and divides by how many there are, giving the average. length() reports how many elements the vector holds, which is the count of patients. sum() would add the readings into a total near 5,000 mmHg, not count them, and c() only builds the vector in the first place. The Python equivalents are np.mean() and len().