195

I would like to change the format (class) of some columns of my data.frame object (mydf) from charactor to factor.

I don't want to do this when I'm reading the text file by read.table() function.

Any help would be appreciated.

4
  • 19
    mydf$myfavoritecolumn <- as.factor(mydf$myfavoritecolumn) Commented Feb 12, 2012 at 18:21
  • Thanks! but I have another problem. I have the name of each column in an array of characters col_names[]. How can I use the above command (mydf$col_names[i]) doesn't work. Commented Feb 12, 2012 at 18:35
  • Any way to do this automatically for all character variables, as data.frame does it with stringsAsFactors? Commented Oct 25, 2012 at 15:21
  • @EtienneLow-Décarie: just unclass and use data.frame on the result,. Commented Aug 17, 2013 at 17:49

8 Answers 8

244

Hi welcome to the world of R.

mtcars  #look at this built in data set
str(mtcars) #allows you to see the classes of the variables (all numeric)

#one approach it to index with the $ sign and the as.factor function
mtcars$am <- as.factor(mtcars$am)
#another approach
mtcars[, 'cyl'] <- as.factor(mtcars[, 'cyl'])
str(mtcars)  # now look at the classes

This also works for character, dates, integers and other classes

Since you're new to R I'd suggest you have a look at these two websites:

R reference manuals: http://cran.r-project.org/manuals.html

R Reference card: http://cran.r-project.org/doc/contrib/Short-refcard.pdf

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks! but I have another problem. I have the name of each column in an array of characters col_names[]. How can I use the above command (neither mydf$col_names[i] nor mydf[,col_names[i]] doesn't work.)
@Rasoul, mydf[, col_names] will do this
+1 for the refs. This is basic stuff, which is OK to ask, but it's also fine to be aware of the extensive work that has been put into these (and similar) works.
105
# To do it for all names
df[] <- lapply( df, factor) # the "[]" keeps the dataframe structure

# to do it for some names in a vector named 'col_names'
col_names <- names(df)
df[col_names] <- lapply(df[col_names] , factor)

Explanation. All dataframes are lists and the results of [ used with multiple valued arguments are likewise lists, so looping over lists is the task of lapply. The above assignment will create a set of lists that the function data.frame.[<- should successfully stick back into into the dataframe, df

Another strategy would be to convert only those columns where the number of unique items is less than some criterion, let's say fewer than the log of the number of rows as an example:

cols.to.factor <- sapply( df, function(col) length(unique(col)) < log10(length(col)) )
df[ cols.to.factor] <- lapply(df[ cols.to.factor] , factor)

3 Comments

This is a very nice solution! It can also work with column numbers which might be especially useful if you wanted to change many but not all. E.g., col_nums <- c(1, 6, 7:9, 21:23, 27:28, 30:31, 39, 49:55, 57) then df[,col_nums] <- lapply(df[,col_nums] , factor).
Caveat: the first solution doesn't work if length(col_names)==1. In that case, df[,col_names] is automatically demoted to a vector instead of a list of length 1, and then lapply tries to operate over each entry rather than the column as a whole. This can be prevented by using df[,col_names,drop=FALSE].
That's a a good point. The other invocation that would retain the list status is to use df[col_names].
36

You could use dplyr::mutate_if() to convert all character columns or dplyr::mutate_at() for select named character columns to factors:

library(dplyr)

# all character columns to factor:
df <- mutate_if(df, is.character, as.factor)

# select character columns 'char1', 'char2', etc. to factor:
df <- mutate_at(df, vars(char1, char2), as.factor)

1 Comment

mutate_at is really fast when you have a lot of columns (~50000) and you only have to transform 3.
18

If you want to change all character variables in your data.frame to factors after you've already loaded your data, you can do it like this, to a data.frame called dat:

character_vars <- lapply(dat, class) == "character"
dat[, character_vars] <- lapply(dat[, character_vars], as.factor)

This creates a vector identifying which columns are of class character, then applies as.factor to those columns.

Sample data:

dat <- data.frame(var1 = c("a", "b"),
                  var2 = c("hi", "low"),
                  var3 = c(0, 0.1),
                  stringsAsFactors = FALSE
                  )

1 Comment

The complete conversion of every character variable to factor usually happens when reading in data, e.g., with stringsAsFactors = TRUE, but this is useful when say, you've read data in with read_excel() from the readxl package and want to train a random forest model that doesn't accept character variables.
14

Another short way you could use is a pipe (%<>%) from the magrittr package. It converts the character column mycolumn to a factor.

library(magrittr)

mydf$mycolumn %<>% factor

2 Comments

Please edit with more information. Code-only and "try this" answers are discouraged, because they contain no searchable content, and don't explain why someone should "try this". We make an effort here to be a resource for knowledge.
pls if I want t use it for all columns of my df ?
6

I've doing it with a function. In this case I will only transform character variables to factor:

for (i in 1:ncol(data)){
    if(is.character(data[,i])){
        data[,i]=factor(data[,i])
    }
}

1 Comment

I believe you need double brackets to actually extract the column and change it to a factor, e.g. [[i]]
4

Unless you need to identify the columns automatically, I found this to be the simplest solution:

df$name <- as.factor(df$name)

This makes column name in dataframe df a factor.

Comments

2

You can use across with new dplyr 1.0.0

library(dplyr)

df <- mtcars 
#To turn 1 column to factor
df <- df %>% mutate(cyl = factor(cyl))

#Turn columns to factor based on their type. 
df <- df %>% mutate(across(where(is.character), factor))

#Based on the position
df <- df %>% mutate(across(c(2, 4), factor))

#Change specific columns by their name
df <- df %>% mutate(across(c(cyl, am), factor))

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.