Pebellslearn by building
0%
RoadmapsMatrixCoursesSandboxSign in
Data Structures  ›  Lesson

Factors — Categories with Levels

Factors 12 minA factor stores categorical data as integer codes that point into a fixed set of levels, which by default are the sorted unique values.

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 2

A 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 large

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

Codes for factor(c("10", "5", "20"))Step 1 of 4
  1. Unique values

    "10", "5" and "20".

Drills

Answer fast — trust the rule.

quick drill

What is levels(factor(c("tomato", "bean", "chilli")))?

quick drill

What is as.integer(factor(c("b", "a", "c", "a")))?

quick drill

What does as.numeric(factor(c("10", "5", "20"))) return?

quick drill

After crop[2] <- "pumpkin", where "pumpkin" is not a level, what is crop[2]?

quick drill

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 through as.character() first.

Practice — level up

0/1 solved

Write your answer, then compare it with a rubric and a model answer.

ExplainThe factor number trap

A column of bed sizes was read in as sizes <- factor(c("10", "5", "20")). Explain why as.numeric(sizes) returns 1 3 2 instead of 10 5 20, and how to get the real numbers.