An old printer's type case: lead letters, brass screws, glass beads and paper slips, one kind per column
a type case keeps many small things in order because every column holds only one kind of thing.
image: ai-generated (gpt-image-2.5-flare)

four shapes of data

in a matrix every cell has the same type, in a data frame every column has its own.

one game, four facts

image: ai-generated (gpt-image-2.5-flare)

play a few rounds

play the game on the site, and stay or switch.
after a few rounds the game shows your rounds as R code, one line per fact.

rounds as vectors

prize_door <- c(2, 1, 3, 3, 1) contestant_choice <- c(2, 3, 1, 1, 1) monty_opens <- c(1, 2, 2, 2, 3) decision <- c("stay", "switch", "stay", "switch", "switch")
c() combines values into a vector, and the first value of each vector belongs to the first round.

the same position, the same round

four vectors of the same length describe five rounds, as long as nobody mixes up the order.

one vector, one type

every value in a vector has the same type, and typeof() tells you which one.

asking a vector

length(prize_door) # 5 typeof(decision) # "character" mean(prize_door) # 2 table(decision) # stay 2, switch 3
sum, mean, median, min, max, range, sd, sort, unique, table: functions that take a whole vector at once.

when types meet

R never mixes types in a vector, it quietly converts to the most general one.

comparing whole vectors

an operation on two vectors works position by position, with no loop to write.

counting with TRUE and FALSE

first_pick_right <- prize_door == contestant_choice sum(first_pick_right) # 2 mean(first_pick_right) # 0.4
R counts TRUE as 1 and FALSE as 0, so the mean of a logical vector is a share.

picking values by position

decision[1] # "stay"
decision[-1] # all but the first
decision[2:4] # "switch" "stay" "switch"
decision[c(1, 3)] # "stay" "stay"
square brackets select, a minus leaves out, and the result is again a vector.

picking values by a condition

a logical vector in square brackets keeps exactly the positions that are TRUE.

when a value is missing

NA means "not known", so anything computed with it is not known either, until you say what to do.

factors: text with fixed levels

decision_factor <- factor( decision, levels = c("stay", "switch") ) levels(decision_factor) # "stay" "switch"
a factor knows all its possible values and their order, even those that do not occur.
a vector is a row of values of one type, and position i belongs to observation i.

vectors become a table

games <- data.frame(prize_door, contestant_choice, monty_opens, decision)
a data frame is a list of equally long vectors, and every vector holds values of one type.

tidy data

after Wickham, Çetinkaya-Rundel & Grolemund: R for Data Science, chapter "data tidying"
when a table is tidy, every column is a vector of one variable, and the tools of R fit it.

data frame and tibble

read.csv("lets_make_a_deal.csv")
86 Linda 2 1 3 stay 87 Robert 3 3 2 stay 88 Barbara 1 3 2 stay 89 Karen 2 2 1 stay 90 Sarah 1 3 2 switch 91 Joseph 1 1 3 stay 92 Richard 1 2 3 switch 93 Charles 1 1 3 stay 94 Susan 3 1 2 stay 95 Patricia 1 3 2 stay 96 Richard 1 2 3 stay 97 Patricia 1 3 2 switch 98 Susan 3 3 1 stay 99 Jessica 1 2 3 stay 100 Patricia 1 1 3 stay
read_csv("lets_make_a_deal.csv")
# A tibble: 100 × 5 contestant prize_door contestant_choice monty_opens decision <chr> <dbl> <dbl> <dbl> <chr> 1 Charles 3 3 2 stay 2 Patricia 1 3 2 stay 3 Karen 3 3 1 stay 4 Jessica 3 1 2 stay 5 Joseph 1 3 2 stay 6 Robert 1 3 2 stay 7 John 3 1 2 stay 8 Richard 2 3 1 switch 9 Michael 3 1 2 stay 10 Elizabeth 3 2 1 switch # ℹ 90 more rows
a tibble is a data frame with better manners: it shows the types and does not flood the console.

100 games as a tibble

library(tidyverse) monty_hall <- read_csv("lets_make_a_deal.csv") glimpse(monty_hall)
Rows: 100 Columns: 5 $ contestant <chr> "Charles", "Patricia", "Karen", "Jessica", "… $ prize_door <dbl> 3, 1, 3, 3, 1, 1, 3, 2, 3, 3, 3, 3, 1, 3, 2,… $ contestant_choice <dbl> 3, 3, 3, 1, 3, 3, 1, 3, 1, 2, 3, 2, 1, 3, 1,… $ monty_opens <dbl> 2, 2, 1, 2, 2, 2, 2, 1, 2, 1, 2, 1, 2, 2, 3,… $ decision <chr> "stay", "stay", "stay", "stay", "stay", "sta…
glimpse() turns the table on its side and shows every column with its type and first values; it is the first thing to run on new data.
a data frame is a list of equally long vectors, and every vector holds values of one type.