Intro to R
R is a language you speak with a computer, and the conversation has two forms. In the console you say one thing and get one answer, like sending a message. In a script you write the whole conversation down, so it can be repeated, corrected and sent to someone else.
An .R script is a plain text document. You can open it in a text editor, in a browser, or in a proper development environment such as RStudio.1 Nothing about it is secret or binary — this link opens one straight in your browser.
Everything in this section runs in the page. You do not need to install anything yet.
R is a calculator
The box below is not a picture of R — it is R, running inside this page. Edit the code, press Run, and the answer appears underneath, exactly as it would in a console. Test it.
The first Run takes a moment, because R itself has to be downloaded first. Everything after that is instant, and nothing you type ever leaves your computer.
Try deleting everything and typing 1:20 instead.
Definition
Basic arithmetic operators are:
+Addition-Subtraction*Multiplication/Division^Exponent
R is more than a calculator
A calculator returns a number. R returns objects — and it draws.
Your Turn: Adjust the code
If you have never seen R before, change the main title to something that suits you, or change col from "lightblue" to "aliceblue".
If you have some experience, order the bars using sort().
Wrap counts in sort() to order the bars.
Notice what happened in that example. The five numbers were given a name, counts, and then handed to a function, barplot(), together with a few instructions. Naming things and passing them to functions is essentially all of R.
Objects: giving things a name
The standard assignment operator is <-. It stores a value under a name so you can use it later.
Names are case-sensitive: Age and age are two different objects. They may be almost anything, but the useful test is whether the name will still make sense to you in three months — and to whoever reads your code after that.
Assignment is silent by design: a <- 2 stores, it does not print. Wrap the line in parentheses if you want both at once.
Truly Dedicated
Why the arrow? R inherited <- from its ancestor S, which ran on terminals whose keyboards had a dedicated ← key. The key is gone; the arrow stayed.
= also assigns, and inside a function call it does something different — it names an argument. Compare:
x = 5 # assignment
mean(x = 5) # naming the argument "x" of mean()
mean(x <- 5) # assignment inside a call: creates x, then computesThe two meanings never collide as long as you use <- for assignment and = for arguments. In RStudio, Alt + - types the arrow for you.
Vectors
A single value is rarely interesting. R's natural unit is the vector: several values of the same type, in order. Think of one column of a spreadsheet.
c() combines values into a vector; the colon : builds a sequence.
temps <- c(19.1, 21.4, 18.7, 23.0, 22.2)
days <- 1:5
length(temps)
#> [1] 5
mean(temps)
#> [1] 20.88Arithmetic works on the whole vector at once. There is no loop to write.
temps - 273.15 # every element is shifted
#> [1] -254.05 -251.75 -254.45 -250.15 -250.95
temps * 2 # every element is doubled
#> [1] 38.2 42.8 37.4 46.0 44.4
temps > 21 # every element is compared
#> [1] FALSE TRUE FALSE TRUE TRUESquare brackets pull elements out, by position or by condition.
temps[1] # the first element (R counts from 1, not 0)
#> [1] 19.1
temps[c(1, 5)] # the first and the last
#> [1] 19.1 22.2
temps[temps > 21] # every element above 21
#> [1] 21.4 23.0 22.2That last line is worth a second look: temps > 21 produces TRUE/FALSE values, and the brackets keep the TRUE ones. Filtering data — the thing we spend half of this book doing — is that idea, one size larger.
Your Turn: Vectors
sum() on TRUE/FALSE values counts the TRUEs, because TRUE counts as 1.
Types of values
Every vector has a type, and R will tell you with class().
Numbers come as double (with decimals) or integer (whole).
Text is character, always in quotes. Single and double quotes work alike; " is the convention.
Logical values are TRUE and FALSE — the answers to questions. They quietly count as 1 and 0, which is why sum() counts and mean() gives a proportion.
passed <- c(TRUE, TRUE, FALSE, TRUE)
sum(passed) # how many
#> [1] 3
mean(passed) # what share
#> [1] 0.75The abbreviations T and F also work, but avoid them: unlike TRUE, they are ordinary names and can be overwritten.
Factors are categorical values with a fixed set of levels. R sorts levels alphabetically unless you say otherwise — which is fine for fruit and wrong for almost everything else.
dose <- factor(c("low", "medium", "high"))
dose # alphabetical: high, low, medium
#> [1] low medium high
#> Levels: high low medium
dose <- factor(c("low", "medium", "high"),
levels = c("low", "medium", "high"))
dose # the order we mean
#> [1] low medium high
#> Levels: low medium highSoftware cannot know whether an ordering makes sense. That is the analyst's job — and the order will resurface later in every table, axis and legend you produce.
Missing values are NA. Not zero, not empty text: unknown. Missingness is contagious, which is a feature rather than a bug.
weights <- c(3200, 4100, NA, 3750)
mean(weights) # NA: one value is unknown, so the mean is too
#> [1] NA
mean(weights, na.rm = TRUE) # ... unless we say to drop it
#> [1] 3683.333
is.na(weights)
#> [1] FALSE FALSE TRUE FALSEna.rm = TRUE is a decision, not a formality. Section 4.1 returns to what dropping those cases quietly assumes.
Data frames
Put several vectors of the same length side by side and you have a data frame: the rectangle that most of data analysis lives in. Rows are observations, columns are variables.
students <- data.frame(
name = c("Ana", "Ben", "Chi"),
age = c(23, 21, 25),
enrolled = c(TRUE, TRUE, FALSE)
)
students
#> name age enrolled
#> 1 Ana 23 TRUE
#> 2 Ben 21 TRUE
#> 3 Chi 25 FALSEThree functions tell you almost everything about a new data set.
dim(students) # rows, columns
#> [1] 3 3
str(students) # structure: types and first values
#> 'data.frame': 3 obs. of 3 variables:
#> $ name : chr "Ana" "Ben" "Chi"
#> $ age : num 23 21 25
#> $ enrolled: logi TRUE TRUE FALSE
summary(students)
#> name age enrolled
#> Length :3 Min. :21 Mode :logical
#> N.unique :3 1st Qu.:22 FALSE:1
#> N.blank :0 Median :23 TRUE :2
#> Min.nchar:3 Mean :23
#> Max.nchar:3 3rd Qu.:24
#> Max. :25Getting things out follows one rule: [rows, columns].
students$age # one column, by name
#> [1] 23 21 25
students[2, ] # one row
#> name age enrolled
#> 2 Ben 21 TRUE
students[1, 2] # one cell: row 1, column 2
#> [1] 23
students[students$age > 22, ] # every row that meets a condition
#> name age enrolled
#> 1 Ana 23 TRUE
#> 3 Chi 25 FALSEThe $ and the brackets are base R. The tidyverse will soon offer a more readable way to say the same thing — but this is what runs underneath, and it is worth recognising when you meet it in someone else's code.
Functions and their arguments
mean(), barplot() and factor() are functions: a name, a pair of parentheses, and arguments inside.
Arguments can be given by position or by name. Named arguments are slower to type and much easier to read.
round(3.14159, 2) # by position
#> [1] 3.14
round(x = 3.14159, digits = 2) # by name — unmistakable
#> [1] 3.14Most arguments have defaults, which is why round(3.14159) works at all. To find out what a function expects, ask it:
Reading a help page is a skill in itself, and the fastest way to acquire it is to jump straight to the Examples at the bottom, run them, and work upwards from there.
Packages
Base R is the language. Packages are everything else people have built with it, and there are thousands of them on CRAN, the official archive.
Two commands, and beginners mix them up constantly:
install.packages("palmerpenguins") # once per computer — downloads it
library(palmerpenguins) # once per session — switches it onInstalling is like buying a book for your shelf. library() is taking it off the shelf and opening it. A new R session starts with the shelf full and the desk empty, which is why every script should load the packages it needs at the top.
Reading
Posit publishes one-page cheat sheets for dplyr, ggplot2, RStudio and many others. Printed and kept next to the keyboard, they replace a surprising amount of searching.
Plots in base R
R could draw before ggplot2 existed, and base graphics remain excellent for a quick look. One function opens a plot, further functions add to it.
x <- 1:10
y1 <- x * x
y2 <- 2 * y1
plot(x, y1, type = "b", frame = FALSE, pch = 19,
col = "red", xlab = "x", ylab = "y")
lines(x, y2, pch = 18, col = "blue", type = "b", lty = 2)
legend("topleft", legend = c("Line 1", "Line 2"),
col = c("red", "blue"), lty = 1:2, cex = 0.8)
Figure 0.1: Base graphics built in layers: plot() opens the frame with x squared in red, lines() adds twice that in blue.
Every argument here is an aesthetic decision written down: colour, symbol, line type, where the legend goes. Later, ggplot2 will make those decisions systematic rather than individual.
Your Turn: A plot in three lines
iris is a data set built into R: measurements of 150 flowers from three species. Run the code, then colour the points by something else, or change pch (the plotting symbol) to a number between 0 and 25.
Three clouds, one per species. Which two species overlap?
When something goes wrong
It will. Errors are not a verdict on your abilities; they are R's way of saying which line it could not carry out.
| Message | Usually means |
|---|---|
object 'x' not found |
The name does not exist yet — a typo, or a line you have not run. |
could not find function "filter" |
The package is installed but not loaded. library(...) first. |
unexpected symbol / unexpected ')' |
A bracket, quote or comma is missing. |
A lonely + in the console |
R is still waiting for you to close something. Press Esc. |
argument "x" is missing |
A required argument was not supplied. |
A warning is different from an error. An error stops the code; a warning means it ran but R would like a word with you. Both are worth reading rather than scrolling past.
The most effective debugging habit is also the least glamorous: run your code one line at a time and look at the object after each step. Half of all bugs are simply an object that is not what you assumed it was.
Download RStudio: https://posit.co/downloads/. We set it up properly later in this chapter.↩︎