Data Frames, Tibbles and data.table
Everything so far comes together here. The garden's harvest log is a table: one row per plot, one column per measurement, and each column its own type. That is exactly a data frame, the structure most R work happens in.
The rule
A data frame is a list of equal-length columns, indexed
[rows, columns].
harvest <- data.frame(
plot = c("A", "B", "C", "D", "E"),
crop = c("tomato", "bean", "tomato", "chilli", "bean"),
kg = c(12.5, 8, 15, 3.5, 6),
watered = c(TRUE, FALSE, TRUE, TRUE, FALSE)
)It combines the two structures you already know. Like a list, it holds items of different types. Like a vector, each column holds one type. Every column must have the same length, so the rows line up.
nrow(harvest); ncol(harvest) # 5 and 4
str(harvest) # one line per column: name, type, values
harvest$kg # 12.5 8.0 15.0 3.5 6.0, a column as a vector
harvest[2, ] # row 2 (plot B), all columns
harvest[harvest$kg > 7, "plot"] # "A" "B" "C"
harvest[, c("plot", "kg")] # two columns, all rows
harvest$kg_per_m2 <- harvest$kg / 4 # add a new columnThe brackets work like a matrix: rows before the comma, columns after it, blank meaning all. Rows are usually chosen with a logical test and columns by name. head() shows the first rows and summary() summarises every column.
Two popular alternatives follow the same idea.
Tibbles, from the tibble package in the tidyverse, are data frames with stricter manners. tibble::as_tibble(harvest) prints each column's type and only as many rows as fit on screen, never turns text into factors, warns instead of guessing when you misspell a column after $, and keeps a tibble when you select a single column with [ , "kg"]. A plain data frame would hand you a bare vector instead.
data.table, from the data.table package, is built for speed on large tables. Its brackets read dt[i, j, by]: which rows, what to compute, grouped by what. Inside them you name columns directly:
library(data.table)
dt <- as.data.table(harvest)
dt[kg > 7, .(total = sum(kg)), by = crop] # tomato 27.5, bean 8The shortcut
Read every [ , ] as "which rows, which columns". Build the row part as a logical test, name the columns, and leave blank what you want all of.
Watered?
harvest$wateredis TRUE FALSE TRUE TRUE FALSE.
Drills
Answer fast — trust the rule.
What is harvest[3, "crop"]?
What is nrow(harvest[harvest$kg < 10, ])?
On a plain data frame, what does harvest[, "kg"] return?
What is mean(harvest$kg[harvest$crop == "bean"])?
With dt <- as.data.table(harvest), what total does dt[, .(total = sum(kg)), by = watered] give for the TRUE group?
Remember
- A data frame is a list of equal-length columns, indexed
[rows, columns]. - Shortcut: read
[ , ]as "which rows, which columns"; build rows from a logical test. - Trap: a single selected column drops to a vector in a data frame, but not in a tibble.
