37
votes

Consider a data.frame with a mix of data types.

For a weird purpose, a user needs to convert all columns to characters. How is it best done? A tidyverse attempt at solution is this:

map(mtcars,as.character) %>% map_df(as.list) %>% View()
c2<-map(mtcars,as.character) %>% map_df(as.list)

when I call str(c2) it should say a tibble or data.frame with all characters.

The other option would be some parameter settings for write.csv() or in write_csv() to achieve the same thing in the resulting file output.

5

5 Answers

67
votes

EDIT: 2021-03-01

Beginning with dplyr 1.0.0, the _all() function variants are superceded. The new way to accomplish this is using the new across() function.

library(dplyr)
mtcars %>%
  mutate(across(everything(), as.character))

With across(), we choose the set of columns we want to modify using tidyselect helpers (here we use everything() to choose all columns), and then specify the function we want to apply to each of the selected columns. In this case, that is as.character().

Original answer:

You can also use dplyr::mutate_all.

library(dplyr)
mtcars %>%
  mutate_all(as.character)
25
votes

In base R:

x[] <- lapply(x, as.character)

This converts the columns to character class in place, retaining the data.frame's attributes. A call to data.frame() would cause them to be lost.

Attribute preservation using dplyr: Attributes seem to be preserved during dplyr::mutate(across(everything(), as.character)). Previously they were destroyed by dplyr::mutate_all.

Example

x <- mtcars
attr(x, "example") <- "1"

In the second case below, the example attribute is retained:

# Destroys attributes

data.frame(lapply(x, as.character)) %>%
  attributes()

# Preserves attributes

x[] <- lapply(x, as.character)
attributes(x)
4
votes

This might work, but not sure if it's the best.

df = data.frame(lapply(mtcars, as.character))
str(df)
3
votes

Most efficient way using data.table-

data.table::setDT(mtcars)
mtcars[, (colnames(mtcars)) := lapply(.SD, as.character), .SDcols = colnames(mtcars)]

Note: You can use this to convert few columns of a data table to your desired column type.

If we want to convert all columns to character then we can also do something like this-

to_col_type <- function(col_names,type){
            get(paste0("as.", type))(dt[[col_names]])
            }
mtcars<- rbindlist(list(Map(to_col_type ,colnames(mtcars),"character")))
1
votes

mutate_all in the accepted answer is superseded.

You can use mutate() function with across():

library(dplyr)

mtcars %>% 
  mutate(across(everything(), as.character))