15.10 Changing the Names of Factor Levels

15.10.1 Problem

You want to change the names of levels in a factor.

15.10.2 Solution

Use fct_recode() from the forcats package

sizes <- factor(c( "small", "large", "large", "small", "medium"))
#> [1] small  large  large  small  medium
#> Levels: large medium small

# Pass it a named vector with the mappings
fct_recode(sizes, S = "small", M = "medium", L = "large")
#> [1] S L L S M
#> Levels: L M S

15.10.3 Discussion

If you want to use two vectors, one with the original levels and one with the new ones, use do.call() with fct_recode().

old <- c("small", "medium", "large")
new <- c("S", "M", "L")

# Create a named vector that has the mappings between old and new
mappings <- setNames(old, new)
#>        S        M        L 
#>  "small" "medium"  "large"

# Create a list of the arguments to pass to fct_recode
args <- c(list(sizes), mappings)

# Look at the structure of the list
#> List of 4
#>  $  : Factor w/ 3 levels "large","medium",..: 3 1 1 3 2
#>  $ S: chr "small"
#>  $ M: chr "medium"
#>  $ L: chr "large"

# Use do.call to call fct_recode with the arguments
do.call(fct_recode, args)
#> [1] S L L S M
#> Levels: L M S

Or, more concisely, we can do all of that in one go:

  c(list(sizes), setNames(c("small", "medium", "large"), c("S", "M", "L")))
#> [1] S L L S M
#> Levels: L M S

For a more traditional (and clunky) base R method for renaming factor levels, use the levels()<- function:

sizes <- factor(c( "small", "large", "large", "small", "medium"))

# Index into the levels and rename each one
levels(sizes)[levels(sizes) == "large"]  <- "L"
levels(sizes)[levels(sizes) == "medium"] <- "M"
levels(sizes)[levels(sizes) == "small"]  <- "S"
#> [1] S L L S M
#> Levels: L M S

If you are renaming all your factor levels, there is a simpler method. You can pass a list to levels()<-:

sizes <- factor(c("small", "large", "large", "small", "medium"))
levels(sizes) <- list(S = "small", M = "medium", L = "large")
#> [1] S L L S M
#> Levels: S M L

With this method, all factor levels must be specified in the list; if any are missing, they will be replaced with NA.

It’s also possible to rename factor levels by position, but this is somewhat inelegant:

sizes <- factor(c("small", "large", "large", "small", "medium"))
levels(sizes)[1] <- "L"
#> [1] small  L      L      small  medium
#> Levels: L medium small

# Rename all levels at once
levels(sizes) <- c("L", "M", "S")
#> [1] S L L S M
#> Levels: L M S

It’s safer to rename factor levels by name rather than by position, since you will be less likely to make a mistake (and mistakes here may be hard to detect). Also, if your input data set changes to have more or fewer levels, the numeric positions of the existing levels could change, which could cause serious but nonobvious problems for your analysis.

15.10.4 See Also

If, instead of a factor, you have a character vector with items to rename, see Recipe 15.12.