[r] dplyr change many data types

I have a data.frame:

dat <- data.frame(fac1 = c(1, 2),
                  fac2 = c(4, 5),
                  fac3 = c(7, 8),
                  dbl1 = c('1', '2'),
                  dbl2 = c('4', '5'),
                  dbl3 = c('6', '7')
                  )

To change data types I can use something like

l1 <- c("fac1", "fac2", "fac3")
l2 <- c("dbl1", "dbl2", "dbl3")
dat[, l1] <- lapply(dat[, l1], factor)
dat[, l2] <- lapply(dat[, l2], as.numeric)

with dplyr

dat <- dat %>% mutate(
    fac1 = factor(fac1), fac2 = factor(fac2), fac3 = factor(fac3),
    dbl1 = as.numeric(dbl1), dbl2 = as.numeric(dbl2), dbl3 = as.numeric(dbl3)
)

is there a more elegant (shorter) way in dplyr?

thx Christof

This question is related to r dataframe dplyr

The answer is


It's a one-liner with mutate_at:

dat %>% mutate_at("l1", factor) %>% mutate_at("l2", as.numeric)

Or mayby even more simple with convert from hablar:

library(hablar)

dat %>% 
  convert(fct(fac1, fac2, fac3),
          num(dbl1, dbl2, dbl3))

or combines with tidyselect:

dat %>% 
  convert(fct(contains("fac")),
          num(contains("dbl")))

From the bottom of the ?mutate_each (at least in dplyr 0.5) it looks like that function, as in @docendo discimus's answer, will be deprecated and replaced with more flexible alternatives mutate_if, mutate_all, and mutate_at. The one most similar to what @hadley mentions in his comment is probably using mutate_at. Note the order of the arguments is reversed, compared to mutate_each, and vars() uses select() like semantics, which I interpret to mean the ?select_helpers functions.

dat %>% mutate_at(vars(starts_with("fac")),funs(factor)) %>%   
  mutate_at(vars(starts_with("dbl")),funs(as.numeric))

But mutate_at can take column numbers instead of a vars() argument, and after reading through this page, and looking at the alternatives, I ended up using mutate_at but with grep to capture many different kinds of column names at once (unless you always have such obvious column names!)

dat %>% mutate_at(grep("^(fac|fctr|fckr)",colnames(.)),funs(factor)) %>%
  mutate_at(grep("^(dbl|num|qty)",colnames(.)),funs(as.numeric))

I was pretty excited about figuring out mutate_at + grep, because now one line can work on lots of columns.

EDIT - now I see matches() in among the select_helpers, which handles regex, so now I like this.

dat %>% mutate_at(vars(matches("fac|fctr|fckr")),funs(factor)) %>%
  mutate_at(vars(matches("dbl|num|qty")),funs(as.numeric))

Another generally-related comment - if you have all your date columns with matchable names, and consistent formats, this is powerful. In my case, this turns all my YYYYMMDD columns, which were read as numbers, into dates.

  mutate_at(vars(matches("_DT$")),funs(as.Date(as.character(.),format="%Y%m%d")))

Dplyr across function has superseded _if, _at, and _all. See vignette("colwise").

dat %>% 
mutate(across(all_of(l1), as.factor),
       across(all_of(l2), as.numeric))

A more general way of achieving column type transformation is as follows:

If you want to transform all your factor columns to character columns, e.g., this can be done using one pipe:

df %>%  mutate_each_( funs(as.character(.)), names( .[,sapply(., is.factor)] ))

Since Nick's answer is deprecated by now and Rafael's comment is really useful, I want to add this as an Answer. If you want to change all factor columns to character use mutate_if:

dat %>% mutate_if(is.factor, as.character)

Also other functions are allowed. I for instance used iconv to change the encoding of all character columns:

dat %>% mutate_if(is.character, function(x){iconv(x, to = "ASCII//TRANSLIT")})

or to substitute all NA by 0 in numeric columns:

dat %>% mutate_if(is.numeric, function(x){ifelse(is.na(x), 0, x)})

Examples related to r

How to get AIC from Conway–Maxwell-Poisson regression via COM-poisson package in R? R : how to simply repeat a command? session not created: This version of ChromeDriver only supports Chrome version 74 error with ChromeDriver Chrome using Selenium How to show code but hide output in RMarkdown? remove kernel on jupyter notebook Function to calculate R2 (R-squared) in R Center Plot title in ggplot2 R ggplot2: stat_count() must not be used with a y aesthetic error in Bar graph R multiple conditions in if statement What does "The following object is masked from 'package:xxx'" mean?

Examples related to dataframe

Trying to merge 2 dataframes but get ValueError How to show all of columns name on pandas dataframe? Python Pandas - Find difference between two data frames Pandas get the most frequent values of a column Display all dataframe columns in a Jupyter Python Notebook How to convert column with string type to int form in pyspark data frame? Display/Print one column from a DataFrame of Series in Pandas Binning column with python pandas Selection with .loc in python Set value to an entire column of a pandas dataframe

Examples related to dplyr

R dplyr: Drop multiple columns How to specify "does not contain" in dplyr filter Select first and last row from grouped data Error: could not find function "%>%" Sum across multiple columns with dplyr Removing NA observations with dplyr::filter() Changing factor levels with dplyr mutate Change value of variable with dplyr dplyr change many data types What does %>% function mean in R?