Lesson 4 of 17 · Week 02 · Thu Oct 1

Data Structures

Questions

Objectives

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:

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 used

Click 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:

  1. Use str(plants2) to see the column types.
  2. Replace the bad entry with the mean of the two numbers in it, e.g. plants2$height_cm[ROW] <- VALUE.
  3. Convert the column to numbers with as.numeric().
  4. Store the mean height in avg_height. If you get NA, a step went wrong.
Pasting isn't accepted here — please type your answer so it reflects your own work.

      

Exercise 2 — Scale a sequence

0 / 10 attempts used

Click 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.

Pasting isn't accepted here — please type your answer so it reflects your own work.

      

Exercise 3 — What type are the names?

0 / 10 attempts used

bus_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.

Pasting isn't accepted here — please type your answer so it reflects your own work.

      

Exercise 4 — Number the months

0 / 10 attempts used

Create 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.

Pasting isn't accepted here — please type your answer so it reflects your own work.

      

Exercise 5 — Vector or data frame?

0 / 10 attempts used

plants (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.

Pasting isn't accepted here — please type your answer so it reflects your own work.

      

Exercise 6 — Length of a matrix

0 / 10 attempts used

Click 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?

Pasting isn't accepted here — please type your answer so it reflects your own work.

      

Exercise 7 — Fill by row

0 / 10 attempts used

Click 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).

Pasting isn't accepted here — please type your answer so it reflects your own work.

      

Exercise 8 — A list of what you know

0 / 10 attempts used

Make a list called so_far with two named elements:

  • types: a character vector with the names of the data types from this lesson (at least logical, integer, double, character), and
  • structures: a character vector with the data structures from this lesson (at least vector, factor, list, matrix, data.frame).
Pasting isn't accepted here — please type your answer so it reflects your own work.

      

Exercise 9 — Which command made this?

0 / 10 attempts used

Click 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.

Pasting isn't accepted here — please type your answer so it reflects your own work.

      

Key Points

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.