Replace contents of factor column in R dataframe

R

R Problem Overview


I need to replace the levels of a factor column in a dataframe. Using the iris dataset as an example, how would I replace any cells which contain virginica with setosa in the Species column?

I expected the following to work, but it generates a warning message and simply inserts NAs:

iris$Species[iris$Species == 'virginica'] <- 'setosa'

R Solutions


Solution 1 - R

I bet the problem is when you are trying to replace values with a new one, one that is not currently part of the existing factor's levels:

levels(iris$Species)
# [1] "setosa"     "versicolor" "virginica" 

Your example was bad, this works:

iris$Species[iris$Species == 'virginica'] <- 'setosa'

This is what more likely creates the problem you were seeing with your own data:

iris$Species[iris$Species == 'virginica'] <- 'new.species'
# Warning message:
# In `[<-.factor`(`*tmp*`, iris$Species == "virginica", value = c(1L,  :
#   invalid factor level, NAs generated

It will work if you first increase your factor levels:

levels(iris$Species) <- c(levels(iris$Species), "new.species")
iris$Species[iris$Species == 'virginica'] <- 'new.species'

If you want to replace "species A" with "species B" you'd be better off with

levels(iris$Species)[match("oldspecies",levels(iris$Species))] <- "newspecies"

Solution 2 - R

For the things that you are suggesting you can just change the levels using the levels:

levels(iris$Species)[3] <- 'new'

Solution 3 - R

You can use the function revalue from the package plyr to replace values in a factor vector.

In your example to replace the factor virginica by setosa:

 data(iris)
 library(plyr)
 revalue(iris$Species, c("virginica" = "setosa")) -> iris$Species

Solution 4 - R

I had the same problem. This worked better:

Identify which level you want to modify: levels(iris$Species)

    "setosa" "versicolor" "virginica" 

So, setosa is the first.

Then, write this:

     levels(iris$Species)[1] <-"new name"

Solution 5 - R

A more general solution that works with all the data frame at once and where you don't have to add new factors levels is:

data.mtx <- as.matrix(data.df)
data.mtx[which(data.mtx == "old.value.to.replace")] <- "new.value"
data.df <- as.data.frame(data.mtx)

A nice feature of this code is that you can assign as many values as you have in your original data frame at once, not only one "new.value", and the new values can be random values. Thus you can create a complete new random data frame with the same size as the original.

Solution 6 - R

Using dlpyr::mutate and forcats::fct_recode:

library(dplyr)
library(forcats)

iris <- iris %>%  
  mutate(Species = fct_recode(Species,
    "Virginica" = "virginica",
    "Versicolor" = "versicolor"
  )) 

iris %>% 
  count(Species)

# A tibble: 3 x 2
     Species     n
      <fctr> <int>
1     setosa    50
2 Versicolor    50
3  Virginica    50   

Solution 7 - R

You want to replace the values in a dataset column, but you're getting an error like this:

> invalid factor level, NA generated

Try this instead:

levels(dataframe$column)[levels(dataframe$column)=='old_value'] <- 'new_value'

Solution 8 - R

In case you have to replace multiple values and if you don't mind "refactoring" your variable with as.factor(as.character(...)) you could try the following:

replace.values <- function(search, replace, x){
  stopifnot(length(search) == length(replace))
  xnew <- replace[ match(x, search) ]
  takeOld <- is.na(xnew) & !is.na(x)
  xnew[takeOld] <- x[takeOld]
  return(xnew)
}

iris$Species <- as.factor(search=c("oldValue1","oldValue2"),
                          replace=c("newValue1","newValue2"),
                          x=as.character(iris$Species))

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionlucianoView Question on Stackoverflow
Solution 1 - RflodelView Answer on Stackoverflow
Solution 2 - RGreg SnowView Answer on Stackoverflow
Solution 3 - RnebiView Answer on Stackoverflow
Solution 4 - RPriHohView Answer on Stackoverflow
Solution 5 - RalejandroView Answer on Stackoverflow
Solution 6 - RsbhaView Answer on Stackoverflow
Solution 7 - RJColaresView Answer on Stackoverflow
Solution 8 - RDaniel HoopView Answer on Stackoverflow