R & RStudio: The Basics

SPEA V706 — Statistics for Research in Public Affairs

Coady Wing

The Plan

  • Install R and RStudio
  • Open RStudio
    • Use R as a calculator
    • Objects and classes: vectors, data frames, lists
    • Functions and loops

Installing from the Command Line

Open a Terminal

  • macOS: open Terminal (Applications → Utilities, or Spotlight and type “terminal”)
  • Windows: open PowerShell (Start menu, type “powershell”)

macOS: First Install Homebrew

Homebrew is a package manager for macOS. Install it using this command:

/bin/bash -c "$(curl -fsSL \
  https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

What is happening? 1. /bin/bash -c says “run the following command in bash” - /bin/bash is the path to the shell that runs the script - -c is a flag (option) that means “command”. (Don’t wait for me to type things in or look for a file; just run what comes next.)

  1. "$(…)` runs the command inside the parentheses and substitutes its output into the command line.

  2. curl is a command-line tool that downloads files from the web

    • -fsSL are four separate curl flags (options)
      • -f fail silently on server errors
      • -s silent mode (no progress bar)
      • -S show errors (with -s)
      • -L follow redirects (if the URL points somewhere else)

When you run this command, the computer runs curl first, which downloads Homebrew. Then it hands the download to bash, which runs the installer. You will be prompted for your password, and then Homebrew will install itself.

macOS: Install R and RStudio

brew install --cask r
brew install --cask rstudio
  • --cask means a normal Mac application, the kind that lands in /Applications
  • Check that it worked:
R --version
  • You should see something like R version 4.4.1

Windows: Install R and RStudio

Windows 10 and 11 ship with winget, the Microsoft package manager.

winget install RProject.R
winget install Posit.RStudio
  • Accept the prompts. Both land in the Start menu when they finish
  • Check that it worked:
R --version

Open RStudio

Four Panes

What the Four Panes Do

Source

  • Your script: code you save and rerun

Console

  • Where R actually runs and prints results

Environment

  • The objects you have created and loaded

Files / Plots / Help

  • Your folders, your figures, and the ?help pages
  • The four panes can be dragged around, so yours may sit differently than the picture
  • Tools → Global Options → Pane Layout if you want to rearrange them

Console or Script?

  • Type in the console when you are exploring, but remember that is is not saved.
  • Type in a script when you are going to want the code.
  • You almost always want to be writing in a script.

R as a Calculator

Arithmetic

Type an expression, get a number.

2 + 2
#> [1] 4

12 / 5
#> [1] 2.4

3^2
#> [1] 9
  • The #> lines are what R prints back
  • The [1] is R telling you this answer starts at position 1

A Few More

sqrt(16)
#> [1] 4

log(100)          # natural log, always
#> [1] 4.60517

round(2.71828, 2)
#> [1] 2.72
  • sqrt, log, and round are functions. You give them input in the parentheses
  • log(100) is the natural log. log(100, base = 10) if you want the other one

Objects and Classes

Assignment

Store a value in a named object so you can use it later.

wage <- 42000     # give 42000 a name
wage              # type it to see the value
#> [1] 42000

wage * 12
#> [1] 504000
  • <- is the assignment arrow. Read it as “gets”
  • = also works for assignment
  • Names in snake_case: hourly_wage, n_kids, is_treated

Vectors

A vector is R’s most basic object: an ordered list of values of one type.

# c() = "combine" a set of values into a vector
wages <- c(18, 25, 31, 44, 60)
wages
#> [1] 18 25 31 44 60

length(wages)
#> [1] 5

Most operations work on the whole vector at once. wages * 2 doubles every entry.

Vectors Have a Type

nums   <- c(18, 25, 31)          # numbers
labels <- c("ada", "cal", "ida") # text
flags  <- c(TRUE, FALSE, TRUE)   # logicals

class(nums)
#> [1] "numeric"
class(labels)
#> [1] "character"
  • A vector holds one type: all numbers, or all text, or all TRUE/FALSE
  • class() tells you what type of object you have.

Coercion

What happens if you mix types in one vector?

mixed <- c("ada", 1)
mixed
#> [1] "ada" "1"
class(mixed)
#> [1] "character"
  • R refuses to hold two types in a vector, so it quietly coerces everything into one
  • The number 1 became the text "1". Note the quotes
  • This matters – for example – because you can’t take the mean of a vector of text objects.

Factors

group <- factor(c("low", "high", "low", "mid"))
group
#> [1] low  high low  mid
#> Levels: high low mid

levels(group)
#> [1] "high" "low"  "mid"
  • A factor is a categorical variable: text values from a fixed set of levels
  • R stores the levels in an order, which decides how they appear in tables and plots
  • Useful but a little tricksy.

Missing Values

wages <- c(18, 25, NA, 44)

mean(wages)
#> [1] NA

mean(wages, na.rm = TRUE)
#> [1] 29
  • NA means “missing”, and it is contagious: anything computed from it is missing too

  • is.na(wages) shows which values are NA or not NA.

Indexing

Use square brackets to pull out specific elements of the vector.

wages <- c(18, 25, 31, 44, 60)

wages[3]        # the third entry
#> [1] 31

wages[c(1, 2)]  # the first two
#> [1] 18 25
  • R counts from 1, not 0
  • wages[6] asks for an entry that does not exist, and gives you NA

Logical Subsetting

Keep the entries that satisfy a condition.

wages <- c(18, 25, 31, 44, 60)

wages > 30         # TRUE/FALSE per entry
#> [1] FALSE FALSE  TRUE  TRUE  TRUE

wages[wages > 30]  # keep the TRUE ones
#> [1] 31 44 60
  • The condition builds a logical vector, and the brackets keep where it is TRUE
  • == tests equality. A single = is assignment
  • which(wages > 30) gives the positions where the condition holds: 3 4 5

Data Frames

From Vectors to a Table

  • In base R, a data frame is the standard way to represent a data set.
  • A data frame lines up several vectors of the same length, side by side.
  • Every column can be a different type, and every column must be the same length.

Building a data frame

people <- data.frame(
  name     = c("ada", "cal", "ida"),
  wage     = c(18, 31, 44),
  is_union = c(FALSE, TRUE, TRUE)
)

people
#>   name wage is_union
#> 1  ada   18    FALSE
#> 2  cal   31     TRUE
#> 3  ida   44     TRUE

Looking at a Data Frame

nrow(people)     # how many rows
#> [1] 3
ncol(people)     # how many columns
#> [1] 3
names(people)    # the column names
#> [1] "name"     "wage"     "is_union"
str(people)      # structure: names, types, first values
  • head(people) shows the first few rows when the table is long

Getting at individual variables

people$wage        # $ = one column, as a vector
#> [1] 18 31 44

people[1, ]        # row 1, all columns
people[, "wage"]   # the wage column
people[2, "wage"]  # one cell
#> [1] 31
  • $ names a column, and [row, col] indexes like a matrix
  • Leave a slot empty to mean “all of them”

Working with Columns

A column is a vector, so everything you already know still applies.

mean(people$wage)
#> [1] 31

# add a column
people$annual <- people$wage * 40 * 52

# keep the rows you want
people[people$is_union, ]
#>   name wage is_union annual
#> 2  cal   31     TRUE  64480
#> 3  ida   44     TRUE  91520

Lists

Lists are a more general container

  • A vector needs one type.
  • A data frame needs equal-length columns.
  • A list holds anything in one container: a number, a vector, a whole table
results <- list(n     = 100,
                means = c(2.1, 3.4),
                label = "pilot")

Reaching Into a List

results[["means"]]   # double brackets: the thing itself
#> [1] 2.1 3.4

results$means        # $ works too
#> [1] 2.1 3.4

results["means"]     # single brackets: a shorter list
#> $means
#> [1] 2.1 3.4
  • Double brackets take the element out. Single brackets give you a smaller list
  • Single and double brackets syntax is always a bit confusing.

Functions and Loops

Writing a Function

Write a function when you want to apply the same logic to different inputs.

# convert an hourly wage to a rough annual figure
to_annual <- function(hourly) {
  hourly * 40 * 52
}

to_annual(25)
#> [1] 52000
to_annual(c(18, 31))   # works on a vector too
#> [1] 37440 64480

Anatomy of a Function

How much do you make in a year?

to_annual <- function(hourly_wage, hours_worked = 40, weeks_worked = 52) {
  hourly_wage * hours_worked * weeks_worked
}

to_annual(25)              # uses the defaults
#> [1] 52000
to_annual(25, hours_worked = 20)  # part time
#> [1] 26000
  • to_annual is the name of the function you are creating.
  • hourly_wage and weeks_worked are arguments: you want the user to pass some information to the function.
  • hours_worked = 40 is a default, used when the caller says nothing
  • In R, the last expression in the function definition is the one that is returned to the user.
  • A for Loop

Do the same thing to each item in a collection.

years <- c(2018, 2019, 2020)

for (y in years) {
  message("working on ", y)
}
#> working on 2018
#> working on 2019
#> working on 2020

The loop runs the body once per element, with y taking each value in turn.

Loops That Keep Something

Make the container first, then fill it.

wages   <- c(18, 25, 31, 44)
doubled <- numeric(length(wages))   # empty container, right size

for (i in 1:length(wages)) {
  doubled[i] <- wages[i] * 2
}

doubled
#> [1] 36 50 62 88
  • i is a position here, not a value, so wages[i] pulls the entry out
  • doubled <- wages * 2 does the same job in one line.

Getting Help

R has the help manual built in.

?mean          # opens the help page for the mean() function
args(round)    # just the argument list
example(mean)  # runnable examples
  • The Usage and Arguments sections tell you what a function expects
  • The examples at the bottom of a help page are usually the fastest way in
  • ??regression searches the help system when you do not know the function’s name

Recap

  • Install R and RStudio
  • vectors, data frames, lists, types, coercion, NA
  • Index with [ ], and subset with conditions like wages[wages > 30]
  • A data frame is columns side by side; a list holds anything at all
  • Write functions or a loops to repeat logic