Skip to content

R - Factors

Factors are a special data type in R used to handle categorical data. They are essential for statistical modeling and data visualization, as they allow you to define a fixed set of categories, known as levels. Factors can be created from both character and integer vectors and are particularly useful for columns with a limited number of unique values, such as "Male"/"Female", or "Low"/"Medium"/"High".

Factors are created using the factor() function, which takes a vector as its primary input. Understanding factors is crucial for both base R and modern data analysis workflows.

Important Note on Modern R: Since R version 4.0.0 (released in 2020), the default behavior of functions like data.frame() and read.csv() has changed. They no longer automatically convert character vectors into factors. The old default was stringsAsFactors = TRUE, but the new default is stringsAsFactors = FALSE. This means you now usually need to create factors explicitly, which gives you more control over your data.

Let’s create a factor from a character vector. Notice how the output displays the original data along with the unique Levels.

# Create a character vector
directions <- c("East", "West", "East", "North", "North", "East", "West")
# Check its class and if it's a factor
print(directions)
cat("Is it a factor? ", is.factor(directions), "\n")
# Apply the factor() function to convert it
factor_directions <- factor(directions)
# Check the result
print(factor_directions)
cat("Is it a factor now? ", is.factor(factor_directions), "\n")

When you run the code above, you get the following output:

[1] "East" "West" "East" "North" "North" "East" "West"
Is it a factor? FALSE
[1] East West East North North East West
Levels: East North West
Is it a factor now? TRUE

As mentioned, modern R does not automatically create factors from strings. Let’s see this in action and then explicitly convert the column.

# Create vectors for our data frame
height <- c(132, 151, 162, 139, 166, 147, 122)
weight <- c(48, 49, 66, 53, 67, 52, 40)
gender <- c("male", "male", "female", "female", "male", "female", "male")
# Create the data frame
employee_data <- data.frame(height, weight, gender)
print(employee_data)
# Test if the gender column is a factor (it won't be by default)
cat("Is 'gender' a factor by default? ", is.factor(employee_data$gender), "\n")
cat("What is the class of 'gender'? ", class(employee_data$gender), "\n\n")
# Now, let's convert it to a factor
employee_data$gender <- factor(employee_data$gender)
# Check again
cat("Is 'gender' a factor now? ", is.factor(employee_data$gender), "\n")
# Print the gender column to see the levels
print(employee_data$gender)

Executing this code demonstrates the modern workflow:

height weight gender
1 132 48 male
2 151 49 male
3 162 66 female
4 139 53 female
5 166 67 male
6 147 52 female
7 122 40 male
Is 'gender' a factor by default? FALSE
What is the class of 'gender'? character
Is 'gender' a factor now? TRUE
[1] male male female female male female male
Levels: female male

The order of levels in a factor defaults to alphabetical. You can change this order, which is very important for visualizations and modeling (e.g., setting a baseline category).

You can re-apply the factor() function with the levels argument to specify the desired order.

# Our original factor from before
directions <- c("East", "West", "East", "North")
factor_directions <- factor(directions)
cat("Original Factor Levels:\n")
print(factor_directions)
# Reorder the levels
ordered_factor <- factor(factor_directions, levels = c("North", "East", "West"))
cat("\nReordered Factor Levels:\n")
print(ordered_factor)

The output shows the new level ordering:

Original Factor Levels:
[1] East West East North
Levels: East North West
Reordered Factor Levels:
[1] East West East North
Levels: North East West

The forcats package (part of the tidyverse) provides a suite of intuitive functions for working with factors. The fct_relevel() function is excellent for reordering.

# First, ensure you have tidyverse installed: install.packages("tidyverse")
library(forcats)
# Using the same factor
factor_directions <- factor(c("East", "West", "East", "North"))
# Use fct_relevel to bring "North" to the front
forcats_reordered <- fct_relevel(factor_directions, "North")
cat("Reordered with forcats:\n")
print(forcats_reordered)
# You can specify the full order as well
forcats_reordered_full <- fct_relevel(factor_directions, "North", "East", "West")
print(levels(forcats_reordered_full))

The forcats approach is often more readable and powerful for complex manipulations.

Reordered with forcats:
[1] East West East North
Levels: North East West
[1] "North" "East" "West"

The gl() function (Generate Levels) is a handy tool for creating balanced, repetitive factor structures, often used in designing experiments or creating sample data.

gl(n, k, labels)
  • n: an integer specifying the number of levels.
  • k: an integer specifying the number of replications for each level.
  • labels: a character vector providing labels for the factor levels.

Let’s generate a factor with 3 levels, each repeated 4 times.

v <- gl(3, 4, labels = c("Tampa", "Seattle", "Boston"))
print(v)

The output clearly shows the generated factor:

[1] Tampa Tampa Tampa Tampa Seattle Seattle Seattle Seattle Boston Boston Boston Boston
Levels: Tampa Seattle Boston