Map readr::type_convert to specific columns only

446 Views Asked by At

readr::type_convert guesses the class of each column in a data frame. I would like to apply type_convert to only some columns in a data frame (to preserve other columns as character). MWE:

# A data frame with multiple character columns containing numbers.
df <- data.frame(A = letters[1:10],
                 B = as.character(1:10),
                 C = as.character(1:10))

# This works
df %>% type_convert()

Parsed with column specification:
cols(
  A = col_character(),
  B = col_double(),
  C = col_double()
)
   A  B  C
1  a  1  1
2  b  2  2
...

However, I would like to only apply the function to column B (this is a stylised example; there may be multiple columns to try and convert). I tried using purrr::map_at as well as sapply, as follows:

# This does not work
map_at(df, "B", type_convert)

Error in .f(.x[[i]], ...) : is.data.frame(df) is not TRUE

# This does not work
sapply(df["B"], type_convert)

Error in FUN(X[[i]], ...) : is.data.frame(df) is not TRUE

Is there a way to apply type_convert selectively to only some columns of a data frame?

Edit: @ekoam provides an answer for type_convert. However, applying this answer to many columns would be tedious. It might be better to use the base::type.convert function, which can be mapped:

purrr::map_at(df, "B", type.convert) %>%
   bind_cols()

# A tibble: 10 x 3
       A     B C    
   <chr> <int> <chr>
 1     a     1 1    
 2     b     2 2    
2

There are 2 best solutions below

3
On BEST ANSWER

Try this:

df %>% type_convert(cols(B = "?", C = "?", .default = "c"))

Guess the type of B; any other character column stays as is. The tricky part is that if any column is not of a character type, then type_convert will also leave it as is. So if you really have to type_convert, maybe you have to first convert all columns to characters.

0
On

type_convert does not seem to support it. One trick which I have used a few times is using combination of select & bind_cols as shown below.

df %>%
    select(B) %>% 
    type_convert() %>% 
    bind_cols(df %>% select(-B))