Factors — Categories with Levels
The crop column holds only three possible values: tomato, bean and chilli. Categories like this have a fixed list of allowed values and often a natural order, and R has a dedicated type for them. Factors make counting, plotting and modelling by group work properly, but they hide a trap that catches almost everyone once.
The rule
A factor stores categories as integer codes plus a fixed set of levels.
crop <- factor(c("tomato", "bean", "tomato", "chilli", "bean"))
crop # tomato bean tomato chilli bean
# Levels: bean chilli tomato
levels(crop) # "bean" "chilli" "tomato"
nlevels(crop) # 3
as.integer(crop) # 3 1 3 2 1, the codes underneath
table(crop) # bean 2, chilli 1, tomato 2A factor has two parts:
- Levels: the allowed categories. By default they are the unique values sorted alphabetically.
- Codes: one integer per element, pointing at its level. "tomato" is level 3, so it is stored as 3.
You can choose the level order yourself, which controls the order in tables and charts:
crop <- factor(crop, levels = c("tomato", "bean", "chilli"))For categories with a real ranking, make an ordered factor, and comparisons start to work:
size <- factor(c("small", "large", "medium"),
levels = c("small", "medium", "large"), ordered = TRUE)
size[1] < size[2] # TRUE: small comes before largeLevels are a fixed list. Assigning a value that is not a level fails softly: crop[2] <- "pumpkin" turns that element into NA with the warning invalid factor level, NA generated. Add the level first if you really want it. droplevels() removes levels that no longer appear in the data.
Since R 4.0, data.frame() and read.csv() keep text as character by default, so you create factors on purpose with factor().
The shortcut
To predict a factor's codes: sort the unique values to get the levels, then replace each value with its position in that list. Remember that the sorting is done as text.
Unique values
"10", "5" and "20".
Drills
Answer fast — trust the rule.
What is levels(factor(c("tomato", "bean", "chilli")))?
What is as.integer(factor(c("b", "a", "c", "a")))?
What does as.numeric(factor(c("10", "5", "20"))) return?
After crop[2] <- "pumpkin", where "pumpkin" is not a level, what is crop[2]?
What is nlevels(crop) for the garden's five crop entries?
Remember
- A factor stores categories as integer codes plus a fixed set of levels.
- Shortcut: sort the unique values as text to get the levels; each value's code is its position.
- Trap:
as.numeric()on a factor gives codes; go throughas.character()first.
