Factors

Reviewed & published by Brayan K

A factor is R's data structure for categorical data — values drawn from a fixed set of categories called levels, like sizes, survey answers, or country names.

Part of the free R course at LearnCodingFast — hands-on lessons with worked examples and the output they print, plus practice exercises and a quick quiz.

By the end of this lesson you'll create factors, inspect and count their levels with table(), build ordered factors for ranked categories, and avoid the classic mistake of converting a factor straight to numbers.

What You'll Learn in This Lesson

1️⃣ Creating and Counting Factors

Wrap a character vector in factor() to turn it into categorical data. R finds the distinct values (the levels) and stores each entry as a reference to a level. table() gives you an instant frequency count.

# A factor stores CATEGORICAL data — values from a fixed set of "levels".
# Build one from a character vector with factor().

colors <- c("red", "green", "red", "blue", "green")
f <- factor(colors)
f                    # -> [1] red   green red   blue  green
                     #    Levels: blue green red

# levels() shows the distinct categories (alphabetical by default):
levels(f)            # -> [1] "blue"  "green" "red"

# table() counts how many of each level — extremely useful:
table(f)

2️⃣ Ordered Factors

When categories have a natural ranking, pass ordered = TRUE and list the levels from lowest to highest. Now comparisons and min()/max() respect that order.

# Some categories have a natural ORDER (small < medium < large).
# Use ordered = TRUE and set the levels yourself.

sizes <- c("medium", "small", "large", "small", "large")
sf <- factor(sizes,
             levels = c("small", "medium", "large"),
             ordered = TRUE)
sf                   # prints with the order you set

# Now comparisons make sense:
sf > "small"         # -> [1]  TRUE FALSE  TRUE FALSE  TRUE
min(sf)              # -> [1] small
                     #    Levels: small < medium < large

Notice the printed levels now show small < medium < large — R understands the ranking, so sf > "small" is meaningful.

3️⃣ Factors Are Integers Underneath

Internally a factor maps each level to an integer code. This makes factors efficient but causes a famous trap: converting a factor of number-like labels with as.integer() gives you the codes, not the labels. Always go via as.character() first.

# Factors are stored as integers under the hood, with a label per level.
# That trips people up when converting back to numbers.

ratings <- factor(c("3", "1", "2", "3"))
as.integer(ratings)        # the LEVEL codes, NOT the labels! -> [1] 3 1 2 3

# To recover the original numbers, go via character first:
as.integer(as.character(ratings))   # -> [1] 3 1 2 3

# Count and summarise:
summary(factor(c("yes", "no", "yes", "yes")))   # -> no yes
                                                 #     1   3

Your turn. Fill in the ___ blank, run it, and compare with the expected output.

# 🎯 YOUR TURN — replace each ___ then run it.

shirts <- c("S", "L", "M", "L", "S", "M", "L")

# 1) Make an ORDERED factor with levels small to large
sizes <- factor(shirts,
                levels = ___,   # 👉 replace ___ with c("S", "M", "L")
                ordered = TRUE)

# 2) Count how many of each size with table()
print(table(sizes))

# 3) Print the largest size ordered
cat("Largest ordered:", as.character(max(sizes)), "\n")

# ✅ Expected output:
# sizes
# S M L
# 2 2 3
# Largest ordered: L

Mini-Challenge: Survey Responses

Write it from the outline, run it, and check it against the example output. Ordered factors make "agree or stronger" a one-line comparison.

Common Errors (and the fix)

Pro Tips

📋 Quick Reference — Factors

TaskR Syntax
Make a factorfactor(x)
See categorieslevels(f)
Count each categorytable(f)
Ordered factorfactor(x, ordered = TRUE)
Number labels backas.numeric(as.character(f))
Drop empty levelsdroplevels(f)

🎉 Lesson Complete!

Practice quiz

What kind of data is a factor designed to store?

  • Categorical data from a fixed set of levels
  • Only continuous numbers
  • Dates and times
  • Raw binary data

Answer: Categorical data from a fixed set of levels. A factor stores categorical data drawn from a fixed set of categories called levels.

Which function creates a factor from a character vector?

  • as.category()
  • factor()
  • levels()
  • table()

Answer: factor(). factor() turns a vector into categorical data.

Which function shows the distinct categories of a factor?

  • table()
  • summary()
  • levels()
  • names()

Answer: levels(). levels(f) returns the factor's distinct categories.

Which function gives a frequency COUNT of each level?

  • count()
  • length()
  • factor()
  • table()

Answer: table(). table(f) counts how many entries fall in each level.

How do you create an ORDERED factor?

  • factor(x, ordered = TRUE)
  • ordered.factor(x)
  • factor(x, rank = TRUE)
  • sort(factor(x))

Answer: factor(x, ordered = TRUE). Pass ordered = TRUE (and set levels low to high) to make an ordered factor.

By default, in what order are a factor's levels arranged?

  • Order of first appearance
  • Alphabetical order
  • Reverse order
  • Random order

Answer: Alphabetical order. Without an explicit levels argument, levels default to alphabetical order.

How are factors stored internally?

  • As plain character strings
  • As dates
  • As integer codes plus a label per level
  • As raw bytes

Answer: As integer codes plus a label per level. A factor maps each level to an integer code, with the labels stored once.

Why can as.integer() on a factor of "10","20","30" give 1,2,3 instead of 10,20,30?

  • It rounds the values
  • It is a bug in R
  • It sorts them first
  • It returns the level codes, not the labels

Answer: It returns the level codes, not the labels. as.integer() returns the underlying level codes, not the numeric labels.

What is the safe way to convert a number-like factor back to numbers?

  • as.numeric(as.character(f))
  • as.numeric(f)
  • as.integer(f)
  • unclass(f)

Answer: as.numeric(as.character(f)). Go via character first: as.numeric(as.character(f)) recovers the original numbers.

Which function removes levels that have no data after filtering?

  • clean()
  • droplevels()
  • trim()
  • compact()

Answer: droplevels(). droplevels(f) drops categories that no longer appear in the data.

Continue this course

Frequently asked questions

What is a factor and when should I use one?

A factor is R's way of storing categorical data — variables that take values from a small, fixed set of categories, like 'small/medium/large', 'yes/no', or country names. R stores the categories (called levels) once and references them by integer codes, which is memory-efficient and tells statistical functions to treat the variable as categories rather than free text or numbers. Use factors for grouping variables, survey responses, and any column with a limited set of possible values.

What is the difference between an ordered and unordered factor?

An ordinary factor treats its levels as unordered categories — 'red', 'green', 'blue' have no inherent ranking. An ordered factor (made with ordered = TRUE) records a meaningful sequence, like 'small' < 'medium' < 'large', so comparisons such as size > 'small' and functions like min() and max() work correctly. Use ordered factors for things with a natural progression: sizes, education levels, satisfaction ratings.

Why did as.numeric() on my factor give the wrong numbers?

Because factors store integer codes for their levels, not the original values. If you have factor(c("10", "20", "30")), the underlying codes are 1, 2, 3, so as.integer() returns those codes, not 10, 20, 30. The fix is to convert to character first: as.numeric(as.character(f)). This is one of R's classic gotchas, so it's worth committing to memory.

How do I change or reorder a factor's levels?

Pass the levels argument to factor() in the order you want, e.g. factor(x, levels = c("low", "mid", "high")). To rename levels, assign to levels(f). Reordering is especially important for plots and models, because R uses the first level as the baseline/reference. Setting levels explicitly also lets you keep categories that don't appear in the data yet, which keeps tables and charts consistent.