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
- What a factor is and why categorical data needs one
- How to create factors with factor() and inspect levels()
- How to count categories with table()
- How to make ordered factors for ranked categories
- Why factors are stored as integer codes
- How to safely convert a factor back to numbers
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 < largeNotice 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 3Your 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: LMini-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)
- as.numeric(f) gives codes, not values — use as.numeric(as.character(f)) to recover the original numbers.
- A typo creates an extra level — "agreee" becomes its own category. Clean text before factoring, or set levels explicitly.
- Comparisons fail on unordered factors — f > "x" warns and returns NA unless the factor is ordered = TRUE.
- Levels in the wrong order — by default levels are alphabetical, so set levels = to control plot order and the model baseline.
Pro Tips
- 💡 table() is your friend: it's the fastest way to see category counts and spot typos in labels.
- 💡 Drop unused levels: after filtering, droplevels(f) removes categories with no data.
- 💡 Modern R: since R 4.0, read.csv() keeps text as character by default — call factor() when you actually want categories.
📋 Quick Reference — Factors
| Task | R Syntax |
|---|---|
| Make a factor | factor(x) |
| See categories | levels(f) |
| Count each category | table(f) |
| Ordered factor | factor(x, ordered = TRUE) |
| Number labels back | as.numeric(as.character(f)) |
| Drop empty levels | droplevels(f) |
🎉 Lesson Complete!
- ✅ A factor stores categorical data as a fixed set of levels
- ✅ table() counts each category instantly
- ✅ Ordered factors enable meaningful comparisons
- ✅ Factors are integer codes underneath — convert via as.character()
- ✅ Set levels = to control order and baselines
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
- Previous: Operators
- Next: Functions — Write reusable functions with arguments, defaults, and return values
- Quick reference: R cheat sheet
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.