forcats fct_recode() in R: Rename Factor Levels
forcats fct_recode() renames the levels of a factor by hand, one mapping at a time. You name each new label and point it at an existing level, leaving every other level untouched.
fct_recode(f, New = "old") # rename one level fct_recode(f, A = "x", B = "y") # rename several levels fct_recode(f, Big = "L", Big = "XL") # merge many levels into one fct_recode(f, "Extra Large" = "XL") # quote names that have spaces fct_recode(iris$Species, Iris = "setosa")# works on any factor column suppressWarnings(fct_recode(f, X = "z")) # silence unknown-level warning
Need explanation? Read on for examples and pitfalls.
What fct_recode() does
fct_recode() is a hand-operated level renamer. It belongs to the forcats package and changes the labels of a factor without touching the underlying data order or the level order. You supply pairs in the form new_label = "old_level", and every level you do not mention is carried through unchanged.
Start with a small factor so the behavior is easy to see.
Now rename every level with one call. The new label sits on the left of the =, the existing level (as a quoted string) sits on the right.
The values stayed in place and the level order is still L, M, S, XL order, just relabelled. fct_recode() never reorders.
fct_relevel() or fct_inorder().Syntax
The signature is fct_recode(.f, ...). The first argument .f is the factor (or a character vector, which gets coerced to a factor). The ... collects any number of new_label = "old_level" pairs.
Three rules cover almost every use:
- The new label is on the left, unquoted unless it contains spaces or starts with a digit.
- The old level is on the right, always a single quoted string.
- Repeat a label to merge several old levels into one (shown below).
When the mapping lives in a named vector, splice it into ... with the !!! operator. This is the pattern for programmatic renaming, where labels come from a lookup table rather than being typed by hand.
Examples by use case
Each example below solves a different real task. They use built-in R data so you can run them as is.
Rename levels for display
Recode terse codes into readable labels. Tidy data often stores levels in lowercase or with terse codes. Recode them to presentation-ready labels right before plotting or printing a table.
Merge several levels into one
Repeat a label to merge levels. Repeat a label on the left and fct_recode() collapses all those old levels into a single new one. Here five letter grades become a Pass/Fail factor.
Standardize inconsistent labels
Map every spelling to one clean level. Survey exports frequently mix yes, Yes, and Y for the same answer. Map each spelling to one clean level so counts are correct.
fct_recode() vs other forcats renamers
Pick the tool by how the mapping is defined. fct_recode() is best when you type the mapping by hand. For rule-based or automatic merging, reach for a sibling function.
| Function | Use it when | Example |
|---|---|---|
fct_recode() |
You rename levels by hand, one pair at a time | fct_recode(f, New = "old") |
fct_collapse() |
You merge groups of levels with named vectors | fct_collapse(f, big = c("a", "b")) |
fct_lump() |
You merge rare levels into "Other" automatically | fct_lump(f, n = 3) |
fct_relevel() |
You change level order, not their names | fct_relevel(f, "b") |
dplyr::recode() |
You recode a plain vector that is not a factor | recode(x, a = "A") |
The decision rule: if you can list every old level explicitly, use fct_recode(). If the levels to merge are defined by a count or a group, use fct_collapse() or fct_lump() instead.
levels(f) <- c(...), which forces you to supply every level in exact order. fct_recode() is safer because you name each pair, so a reordered factor cannot silently scramble your labels.Common pitfalls
Two mistakes cause almost every fct_recode() problem. Both produce a warning rather than an error, so they are easy to miss.
The first is getting the direction backwards. The new label goes on the left, the existing level on the right. Swap them and fct_recode() cannot find the level you named.
The second is naming a level that does not exist, often a typo. fct_recode() warns with Unknown levels in f and leaves the factor unchanged.
fct_recode() does not stop on a misspelled level, it only warns. Always check levels() after recoding, or the typo ships unnoticed.Try it yourself
Try it: Recode the iris Species factor so "setosa" becomes "Iris setosa" while the other two levels stay unchanged. Save the result to ex_species.
Click to reveal solution
Explanation: Levels you do not mention pass through untouched, so only "setosa" changes. The new label needs quotes because it contains a space.
Related forcats functions
fct_recode() is one of several forcats level editors. Explore these when hand-renaming is not the right fit:
- fct_collapse() merges groups of levels using named vectors.
- fct_lump() bundles the least common levels into "Other".
- fct_relevel() changes the order of levels without renaming.
- fct_other() keeps or drops named levels, sending the rest to "Other".
- fct_drop() removes unused levels after subsetting.
For the full reference, see the forcats fct_recode documentation.
FAQ
What is the difference between fct_recode() and dplyr recode()?
fct_recode() works on a factor and preserves its level structure and order, returning a factor. dplyr::recode() works on any atomic vector and returns the same type it received. Use fct_recode() when the column is already a factor and you want to keep factor semantics. Use recode() for character or numeric vectors that are not factors.
Why does fct_recode() put the new name on the left?
The pattern new = "old" mirrors normal R assignment, where the target is on the left. It also lets you reuse a name to merge levels: writing Pass = "A", Pass = "B" reads naturally as "both map to Pass". A left-side old level could not express that merge cleanly.
Can fct_recode() combine multiple factor levels?
Yes. Assign the same new label to several old levels and they collapse into one. For example, fct_recode(f, Big = "L", Big = "XL") merges L and XL into Big. If the levels to merge are defined by a rule or count rather than an explicit list, fct_collapse() or fct_lump() is a better fit.
How do I fix the "Unknown levels in f" warning?
That warning means a level you named on the right side of = does not exist in the factor. Run levels(f) to see the exact spelling, including capitalization, and correct your mapping. If you know the level is genuinely optional, wrap the call in suppressWarnings() to silence it deliberately.