0%
DQDigital Qasas Courses/Medical Statistics with R and Python
Sign inAll courses
  • Why R and Python, and running them in your browser
  • Data frames, import, and tidy medical data
  • Tables and summaries
  • Variables, types, and the question behind the data
  • Displaying data: frequency distributions, histograms, and shape
  • Means, standard deviations and standard errors
  • The normal distribution
  • Confidence interval for a mean
  • Using P-values and confidence intervals
  • Comparison of two means
  • Analysis of variance
  • Linear regression and correlation
  • Multiple regression and diagnostics
  • Transformations
  • Risk, odds, and how to compare them
  • Proportions and the binomial distribution
  • Two proportions: risk ratio, odds ratio, risk difference, and confidence intervals
  • Chi-squared: 2x2 tables, larger tables, trend, and exact tests
  • Confounding and stratification
  • Logistic regression
  • Matched studies
  • Rates and the Poisson distribution
  • Comparing rates and Poisson regression
  • Standardization: direct, indirect, and the SMR
  • Kaplan-Meier survival curves and the log-rank test
  • Cox proportional-hazards regression
  • Likelihood and the generalized linear model
  • Building models, checking assumptions, and clustered data
  • Systematic reviews and meta-analysis
  • Bayesian statistics
  • Linking analysis to study design
  • Sample size and power
  • Measurement error and its consequences
  • Capstone: from a messy dataset to a reported result
0. Getting started: R and Python for medical data

Why R and Python, and running them in your browser

Last updated 30 June 2026

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:

LanguageBuilt forStrongest atWhere you meet it
Rstatistics and data analysisconcise regression, survival, and epidemiology packages (epiR, survival)clinical trials, cohort studies, journal papers
Pythongeneral programmingmachine learning, data engineering, automation, dashboardshospital 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?

  • R uses hr <- 88 and Python uses hr = 88.
  • R uses hr = 88 and Python uses hr <- 88.
  • Both languages use hr == 88.
R's assignment operator is the arrow <-, 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 level x = 5 happens to work, but the course style is x <- 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. Writing if (hr = 88) when you meant if (hr == 88) is a classic bug in both languages.
  • Forgetting ddof=1 in numpy. np.std() and np.var() divide by by default, so they return the population figure. R and most teaching use the sample version. Set ddof=1 when you compare results across the two languages.
  • Counting with the wrong tool. length() in R and len() 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 to np.array(), length() maps to len(), mean() maps to np.mean(). Most basics differ only in spelling.
  • Name variables for what they hold. sbp or systolic reads better than x, and your future self will thank you.
  • When a function surprises you, read its help (?name in 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's mean() and sd() 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() for the average and length() for the count.
  • mean() for the average and sum() for the count.
  • c() for the average and mean() for the count.
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().
Next →Data frames, import, and tidy medical data
On this page
  • Why this course uses both
  • A one-line orientation to each
  • Running code with no install
  • Variables and assignment
  • Vectors and arrays: several patients at once
  • Calling functions and reading their arguments
  • Getting help
  • Comments, and code you can re-read
  • Worked example: mean and standard deviation of clinic readings
  • Common mistakes
  • Tips