๐Ÿ—“๏ธ Week 02
Data Structures & R Programming

STAT 204 โ€“ Introduction to Statistical Data Analysis

01 Oct 2026

๐Ÿ“œ Learning Pledge (reminder)

Programming is a systematic way to think about a problem โ€” turning a fuzzy question into precise definitions and a chain of answers. Learning R is how we build that mental model.

Thereโ€™s no point using AI if youโ€™re trying to build that mental model yourself.

Where we left off

Week 1 recap

On Tuesday we covered:

  • Positron & Git: the workspace, first commit and push ๐Ÿ–ฅ๏ธ
  • R as a calculator and comments ๐Ÿงฎ
  • Variables and naming rules ๐Ÿ“Š
  • Data types & classes: numeric, character, logical, factor; coercion ๐Ÿ”ข
  • Environment management: ls(), rm(), exists() ๐Ÿงน
  • Vectors: c(), seq(), rep(), special values (NA, NaN, Inf), recycling, subsetting, which(), set operations ๐Ÿ“ˆ

The Week 1 deck has everything else we planned โ€” today we pick it up from matrices.

This week

Thursday โ€” Data structures

  • Matrices and lists
  • Strings
  • Data frames (with penguins ๐Ÿง)
  • Random numbers and seeds
  • Packages and help
  • Mini project
  • Common mistakes & fixes

Tuesday โ€” Programming & data import

  • Writing functions
  • Loops, vectorization, apply()
  • Conditionals
  • Saving work and importing data
  • Reshaping and merging data frames

Matrices: 2D Data Structures

Creating Matrices

Matrices are 2-dimensional arrays that store data of the same type:

# Fill by column (default) or by row
mat1 <- matrix(1:12, nrow = 3, ncol = 4)
mat1
     [,1] [,2] [,3] [,4]
[1,]    1    4    7   10
[2,]    2    5    8   11
[3,]    3    6    9   12
matrix(1:12, nrow = 3, ncol = 4, byrow = TRUE)
     [,1] [,2] [,3] [,4]
[1,]    1    2    3    4
[2,]    5    6    7    8
[3,]    9   10   11   12
# Bind vectors as rows or columns
vec1 <- c(1, 2, 3)
vec2 <- c(4, 5, 6)
rbind(vec1, vec2)
     [,1] [,2] [,3]
vec1    1    2    3
vec2    4    5    6
cbind(vec1, vec2)
     vec1 vec2
[1,]    1    4
[2,]    2    5
[3,]    3    6
matrix(0, nrow = 2, ncol = 3)  # Empty matrix filled with zeros
     [,1] [,2] [,3]
[1,]    0    0    0
[2,]    0    0    0

Matrix Attributes and Subsetting

dim(mat1)        # (rows, columns); also nrow(), ncol(), length()
[1] 3 4
rownames(mat1) <- c("Row1", "Row2", "Row3")
colnames(mat1) <- c("Col1", "Col2", "Col3", "Col4")
mat1
     Col1 Col2 Col3 Col4
Row1    1    4    7   10
Row2    2    5    8   11
Row3    3    6    9   12
mat1[1, 2]              # Row 1, column 2
[1] 4
mat1[2, ]               # Entire row 2
Col1 Col2 Col3 Col4 
   2    5    8   11 
mat1[, 3]               # Entire column 3
Row1 Row2 Row3 
   7    8    9 
mat1[1:2, 2:4]          # Submatrix
     Col2 Col3 Col4
Row1    4    7   10
Row2    5    8   11
mat1["Row1", "Col2"]    # By name
[1] 4
mat1[5]                 # Matrices are vectors underneath (column-wise)
[1] 5

Linear algebra (%*%, solve(), t()), sweep(), and arrays are in the Self-Guided Practice section at the end.

Lists

Lists Hold Anything

A list can contain elements of different types:

x <- list("California", c(1,3,5,1), 92, TRUE, matrix(1:4, 2, 2))
str(x)
## List of 5
##  $ : chr "California"
##  $ : num [1:4] 1 3 5 1
##  $ : num 92
##  $ : logi TRUE
##  $ : int [1:2, 1:2] 1 2 3 4

Empty list of a given length:

vector("list", length = 2)
## [[1]]
## NULL
##
## [[2]]
## NULL

List Subsetting: [] vs [[]]

x <- list("California", c(1,3,5,1), 92)

[] returns a list; [[]] returns the element:

x[1]
## [[1]]
## [1] "California"

x[[1]]
## [1] "California"

Go deeper:

x[[2]][4]        # 4th element of the 2nd component
## [1] 1
x[[c(2, 4)]]     # same thing (recursive indexing)
## [1] 1

Named List Elements

x <- list(state = "CA", co = c(1,3,5,1), loc = 92)
x$state          # element
x[["state"]]     # element
x["state"]       # a list!

Many R functions return (named) lists:

H <- hist(faithful$waiting)
names(H)
## [1] "breaks"   "counts"   "density"  "mids"
## [5] "xname"    "equidist"
H$counts

Exercise: Lists

  1. Create a list containing: your name, a vector of your three favorite numbers, and a 2ร—2 matrix of your choice
  2. Extract just the middle number from your vector using [[]]
  3. Add names to your list elements and practice accessing them with $ and [["name"]]

Working with Strings

x <- "Hello"; y <- "Bye"; z <- "world"

paste(x, z)
## [1] "Hello world"

w <- c(x, y)
paste(w, z, sep = " cruel ")
## [1] "Hello cruel world" "Bye cruel world"

paste(w, z, sep = " cruel ", collapse = " and ")
## [1] "Hello cruel world and Bye cruel world"

Extracting pieces:

substr(x, 2, 4)                      # "ell"
substr(x, nchar(x) - 2, nchar(x))    # last 3 characters: "llo"

Data Frames

Data Frames

  • Special R objects for storing data โ€” like a spreadsheet
  • Columns can be different types (unlike matrices)
  • Variables = columns, observations = rows
x <- data.frame(var1 = 1:4, var2 = c(T,T,F,F),
                var3 = factor(c(1,1,2,1)))
str(x)
## 'data.frame':    4 obs. of  3 variables:
##  $ var1: int  1 2 3 4
##  $ var2: logi  TRUE TRUE FALSE FALSE
##  $ var3: Factor w/ 2 levels "1","2": 1 1 2 1

Accessing: matrix-style or by name

x[2, 3]           # row 2, column 3
x[1:2, "var3"]    # rows 1-2 of var3
x$var3[1:2]       # same thing

The penguins dataset

# Load the palmerpenguins package
library(palmerpenguins)

# Look at the penguins dataset
penguins
# A tibble: 344 ร— 8
   species island    bill_length_mm bill_depth_mm flipper_length_mm body_mass_g
   <fct>   <fct>              <dbl>         <dbl>             <int>       <int>
 1 Adelie  Torgersen           39.1          18.7               181        3750
 2 Adelie  Torgersen           39.5          17.4               186        3800
 3 Adelie  Torgersen           40.3          18                 195        3250
 4 Adelie  Torgersen           NA            NA                  NA          NA
 5 Adelie  Torgersen           36.7          19.3               193        3450
 6 Adelie  Torgersen           39.3          20.6               190        3650
 7 Adelie  Torgersen           38.9          17.8               181        3625
 8 Adelie  Torgersen           39.2          19.6               195        4675
 9 Adelie  Torgersen           34.1          18.1               193        3475
10 Adelie  Torgersen           42            20.2               190        4250
# โ„น 334 more rows
# โ„น 2 more variables: sex <fct>, year <int>
# Quick exploration
nrow(penguins)  # How many rows (observations)?
[1] 344
ncol(penguins)  # How many columns (variables)?
[1] 8
names(penguins) # What are the column names?
[1] "species"           "island"            "bill_length_mm"   
[4] "bill_depth_mm"     "flipper_length_mm" "body_mass_g"      
[7] "sex"               "year"             

Data exploration functions

# Look at the first few rows
head(penguins)
# A tibble: 6 ร— 8
  species island    bill_length_mm bill_depth_mm flipper_length_mm body_mass_g
  <fct>   <fct>              <dbl>         <dbl>             <int>       <int>
1 Adelie  Torgersen           39.1          18.7               181        3750
2 Adelie  Torgersen           39.5          17.4               186        3800
3 Adelie  Torgersen           40.3          18                 195        3250
4 Adelie  Torgersen           NA            NA                  NA          NA
5 Adelie  Torgersen           36.7          19.3               193        3450
6 Adelie  Torgersen           39.3          20.6               190        3650
# โ„น 2 more variables: sex <fct>, year <int>
# Get a summary of the data
summary(penguins)
      species          island    bill_length_mm  bill_depth_mm  
 Adelie   :152   Biscoe   :168   Min.   :32.10   Min.   :13.10  
 Chinstrap: 68   Dream    :124   1st Qu.:39.23   1st Qu.:15.60  
 Gentoo   :124   Torgersen: 52   Median :44.45   Median :17.30  
                                 Mean   :43.92   Mean   :17.15  
                                 3rd Qu.:48.50   3rd Qu.:18.70  
                                 Max.   :59.60   Max.   :21.50  
                                 NAs    :2       NAs    :2      
 flipper_length_mm  body_mass_g       sex           year     
 Min.   :172.0     Min.   :2700   female:165   Min.   :2007  
 1st Qu.:190.0     1st Qu.:3550   male  :168   1st Qu.:2007  
 Median :197.0     Median :4050   NAs   : 11   Median :2008  
 Mean   :200.9     Mean   :4202                Mean   :2008  
 3rd Qu.:213.0     3rd Qu.:4750                3rd Qu.:2009  
 Max.   :231.0     Max.   :6300                Max.   :2009  
 NAs    :2         NAs    :2                                 
# Look at the structure of the data
str(penguins)
tibble [344 ร— 8] (S3: tbl_df/tbl/data.frame)
 $ species          : Factor w/ 3 levels "Adelie","Chinstrap",..: 1 1 1 1 1 1 1 1 1 1 ...
 $ island           : Factor w/ 3 levels "Biscoe","Dream",..: 3 3 3 3 3 3 3 3 3 3 ...
 $ bill_length_mm   : num [1:344] 39.1 39.5 40.3 NA 36.7 39.3 38.9 39.2 34.1 42 ...
 $ bill_depth_mm    : num [1:344] 18.7 17.4 18 NA 19.3 20.6 17.8 19.6 18.1 20.2 ...
 $ flipper_length_mm: int [1:344] 181 186 195 NA 193 190 181 195 193 190 ...
 $ body_mass_g      : int [1:344] 3750 3800 3250 NA 3450 3650 3625 4675 3475 4250 ...
 $ sex              : Factor w/ 2 levels "female","male": 2 1 1 NA 1 2 1 2 NA NA ...
 $ year             : int [1:344] 2007 2007 2007 2007 2007 2007 2007 2007 2007 2007 ...

Interactive data exploration

Explore the penguins! (8 minutes) ๐Ÿง

Working with a partner:

  1. Use View(penguins) to open the data in a spreadsheet-like view
  2. How many penguin species are in the data?
  3. Whatโ€™s the average bill length? (Hint: mean(penguins$bill_length_mm, na.rm = TRUE))
  4. What islands are represented?
  5. How many penguins are from each island? (Hint: table(penguins$island))

Discuss: What interesting patterns do you notice? ๐Ÿ”

Random Numbers

Distributions in R

Every standard distribution has four functions: d (density), p (CDF), q (quantile), r (random draws):

dnorm(1, mean = 0, sd = 1)      # Density at x = 1
## [1] 0.2419707
pnorm(1, mean = 0, sd = 1)      # P(X โ‰ค 1)
## [1] 0.8413447
qnorm(0.5, mean = 0, sd = 1)    # Median
## [1] 0
rnorm(4, mean = 3, sd = 1)      # 4 random values
## [1] 4.027 2.760 2.814 3.857

Other distributions and sampling:

rbinom(10, size = 12, prob = 0.2)
##  [1] 1 4 2 1 2 1 3 4 2 3

x <- c("CA", "NE", "OR", "WA", "UT")
sample(x, 3, replace = TRUE)
## [1] "WA" "WA" "NE"
sample(x, 3, replace = FALSE)
## [1] "WA" "OR" "NE"

Setting a Seed

Random draws change every time โ€” set.seed() makes them reproducible:

# Without seed - different results
rnorm(1)
## [1] 0.4955
rnorm(1)
## [1] -1.3175

# With seed - identical results
set.seed(100)
rnorm(1)
## [1] -0.5022

set.seed(100)
rnorm(1)
## [1] -0.5022

Exercise: Data Frames and Random Numbers

Part A: Data Frames

  1. Create a data frame with columns: Name (character), Age (numeric), Student (logical) for 5 people
  2. Calculate the mean age using 2 different ways, including using the mean() function.

Part B: Random Numbers

  1. Set seed to 42 and generate 100 random normal values (mean=50, sd=10)
  2. What percentage fall between 40 and 60?
  3. Create a histogram of these values

R packages: Extending Rโ€™s power

Working with packages

Packages are collections of functions that extend R:

# Install a package (only need to do this once)
install.packages("tidyverse")

# Load a package (do this each R session)
library(tidyverse)

# Now you can use functions from that package! ๐ŸŽ‰

Popular packages ๐Ÿ“ฆ

  • tidyverse: Data manipulation and visualization
  • ggplot2: Beautiful graphics (part of tidyverse)
  • dplyr: Data manipulation (part of tidyverse)
  • palmerpenguins: Practice datasets (including penguins!) ๐Ÿง

Getting help in R

Help system

?mean                  # Help for a function (same as help(mean))
??regression           # Search all help pages (same as help.search())
example(mean)          # Run the examples from the help page
help(package = "palmerpenguins")   # Help for a whole package

apropos("mean")        # Functions whose name contains "mean"
find("mean")           # Which package a function lives in

Other ways to get help ๐Ÿ†˜

  • Google: โ€œHow to [do something] in Rโ€
  • Stack Overflow: Huge community of R users
  • R Documentation: Official function documentation
  • Your classmates and instructor! ๐Ÿ‘ฅ
  • Note about LLMs: They are not permitted on homework (see the syllabus AI Policy). The midterm is in person with no AI, so homework is where you build the fluency you need. You may use them for studying, after trying problems yourself.

Hands-on challenge

Mini project

Your mission (15 minutes) ๐ŸŽฏ

Create a simple analysis of your class!

  1. Create vectors for: student_names, birth_months, favorite_numbers. Assign 50 random numbers to months (from 1 to 12), 50 random numbers from 0 to 100 in the favorite numbers column, and use the package randomNames to generate 50 names. Create a data frame with all three columns.
  2. Calculate some summaries (mean, max, min of favorite numbers)
  3. Save everything in an R script called โ€œclass_analysis.Rโ€
  4. Add comments explaining each step ๐Ÿ“

Bonus: Try to find out which birth month is most common using table() ๐Ÿ—“๏ธ

Work in pairs and help each other! ๐Ÿ‘ฅ

Common mistakes & fixes

Case Sensitivity and Assignment

x <- 5
X <- 10
x; X             # Two different variables!
[1] 5
[1] 10
Mean(c(1, 2, 3)) # Error! Function names are case sensitive too
Error in `Mean()`:
! could not find function "Mean"
head(Penguins)   # Error - the dataset is `penguins`
Error:
! object 'Penguins' not found

Use <- for assignment ๐Ÿ“

Itโ€™s the R convention, it canโ€™t be confused with ==, and it shows the direction of assignment. Inside a function call, = names an argument: mean(x = c(1, 2, 3)).

Keyboard shortcut: Alt + - (Windows) or Option + - (Mac)

Error Messages: Your Friends!

  • Typos in function names: maen() instead of mean() โ†’ use tab-completion โœ…
  • Missing parentheses: mean instead of mean() โ†’ functions need () โœ…
  • Forgetting quotes: name <- Alice instead of name <- "Alice" โ†’ text needs quotes โœ…
ages <- c(20, 21, 19, 22, 20)
mean(Ages)  # We created 'ages', not 'Ages'
Error:
! object 'Ages' not found
mean(ages)  # Fixed!
[1] 20.4

Reading error messages ๐Ÿ”

Donโ€™t panic ๐Ÿ˜Œ โ†’ read the message ๐Ÿ“– โ†’ check for typos โœ๏ธ โ†’ search the error if youโ€™re stuck ๐Ÿ”

Session 2: Programming in R

Tuesday: functions, loops, conditionals, and getting data into R.

Defining Functions

logit <- function(x){
  z <- log(x/(1-x))
  return(z)
}

logit(runif(3, 0, 1))
## [1]  0.210 -2.818 -0.126

my_norm <- function(x){sqrt(x%*%x)}
my_norm(1:4)
##      [,1]
## [1,] 5.477

Functions with Multiple Arguments

f <- function(x, a=1, b=0){
  a*x^2 + b
}

f(2)        # Uses defaults
## [1] 4

f(2, 2)     # a=2, b=0
## [1] 8

f(2, 2, 2)  # a=2, b=2
## [1] 10

Default values make functions flexible!

Function Internals and Arguments

To see calculations, use print():

f1 <- function(x){
  paste("Attempt 1 to show value of x=", x)
  print(paste("Attempt 2 to show value of x=", x))
}

f1(3)
## [1] "Attempt 2 to show value of x= 3"

Only printed output is shown!

Positional vs named arguments:

f <- function(x, y){
  print(paste("x =", x, "y =", y))
}

f(2, 3)
## [1] "x = 2 y = 3"

f(x=2, y=3)
## [1] "x = 2 y = 3"

f(y=3, x=2)
## [1] "x = 2 y = 3"

๐Ÿ“ Self-Guided: Lazy Evaluation

How R evaluates function arguments is not covered live โ€” see the Self-Guided Practice section at the end of these slides, or bring questions to the Wednesday self-guided session.

Exercise: Functions

Write these functions:

  1. my_range() - takes a vector and returns max - min
  2. standardize() - takes a vector and returns (x - mean)/sd
  3. my_summary() - takes a vector and returns a named list with mean, median, and sd
  4. Post your solution on Ed Discussion

Test your functions on:

test_data <- c(12, 15, 18, 20, 22, 25, 30)

Bonus: Modify my_summary() to handle NA values

๐Ÿ“ Self-Guided: Scoping

How R resolves free variables in functions is not covered live โ€” see the Self-Guided Practice section at the end of these slides, or bring questions to the Wednesday self-guided session.

Sourcing Functions

Store frequently-used functions in a file:

source(file="myfunctions.R")

Make sure the file is in your working directory or provide full path!

For Loops

for(i in 1:3){
  print(2*i)
}
## [1] 2
## [1] 4
## [1] 6

Index can be any vector:

mystates <- c("CA", "NE", "OR")
for(i in mystates){
  print(i)
}
## [1] "CA"
## [1] "NE"
## [1] "OR"

While Loops

x <- 1
while(x < 10){
  x <- x^2 + 1
  print(x)
}
## [1] 2
## [1] 5
## [1] 26

Efficient Loop Usage

Pre-allocate memory!

# Slow - growing vector
x <- numeric(0)
for(i in 1:10){x[i] <- i}

# Even slower - concatenating
x <- numeric(0)
for(i in 1:10){x <- c(x,i)}

# Fast - pre-allocated
x <- numeric(10)
for(i in 1:10){x[i] <- i}

Memory allocation is expensive!

Speed: Vectorize and Use Built-ins

x <- rexp(10000000, rate=1)

logown <- function(x){
  z <- rep(0, length(x))
  for(i in 1:length(x)){
    z[i] <-
       log(x[i])
  }
  return(z)
}

system.time(log(x))
##    user  system elapsed 
##   0.138   0.017   0.155

system.time(logown(x))
##    user  system elapsed 
##   0.609   0.002   0.612

Vectorized functions are much faster!

For common operations, use optimized built-ins (colSums(), rowMeans(), โ€ฆ):

x <- matrix(rexp(6000000), ncol=6000)

system.time(apply(x, 2, sum))
##    user  system elapsed
##   0.073   0.020   0.092

system.time(colSums(x))
##    user  system elapsed
##   0.008   0.000   0.008

The apply Function

apply(X, MARGIN, FUN) runs a function over rows (1) or columns (2) of a matrix:

scores <- matrix(c(85, 92, 78, 96, 88, 74, 91, 89, 76, 94, 82, 90),
                 nrow = 3, ncol = 4)
rownames(scores) <- c("Student1", "Student2", "Student3")
colnames(scores) <- c("Math", "Science", "History", "English")
scores
         Math Science History English
Student1   85      96      91      94
Student2   92      88      89      82
Student3   78      74      76      90
apply(scores, 1, mean)  # Row means: one per student
Student1 Student2 Student3 
   91.50    87.75    79.50 
apply(scores, 2, min)   # Column minimums: one per subject
   Math Science History English 
     78      74      76      82 

Equivalent loop โ€” apply() is cleaner, but not always faster:

z <- numeric(4)
for(i in 1:4){
  z[i] <- min(scores[,i])
}

Apply with Multiple Arguments

Extra arguments are passed on to the function:

x <- matrix(rnorm(6000), ncol=3)

apply(x, 2, quantile, c(0.025, 0.975))
##            [,1]      [,2]      [,3]
## 2.5%  -1.890475 -1.950963 -1.990845
## 97.5%  1.981555  1.977111  1.992657

Exercise: Matrix Standardization

We looked at two different ways to standardize the columns of a matrix:

x <- matrix(rexp(6000000), ncol=6000)

system.time(for(i in 1:6000){x[,i] <- x[,i]/sum(x[,i])})
##    user  system elapsed 
##   0.050   0.011   0.061

system.time(scale(x, center=F, scale=colSums(x)))
##    user  system elapsed 
##   0.040   0.005   0.045

Your task: Find a third approach and compare the computation time to the first two approaches. Post your solution on Ed Discussion.

Hint: Consider using sweep() (see Sweeping in the Self-Guided Practice section) or vectorization with matrix operations

Conditional Statements

x <- 7
if(x <= 10){
  print("Less than or equal to 10!")
} else {
  print("Greater than 10!")
}
## [1] "Less than or equal to 10!"

Logical operators:

if(x <= 10 & x > 5){
  print("Between 5 and 10!")
}
## [1] "Between 5 and 10!"

& = and, | = or

Vectorized Conditionals

x <- c(1, 3, -1)

if(x < 2){print("Hello")} else{print("Bye")}
## Warning: condition has length > 1
## [1] "Hello"

ifelse(x < 2, "Hello", "Bye")
## [1] "Hello" "Bye"   "Hello"

Nested ifelse:

ifelse(x < 2, ifelse(x < 0, "Hello", ""), "Bye")
## [1] ""      "Bye"   "Hello"

The expand.grid Function

Evaluate functions on a 2D grid:

x <- seq(-2, 2, length=50)
y <- seq(-2, 2, length=50)
f <- function(x, y) x^2 + y^2

# This only evaluates diagonal
str(f(x, y))
##  num [1:50] 8 7.36 6.75 6.16 5.6 ...

# This evaluates full grid
z <- expand.grid(x, y)
str(f(z[,1], z[,2]))
##  num [1:2500] 8 7.68 7.37 7.08 6.8 ...

Exercise: Function Minimization

Finding the Minimum of a Function

Consider the following function:

\(f(x, y) = (1.5 - x + xy)^2 + (2.25 - x + xy^2)^2 + (2.625 - x + xy^3)^2\)

where possible inputs for \(x\) and \(y\) are from -4 to 4 in increments of 0.1.

Your tasks:

  1. Create a grid of all (x, y) combinations using expand.grid()
  2. Evaluate the function at all points in the grid
  3. Find the global minimum - what values of x and y result in this minimum?

Hint: Use which.min() to find the index of the minimum value

Saving and Importing Data

Saving Your Work

Save specific objects (reload them later with load()):

x <- seq(1, 8)
y <- c("CA", "NE")
save(x, y, file="myobjects.RData")

Save matrix as text:

x <- matrix(1:10, ncol=5)
write(x, file="myfile.txt")

Importing Data: Manual Entry

For small datasets:

y1 <- c(22, 26)
y2 <- c(28, 24, 29)
y3 <- c(29, 32, 28)
y4 <- c(23, 24)

y <- c(y1, y2, y3, y4)
Model <- c(rep("A", 2), rep("B", 3), rep("C", 3), rep("D", 2))
mileages <- data.frame(y, Model)

Importing from Files

Text file with headers:

arod <- read.table("data/a-rod-2016.txt", header=T)

CSV files:

data <- read.csv("mydata.csv")

Tips for preparing data:

  • Same number of columns per row

  • Use NA for missing data

  • Remove special characters

  • Replace spaces in headers with underscores

Reformatting Data

df <- PlantGrowth
unstacked_df <- unstack(df)
head(unstacked_df, 3)
##   ctrl trt1 trt2
## 1 4.17 4.81 6.31
## 2 5.58 4.17 5.12
## 3 5.18 4.41 5.54

stacked_df <- stack(unstacked_df)
head(stacked_df, 3)
##   values  ind
## 1   4.17 ctrl
## 2   5.58 ctrl
## 3   5.18 ctrl

Merging Data Frames

authors <- data.frame(
  surname = c("Tukey", "Venables", "Tierney", "Ripley", "McNeil"), 
  nationality = c("US", "AUS", "US", "UK", "AUS")
)

books <- data.frame(
  name = c("Tukey", "Venables", "Tierney", "Ripley", "Ripley", "McNeil", "R Core"), 
  title = c("Exploratory Data Analysis", "Modern Applied Statistics", 
            "LISP-STAT", "Spatial Statistics", "Stochastic Simulation", 
            "Interactive Data Analysis", "An Introduction to R")
)

m1 <- merge(authors, books, by.x = "surname", by.y = "name")

Merge Result

m1
##    surname nationality                         title
## 1   McNeil         AUS   Interactive Data Analysis
## 2   Ripley          UK          Spatial Statistics
## 3   Ripley          UK         Stochastic Simulation
## 4  Tierney          US                     LISP-STAT
## 5    Tukey          US     Exploratory Data Analysis
## 6 Venables         AUS Modern Applied Statistics

Only matching rows are kept by default!

Wrapping up

Reflection time ๐Ÿค”

Think-pair-share (5 minutes) โฑ๏ธ

Think (1 min): Name one thing you learned about R this week that you didnโ€™t know before.

Pair (2 min): Share with your neighbor and listen to their surprise ๐Ÿ‘ฅ

Share (2 min): Share it on Ed Discussion ๐Ÿ—ฃ๏ธ

Remember: Every expert was once a beginner! ๐ŸŒฑ

Questions?

Resources:

Next week: Numerical summaries, categorical data, and exploratory data analysis ๐Ÿ“Š

๐Ÿ“ Self-Guided Practice (Wednesday Session)

The following slides were part of this weekโ€™s original material but are not covered live. Work through them on your own, or bring questions to the Wednesday self-guided session.

Lazy Evaluation

R doesnโ€™t check unused arguments:

f <- function(a, b){
  return(a)
}

f(3)        # No error!
## [1] 3

f(3, 2)     # Also works
## [1] 3

Functions as arguments:

summarizex <- function(x, ff){
  z <- ff(x)
  return(z)
}

summarizex(c(1,2,-1,4,0), mean)
## [1] 1.2

Scoping

R allows free variables in functions:

b <- 4
f <- function(x, y){
  z <- x + y/b
  return(z)
}

f(3, 2)
## [1] 3.5

Warning: Avoid free variables unless you know what youโ€™re doing! Can cause unexpected behavior.

Linear Algebra with Matrices

# Create matrices for linear algebra
A <- matrix(c(2, 1, 3, 4), nrow = 2)
B <- matrix(c(1, 2, 2, 1), nrow = 2)

A
     [,1] [,2]
[1,]    2    3
[2,]    1    4
B
     [,1] [,2]
[1,]    1    2
[2,]    2    1
# Matrix operations
A + B            # Element-wise addition
     [,1] [,2]
[1,]    3    5
[2,]    3    5
A - B            # Element-wise subtraction
     [,1] [,2]
[1,]    1    1
[2,]   -1    3
A * B            # Element-wise multiplication (NOT matrix multiplication)
     [,1] [,2]
[1,]    2    6
[2,]    2    4
A %*% B          # Matrix multiplication
     [,1] [,2]
[1,]    8    7
[2,]    9    6
# More linear algebra operations
t(A)             # Transpose
     [,1] [,2]
[1,]    2    1
[2,]    3    4
det(A)           # Determinant (for square matrices)
[1] 5
solve(A)         # Matrix inverse
     [,1] [,2]
[1,]  0.8 -0.6
[2,] -0.2  0.4
eigen(A)         # Eigenvalues and eigenvectors
eigen() decomposition
$values
[1] 5 1

$vectors
           [,1]       [,2]
[1,] -0.7071068 -0.9486833
[2,] -0.7071068  0.3162278
# Verify inverse: A %*% solve(A) should equal identity matrix
A %*% solve(A)
     [,1]          [,2]
[1,]    1 -1.110223e-16
[2,]    0  1.000000e+00

Sweeping

The sweep() function sweeps out a statistic from a matrix:

A <- matrix(1:16, 4, 4, byrow=T)
A
##      [,1] [,2] [,3] [,4]
## [1,]    1    2    3    4
## [2,]    5    6    7    8
## [3,]    9   10   11   12
## [4,]   13   14   15   16

m <- max(A)
A1 <- sweep(A, MARGIN=1:2, STATS=m, FUN="-")

Sweep Example: Centering

Subtract column means:

colMeans(A)
## [1]  7  8  9 10

sweep(A, 2, colMeans(A), "-")
##      [,1] [,2] [,3] [,4]
## [1,]   -6   -6   -6   -6
## [2,]   -2   -2   -2   -2
## [3,]    2    2    2    2
## [4,]    6    6    6    6

Each column now has mean = 0!

Arrays

R supports higher-order arrays:

S <- array(1:24, dim=c(4,2,3))
## , , 1
##      [,1] [,2]
## [1,]    1    5
## [2,]    2    6
## [3,]    3    7
## [4,]    4    8
## 
## , , 2
##      [,1] [,2]
## [1,]    9   13
## [2,]   10   14
## [3,]   11   15
## [4,]   12   16

Document Creation Tools

LaTeX Integration in Quarto

Quarto has built-in support for LaTeX typesetting:

  • LaTeX: Professional typesetting system for technical documents ๐Ÿ“„
  • Math Equations: Beautiful mathematical notation ๐Ÿ“
  • Bibliography: Automatic citation management ๐Ÿ“š
  • Cross-references: Automatic numbering and linking ๐Ÿ”—
% Example LaTeX equation in Quarto
$$\bar{x} = \frac{1}{n}\sum_{i=1}^{n} x_i$$

% Inline math: The mean is $\bar{x}$

Quarto: Reproducible Documents

Quarto combines code, text, and output in one document:

  • Code Chunks: Executable R code within text ๐Ÿ’ป
  • Multiple Outputs: HTML, PDF, Word, presentations ๐Ÿ“Š
  • Dynamic: Results update when code changes ๐Ÿ”„
  • Reproducible: Anyone can recreate your analysis ๐Ÿ”
# My Analysis


::: {.cell}

```{.r .cell-code}
# This code will run and show results
summary(penguins)
```

::: {.cell-output .cell-output-stdout}

```
      species          island    bill_length_mm  bill_depth_mm  
 Adelie   :152   Biscoe   :168   Min.   :32.10   Min.   :13.10  
 Chinstrap: 68   Dream    :124   1st Qu.:39.23   1st Qu.:15.60  
 Gentoo   :124   Torgersen: 52   Median :44.45   Median :17.30  
                                 Mean   :43.92   Mean   :17.15  
                                 3rd Qu.:48.50   3rd Qu.:18.70  
                                 Max.   :59.60   Max.   :21.50  
                                 NAs    :2       NAs    :2      
 flipper_length_mm  body_mass_g       sex           year     
 Min.   :172.0     Min.   :2700   female:165   Min.   :2007  
 1st Qu.:190.0     1st Qu.:3550   male  :168   1st Qu.:2007  
 Median :197.0     Median :4050   NAs   : 11   Median :2008  
 Mean   :200.9     Mean   :4202                Mean   :2008  
 3rd Qu.:213.0     3rd Qu.:4750                3rd Qu.:2009  
 Max.   :231.0     Max.   :6300                Max.   :2009  
 NAs    :2         NAs    :2                                 
```


:::
:::


The mean bill length is 43.9219298 mm.