R Factors

A factor is R's way of representing categorical data with a fixed, known set of possible values, which makes grouping, ordering, and modeling categorical variables far more reliable than plain text.

What Is a Factor?

A factor stores a variable that can only take on a limited set of values, called levels — think blood type, shirt size, or a survey rating. Internally R stores a factor as small integer codes plus a table of level labels, which is more memory-efficient than repeating the same text over and over and lets functions like table() and many statistical models treat the variable as categorical rather than free text.

Creating a Factor

mood <- factor(c("happy", "sad", "happy", "angry", "happy"))
print(mood)
table(mood)

Levels and the Codes Behind Them

Every factor has a set of levels — the distinct categories it's allowed to hold — and each value is stored as an integer pointing into that list of levels. By default R orders the levels alphabetically, so the first level alphabetically becomes code 1, the next becomes code 2, and so on.

Inspecting Levels

levels(mood)
nlevels(mood)
as.integer(mood)

Ordered Factors

Some categories have a natural order — small, medium, large, or low, medium, high. Passing ordered = TRUE (along with an explicit levels argument) tells R about that sequence, which unlocks meaningful comparisons like < and > between factor values, and makes sort() arrange them by rank instead of alphabetically.

Comparing Ordered Levels

size <- factor(c("S", "M", "L", "M"),
               levels = c("S", "M", "L"),
               ordered = TRUE)
size[1] < size[3]
sort(size)
AspectRegular FactorOrdered Factor
Created withfactor(x)factor(x, levels = ..., ordered = TRUE)
Comparing with < or >Returns NA with a warningWorks, following the level order
Typical useCategories with no rank, like city or colorCategories with rank, like S/M/L or low/medium/high
Note: Since R 4.0, functions like data.frame() and read.csv() no longer convert text columns into factors automatically — you now have to call factor() yourself when you want one, which avoids a lot of accidental categorical data in older R scripts.
  • Converting a factor straight to numbers with as.numeric(f) returns the internal codes, not the original values — go through as.numeric(as.character(f)) if you need the real numbers back.
  • Subsetting a factor doesn't drop unused levels automatically; call droplevels(f) afterward to clean it up.
  • table(f) and summary(f) are quick ways to see how many observations fall into each level.
  • Comparing two factors that were built with different level sets can silently produce NA — make sure levels line up before comparing.

Exercise: R Factors

What does the factor() function primarily do to a vector?