1  R setup

Objectives

  • Explore the data‑science lifecycle. The R for Data Science introduction models data science as a cycle: you begin by importing and tidying raw data; then understand it through an iterative loop of transforming, visualising and modelling; and finally communicate your results. Programming surrounds all of these steps and supports them. Today you will learn why each component is important and how they connect.
  • Recognise the tools you need. To run the code in R for Data Science you need R, RStudio, the tidyverse package collection and a handful of other packages. We will install R (from the Comprehensive R Archive Network), download RStudio (an integrated development environment), and install the tidyverse.
  • Prepare your computing environment. By the end of class you should have R and RStudio installed, know how to install and load packages, and be able to run simple R commands (arithmetic, vector creation, summary statistics). We will also introduce a dataset that you will revisit throughout the semester.
  • Recognise a handful of classic R “gotchas.” R is friendly, but a few of its default behaviors surprise almost every new user. Seeing them once, on purpose, in a low-stakes setting is far better than discovering them for the first time in the middle of a homework assignment.

Notes

The data‑science workflow

Data science is not a linear process. You first import data from files, databases or the web; tidy it so that each variable is a column and each observation a row; transform, visualise and model your data in an iterative loop to understand patterns and relationships; and then communicate your findings to others. Programming is a cross‑cutting skill that supports each of these phases. Throughout this course, you will move back and forth between these steps rather than following them in a strict order.

It helps to picture the cycle as a loop rather than a checklist:

import -> tidy -> [transform <-> visualize <-> model] -> communicate

The middle three steps form their own inner loop. You rarely visualize data once and move on; a plot usually raises a new question, which sends you back to transforming the data, which produces a new plot, and so on. A finished analysis is the record of many trips around that inner loop, not a single pass through it.

NoteWhere we are headed this semester

Every session in this course maps onto one or more parts of this cycle. Early sessions (like today) focus on tooling, the prerequisite for doing any of the above. Soon we move into importing and tidying data, then spend the bulk of the semester on transforming and visualizing, before finishing with modelling and communicating results (reports and reproducible documents like this one).

Tools and setup

You need four things to run the book’s code: R, RStudio, the tidyverse and some additional packages.

  • R is the programming language you will use. Download the latest version from CRAN at https://cloud.r-project.org. A new major version of R is released once a year (typically in April), with minor/patch versions in between; updating regularly ensures compatibility with the newest packages.
  • RStudio is an integrated development environment (IDE) for R. R is the engine, and RStudio is the car around it. Download it from https://posit.co/download/rstudio-desktop/. RStudio is updated a couple of times a year. When you start RStudio, you will see a console pane for typing R code and an output pane for plots.
  • The tidyverse is a collection of packages for data manipulation, visualization and programming. To install all core tidyverse packages at once, run install.packages("tidyverse") in the R console. After installation, load the tidyverse with library(tidyverse); this attaches packages such as dplyr, ggplot2, tidyr, readr, stringr, forcats, lubridate, purrr and tibble. You only need to install a package once, but you must load it (with library()) in each new R session.
  • Other packages. We will occasionally use packages outside the tidyverse (e.g., palmerpenguins, nycflights13, arrow, rvest, duckdb). When you encounter an error that a package is not installed, run install.packages("package_name") to install the package.
TipNo local install required

If you cannot install R/RStudio on your own machine (locked-down laptop, insufficient storage, etc.), Posit Cloud (https://posit.cloud) gives you a full RStudio environment in a browser tab, free of charge for light use. Everything in this book runs there identically.

Getting to know the RStudio window

R4DS assumes you already know your way around the RStudio interface, but it is worth slowing down here since you will live in this window all semester. RStudio is divided into four panes:

  1. Source (top-left): where you write and save .R scripts or .qmd documents like this one. Code here is not run until you tell it to.
  2. Console (bottom-left): where code actually executes, one command at a time. Anything typed directly here is run immediately but is not saved anywhere unless you also put it in a script.
  3. Environment / History (top-right): lists every object (vector, data frame, function, …) currently loaded in memory, and a log of commands you’ve run.
  4. Files / Plots / Packages / Help / Viewer (bottom-right): a multi-purpose pane for browsing files, viewing plots, managing installed packages, and reading documentation.
TipKeyboard shortcuts worth learning on day one
  • Ctrl/Cmd + Enter: run the current line (or selection) from the Source pane.
  • Ctrl/Cmd + Shift + M: insert the pipe operator |>.
  • Alt + - (Windows/Linux) or Option + - (Mac): insert the assignment arrow <-.
  • Tab: autocomplete object names, file paths, and function arguments as you type.
  • F1 (with your cursor on a function name): open that function’s help page.
NoteAlways work inside an RStudio Project

Create a Project (File → New Project) for this course rather than opening loose files. A Project fixes your working directory to a specific folder, so relative file paths (read_csv("data/exams.csv")) work the same way on your laptop as they do on a classmate’s, and as they do when this book itself is rendered on GitHub’s servers. Avoid setwd("C:/Users/yourname/Desktop/...") at the top of scripts; it is the single most common reason “but it worked on my computer!” homework fails to run for someone else.

Installing and testing your environment

  1. Install R and RStudio as described above. Accept the default installation options.
  2. Install the tidyverse. Open RStudio and run the following in the console:
install.packages("tidyverse")   # installs core tidyverse packages
library(tidyverse)
  1. Confirm your setup. Check which versions of R and your packages you actually have. This is the first thing to check when troubleshooting “it works for the professor but not for me”:
R.version.string          # which R version am I running?
[1] "R version 4.5.1 (2025-06-13 ucrt)"
packageVersion("dplyr")   # which version of a given package is installed?
[1] '1.1.4'
  1. Try basic R commands. Use R as a calculator and practise creating vectors and computing summaries:
2 + 2                  # arithmetic
[1] 4
x <- c(1, 2, 3, 5, 7)  # create a numeric vector
x * 2                  # vectorised multiplication
[1]  2  4  6 10 14
mean(x)                # compute the average
[1] 3.6
sum(x > 4)             # count values greater than 4 (logical vector)
[1] 2

Notice that R performs operations element‑wise on vectors, and the assignment operator <- stores values. Use descriptive variable names and indent your code neatly; we will discuss code style in a later class.

WarningNever save your workspace between sessions

When you quit RStudio it may ask “Save workspace image to .RData?” Always say no, and better yet, turn this prompt off entirely (Tools → Global Options → General → uncheck “Restore .RData into workspace at startup,” set “Save workspace to .RData on exit” to Never). A script that depends on hidden objects left over from yesterday’s console session will mysteriously fail the moment you (or a classmate, or a grader) restart R with a clean slate. Restarting R often (Ctrl/Cmd + Shift + F10) and re-running your script from the top is the best way to make sure your code is actually reproducible.

R as a calculator: worked examples and fringe cases

R4DS moves quickly through basic arithmetic because it assumes some prior programming exposure. The examples below slow down and dig into a few behaviors that are technically just consequences of how computers store numbers and evaluate expressions, but that trip up nearly every new R user at some point this semester.

ExampleExample 1.1

Floating-point arithmetic doesn’t always look exact.

0.1 + 0.2 == 0.3
[1] FALSE
0.1 + 0.2
[1] 0.3
print(0.1 + 0.2, digits = 17)
[1] 0.30000000000000004

R stores decimal numbers in binary floating-point format, and numbers like 0.1 and 0.2 cannot be represented exactly in binary, the same way 1/3 cannot be written exactly with a finite number of decimal digits. The rounding error is tiny (about \(10^{-17}\)), but it is enough to make == return FALSE. This is not an R bug; every mainstream programming language (Python, Java, JavaScript, …) does this.

The fix: never test decimal numbers for exact equality. Use all.equal(), which allows for a small numerical tolerance:

isTRUE(all.equal(0.1 + 0.2, 0.3))
[1] TRUE
ExampleExample 1.2

Vector recycling can silently do the wrong thing.

When you combine two vectors with an arithmetic operator, R “recycles” (repeats) the shorter vector to match the length of the longer one.

c(1, 2, 3, 4) + c(1, 2)   # recycles c(1, 2) as c(1, 2, 1, 2) -- no warning
[1] 2 4 4 6

Recycling is genuinely useful (it’s why x * 2 in the earlier example works: the length-1 vector 2 is recycled to match x). The danger appears when the lengths don’t divide evenly, because R still recycles, but now issues a warning that is easy to miss in a long console history:

c(1, 2, 3) + c(1, 2)      # length 3 is not a multiple of length 2
Warning in c(1, 2, 3) + c(1, 2): longer object length is not a multiple of
shorter object length
[1] 2 4 4

If you ever see the warning “longer object length is not a multiple of shorter object length,” stop and check that your vectors are the length you expect. It almost always signals a bug, such as a filtering step that silently dropped a row.

ExampleExample 1.3

Operator precedence, integer division, and negative numbers.

-2^2      # exponentiation binds tighter than unary minus: -(2^2)
[1] -4
(-2)^2    # explicit grouping changes the answer
[1] 4

R evaluates ^ before unary -, so -2^2 is -4, not 4. When in doubt, add parentheses. It costs nothing and removes all ambiguity for the next reader (including future you).

Integer division (%/%) and modulo (%%) also behave in a way that surprises people coming from other languages when negative numbers are involved: R always rounds down (toward negative infinity), not toward zero.

7 %/% 2     #  3
[1] 3
7 %% 2      #  1
[1] 1
-7 %/% 2    # -4, not -3
[1] -4
-7 %% 2     #  1, not -1
[1] 1
ExampleExample 1.4

Missing values propagate, on purpose.

Real data almost always has gaps. R represents a missing value with NA, and by design, almost any calculation that touches an NA returns NA rather than silently skipping it.

scores <- c(88, 92, NA, 79)
mean(scores)                # NA: R refuses to guess
[1] NA
mean(scores, na.rm = TRUE)  # tell R explicitly to ignore missing values
[1] 86.33333
sum(is.na(scores))          # how many values are missing?
[1] 1

This is a deliberate safety feature, not a bug: if R silently dropped missing values by default, you could compute a “average exam score” without ever realizing three students’ grades were missing. You must opt in to ignoring NAs with na.rm = TRUE (or an equivalent argument), which forces you to make a conscious decision about how to handle missing data.

WarningT and F are not protected the way TRUE and FALSE are

TRUE and FALSE are reserved keywords in R and can never be reassigned. T and F are only built-in variables that happen to be set to TRUE/FALSE, which means you (or a package, or a stray line of copy-pasted code) can silently overwrite them:

T           # starts out TRUE, as expected
[1] TRUE
T <- FALSE  # legal! T is just an ordinary variable name, not a reserved word
T
[1] FALSE
if (T) "this line runs" else "this line runs instead -- T no longer means TRUE"
[1] "this line runs instead -- T no longer means TRUE"
rm(T)       # remove the shadowing variable to restore the default

The habit that avoids this entire class of bug: always spell out TRUE and FALSE in your own code, and never use T or F as a variable name.

NoteR is case-sensitive, everywhere

x and X are two completely different objects to R, as are mean and Mean, and read_csv and Read_CSV. “Object not found” errors are frequently just a stray capital letter. This also applies to file names when you read data from disk: read_csv("Data.csv") will fail on a filesystem where the file is actually named data.csv, even though the two look identical in print.

Recap

Term Definition
R The open-source programming language used throughout this course; installed from CRAN.
RStudio An integrated development environment (IDE) that provides a friendlier interface around R.
CRAN The Comprehensive R Archive Network, the official repository for downloading R and R packages.
Package A shareable bundle of R functions and/or data; installed once with install.packages(), loaded each session with library().
tidyverse A collection of packages (dplyr, ggplot2, readr, tidyr, purrr, tibble, stringr, forcats, lubridate) designed to work together.
RStudio Project A folder-linked workspace that fixes the working directory, making relative file paths reproducible across computers.
Working directory The folder R currently looks in (and saves to) by default when you give it a relative file path.
Assignment (<-) Stores a value in a named object, e.g. x <- c(1, 2, 3).
Vectorization R functions and operators act on entire vectors element-by-element without an explicit loop.
Recycling R’s rule for combining vectors of different lengths by repeating the shorter one; issues a warning when lengths don’t divide evenly.
NA R’s representation of a missing value; propagates through most calculations unless explicitly ignored (na.rm = TRUE).
Floating-point error Small representation error inherent to storing decimal numbers in binary; the reason 0.1 + 0.2 == 0.3 is FALSE.

Check your understanding

NoteProblems
  1. What is the difference between installing a package and loading a package? Which R function do you use for each, and how often must you do each one?

  2. Without running R, predict the output of each line, then check your answer:

    1. -3^2
    2. (-3)^2
    3. 10 %% 3
    4. -10 %/% 3
  3. You run mean(c(4, 8, NA, 12)) and get NA back. Your friend says “R is broken.” Explain what actually happened and how to get the average of the non-missing values.

  4. A classmate’s script starts with T <- 1 (perhaps by accident, from a copy-pasted line). Explain what could go wrong later in their script, and what habit would have prevented the problem.

  5. Why does this course recommend creating an RStudio Project for your work, instead of just opening loose .R files from wherever they happen to be saved?

  1. Installing a package (install.packages("pkgname")) downloads it from CRAN onto your computer; you typically only need to do this once (until you want to update it). Loading a package (library(pkgname)) makes its functions available in your current R session; you must do this every time you start a new R session, even if the package is already installed.

    1. -9 (exponentiation binds before unary minus, so this is -(3^2)). b) 9 (the parentheses force the negative to be squared). c) 1 (10 = 3×3 + 1). d) -4 (R’s integer division rounds toward negative infinity: -10/3 = -3.33…, which rounds down to -4, not up to -3).
  2. R did exactly what it was designed to do: because one value is missing (NA), R refuses to compute an average without your explicit instruction on how to handle the gap, since silently ignoring it could hide a data problem. Adding na.rm = TRUE, i.e. mean(c(4, 8, NA, 12), na.rm = TRUE), tells R to compute the mean of just the non-missing values.

  3. T is only a variable pre-loaded with the value TRUE, not a protected keyword like TRUE itself. After T <- 1, any later code that relies on T meaning “true” (e.g., if (T) ...) will behave incorrectly, because T no longer holds a logical value. Always writing out TRUE/FALSE in full avoids this entirely, since those are protected and cannot be reassigned.

  4. An RStudio Project fixes the working directory to a specific folder, so relative paths like read_csv("data/exams.csv") resolve the same way regardless of whose computer (or which server) runs the script. Opening loose files instead means the working directory depends on wherever RStudio happened to start, which is exactly why scripts that use setwd() with a hard-coded path “work on my machine” but fail for everyone else.