Python to R: A Quick Reference

You already know how to program. This page maps the Python patterns you used in GEOL1151 to their R equivalents. Keep it open during the first few weeks.


The big picture

Python (GEOL1151) R (this course)
Data container NumPy array (data[:,0]) Data frame (df$column)
Plotting matplotlib (plt.plot()) ggplot2 (ggplot() + geom_...())
File I/O np.loadtxt(), pd.read_excel() read.csv()
Stats np.mean(), np.std() mean(), sd(), t.test(), aov()
Environment Jupyter notebooks Quarto Live (WebR in browser)

The single biggest change: in Python you worked mostly with arrays (grids of numbers). In R you’ll work mostly with data frames (tables where each column has a name and can be a different type).


Variables and assignment

# Python
x = 42
name = "Durham"
# R
x <- 42
name <- "Durham"

R uses <- for assignment. = also works but <- is the convention.


Vectors (like 1D arrays)

# Python
import numpy as np
temps = np.array([15.2, 16.1, 14.8, 17.3])
temps.mean()        # 15.85
temps[0]            # 15.2 (0-indexed)
temps[1:3]          # array([16.1, 14.8])
# R
temps <- c(15.2, 16.1, 14.8, 17.3)
mean(temps)         # 15.85
temps[1]            # 15.2 (1-indexed!)
temps[2:3]          # 16.1  14.8

Watch out: R is 1-indexed. The first element is [1], not [0].


Loading data

# Python — NumPy (whitespace-delimited)
data = np.loadtxt("rocks.dat", skiprows=1)

# Python — Pandas (CSV or Excel)
import pandas as pd
df = pd.read_csv("data.csv")
df = pd.read_excel("data.xlsx")
# R — CSV
df <- read.csv("data.csv")

# First few rows
head(df)

# Column names
names(df)

# Dimensions
nrow(df)
ncol(df)

Accessing columns

# Python — NumPy array
data[:, 0]          # First column (by position)

# Python — Pandas DataFrame
df["temperature"]   # By name
df.temperature      # Also by name (dot notation)
# R — data frame
df$temperature      # By name (most common)
df[, 1]             # By position
df[, "temperature"] # By name (bracket notation)

The $ operator is your main tool for getting at columns.


Filtering rows

# Python — NumPy
hot = data[data[:, 2] > 30, :]

# Python — Pandas
hot = df[df["temperature"] > 30]
# R — base
hot <- df[df$temperature > 30, ]

# R — dplyr (from Week 2 onward)
library(dplyr)
hot <- df |> filter(temperature > 30)

Note the comma in df[rows, ] — R needs it to distinguish row selection from column selection.


Creating new columns

# Python — Pandas
df["density"] = df["mass"] / df["volume"]
# R — base
df$density <- df$mass / df$volume

# R — dplyr
df <- df |> mutate(density = mass / volume)

Summary statistics

# Python
np.mean(data[:, 0])
np.median(data[:, 0])
np.std(data[:, 0])
np.min(data[:, 0])
np.max(data[:, 0])
len(data)
# R
mean(df$temperature)
median(df$temperature)
sd(df$temperature)
min(df$temperature)
max(df$temperature)
nrow(df)

# All at once
summary(df$temperature)

Note: R’s sd() uses n−1 (sample SD) by default. NumPy’s np.std() uses n (population SD) by default. For the same result as R, you’d need np.std(x, ddof=1) in Python.


Plotting

Quick base R plots (Week 1)

# Python — matplotlib
plt.plot(data[:, 0], data[:, 4])
plt.xlabel("Year")
plt.ylabel("Flow rate")
plt.title("River Wear")
# R — base graphics
plot(df$year, df$flow,
     xlab = "Year",
     ylab = "Flow rate",
     main = "River Wear")

Histograms

plt.hist(density, bins=20)
hist(df$density, breaks = 20)

ggplot2 (from Week 2)

ggplot2 takes a different approach from matplotlib. Instead of calling separate functions for each element, you build a plot by adding layers:

library(ggplot2)

ggplot(df, aes(x = year, y = flow)) +
  geom_line()

ggplot(df, aes(x = density)) +
  geom_histogram(bins = 20)

ggplot(df, aes(x = formation, y = temperature)) +
  geom_boxplot()

The pattern is always: ggplot(data, aes(...)) sets up the mapping, then geom_...() draws the geometry. You’ll find this more systematic than building plots one plt. call at a time.


Functions

# Python
def celsius_to_kelvin(temp):
    return temp + 273.15
# R
celsius_to_kelvin <- function(temp) {
  temp + 273.15
}

R returns the last expression in a function automatically — no return needed (though return() exists if you want it).


Loops and conditionals

# Python
for year in range(2000, 2025):
    if year % 4 == 0:
        print(year, "is a leap year")
# R
for (year in 2000:2024) {
  if (year %% 4 == 0) {
    cat(year, "is a leap year\n")
  }
}

You’ll rarely need explicit loops in R — most operations work on whole vectors at once. For example, mean(df$temperature) averages all values without a loop.


The pipe: |>

R has a pipe operator that chains operations left to right:

# Without pipe
summary(subset(df, year > 2010))

# With pipe
df |>
  subset(year > 2010) |>
  summary()

Read |> as “then”. It passes the result of the left side as the first argument to the right side. You’ll use this heavily from Week 2.


Things that will trip you up

Gotcha Python R
Indexing starts at 0 1
Assignment = <-
Exponentiation ** ^
Integer division // %/%
Modulo % %%
Boolean AND/OR and / or & / | (vectorised)
Not equal != != (same)
Print print() print() or just type the name
NULL/None None NULL
Missing values NaN / None NA
Check missing pd.isna() / np.isnan() is.na()
String quotes 'single' or "double" "double" preferred
Comments # # (same)

Getting help

# R — help on a function
?mean
help(mean)

# Search help
??histogram

In Python you used help(np.mean) or np.mean? in Jupyter. Same idea, different syntax.