Lesson 4 of 17 · Week 02 · Thu Oct 1
Data Structures
Questions
- What are R's basic data types?
- Why does one bad value turn a numeric column into text?
- What are vectors, factors, lists, matrices and data frames, and how do they relate?
Objectives
- Identify the five atomic types with
typeof(). - Predict coercion when types are mixed, and convert types on purpose.
- Name vector elements and look them up by name.
- Build lists and matrices, and tell which kind of object an extraction returns.
Start with a small table
Here's a small data frame about garden plants. Type it into your script and run it; we'll use it all lesson:
plants <- data.frame(species = c("fern", "basil", "cactus"),
height_cm = c(32.5, 21.0, 14.2),
flowering = c(FALSE, TRUE, TRUE))
plants
plants$height_cm # one column, with $
plants$height_cm * 10 # in millimetres
paste("My", plants$species)
Each column of a data frame is a vector, and every element of a vector has the same type. These two ideas explain most of R's surprising behaviour, so they're the subject of this lesson.
Adapted from Software Carpentry's “Data Structures” episode (CC BY 4.0, The Carpentries). Text, examples and exercises have been rewritten for this course.
Data types
R has five basic (“atomic”) types. typeof() tells you which one you have:
typeof(3.14) # "double" numbers with decimals (the default for numbers)
typeof(2L) # "integer" whole numbers; the L makes it an integer
typeof(TRUE) # "logical" TRUE / FALSE
typeof("fern") # "character" text
typeof(1 + 2i) # "complex" rarely needed
class() answers a related question: what kind of object is this (e.g. "numeric",
"data.frame", "factor")? str() shows both the structure and a preview.
Vectors and coercion
Make vectors with c(), sequences with : or seq(), and empty ones with
vector("numeric", length = 3). Since a vector holds one type only, mixing types forces R to
coerce everything to the most flexible type present:
logical < integer < double < complex < character
c(2, "three") # "2" "three" character wins
c(TRUE, 5) # 1 5 TRUE becomes 1
This matters when data is messy: one stray non-number in a column of a CSV (say, "2.3 or 2.4") turns the
whole column into text. You convert deliberately with as.numeric(), as.character(),
as.logical(). Anything that can't be converted becomes NA (with a warning).
Other vector helpers: length(), head(), tail(), append(), and
seq(10, 100, by = 10).
Names
fares <- c(adult = 2.50, student = 1.25)
names(fares) # "adult" "student"
fares["student"] # look up by name
names(fares)[2] <- "child" # change one name
names(fares) <- c("A", "C") # replace them all
R also has built-in constants you can use for names: LETTERS, letters, month.name and
month.abb.
Factors
A factor stores categorical data: a fixed set of levels, with each value pointing at one.
size <- factor(c("small", "large", "small", "medium"))
levels(size) # sorted alphabetically by default
size <- factor(size, levels = c("small", "medium", "large")) # set the order
table(size)
Lists
A list is a vector whose elements can be anything, including different types and lengths:
trip <- list(place = "Monteverde", days = 3, species_seen = c("quetzal", "sloth"))
trip$species_seen
trip[["days"]]
A data frame is actually a list of equal-length vectors (its columns), which explains the ways of pulling pieces out of it:
plants$species,plants[["species"]],plants[[1]]: the column itself, a vector.plants["species"],plants[1]: a smaller data frame with just that column.plants[2, 1]: row 2, column 1, a single value.plants[, 1]: all rows of column 1 (a vector).plants[2, ]: row 2, all columns (a one-row data frame).
Matrices
A matrix is a vector with rows and columns: every element has the same type.
m <- matrix(1:6, nrow = 2, ncol = 3) # filled column by column
m
dim(m); nrow(m); ncol(m)
matrix(1:6, nrow = 2, byrow = TRUE) # filled row by row
Exercises
Each exercise gives you up to 10 checked attempts. Use Run as many times as you like to experiment first, then click Check answer when you're ready. Your exercises use numbers/subsets unique to you, so answers won't match a classmate's exactly.
Exercise 1 — Clean a messy column
0 / 10 attempts usedClick Run to see plants2. Someone typed a range like "14 or 16" into one
height, so the whole height_cm column is text. In your code:
- Use
str(plants2)to see the column types. - Replace the bad entry with the mean of the two numbers in it, e.g.
plants2$height_cm[ROW] <- VALUE. - Convert the column to numbers with
as.numeric(). - Store the mean height in
avg_height. If you getNA, a step went wrong.
Exercise 2 — Scale a sequence
0 / 10 attempts usedClick Run to see from, to and k. Make a vector s
holding the whole numbers from from to to, then a vector scaled equal to
s multiplied by k. Use the variables, not typed-in numbers.
Exercise 3 — What type are the names?
0 / 10 attempts usedbus_fares is a named vector (click Run). Using typeof(), store the type of the
fares themselves in values_type and the type of their names in names_type.
Exercise 4 — Number the months
0 / 10 attempts usedCreate month_no: the numbers 1 to 12, with the abbreviated month names
("Jan", "Feb", …) as its names, using the built-in month.abb and
names(...) <-. Then look up the month printed when you click Run by name, and
store the result in pick.
Exercise 5 — Vector or data frame?
0 / 10 attempts usedplants (from the top of this page) is defined for you. Click Run to print four ways of
extracting part of it. For each, predict what class() returns: "data.frame",
"character", "numeric" or "logical". Store your four answers, in order, in
classes. Then check yourself by running class() on each.
Exercise 6 — Length of a matrix
0 / 10 attempts usedClick Run to see how grid is made. Before running
length(grid), write your prediction in my_guess (a number). Then run it. Were you right? Why?
Exercise 7 — Fill by row
0 / 10 attempts usedClick Run to see vals, nr and nc. Make a matrix
m_row holding vals with nr rows and nc columns, filled row by
row (by default matrix() fills column by column; check ?matrix for how to change that).
Exercise 8 — A list of what you know
0 / 10 attempts usedMake a list called so_far with two named elements:
types: a character vector with the names of the data types from this lesson (at leastlogical,integer,double,character), andstructures: a character vector with the data structures from this lesson (at leastvector,factor,list,matrix,data.frame).
Exercise 9 — Which command made this?
0 / 10 attempts usedClick Run to print a matrix and four candidate commands. Work out which command produced it, and store
its number (1 to 4) in answer. Reason it through first, then check by running the candidates.
Key Points
- Every element of a vector has the same type; mixing types coerces to the most flexible one.
- Convert on purpose with
as.numeric()and friends; check withstr(). - A data frame is a list of equal-length column vectors.
[[ ]]and$pull out a column as a vector;[ ]with one index keeps a data frame.- A matrix is a vector with dimensions;
byrow = TRUEfills it across rows.
Proof of completion
Once you've attempted every exercise above, download a PDF summary of your work on this lesson — your name, the exercises you passed, attempt counts, timing, and your final code for each.