How to coerce multiple column classes?

Solution for How to coerce multiple column classes?
is Given Below:

I have a data frame and columns are different classes including strings, numeric, integer, etc.

I have a vector of classes class_vector <- c("string", "integer" ,"numeric" , "logical" ) that I need to use to coerce each column class to.

Sample data frame:

df <- data.frame(letters = letters[sample.int(20, 10)], integers = sample.int(100, 10), 
                 numbers = rnorm(10), logical = sample.int(2, 10, replace = T)-1)

I’ve tried different variations of the apply function, but I have only been successful at changing multiple column classes to one single class (eg. “character”), but I can’t seem to use a vector/list to change different columns to different classess.

You can use purrr:map2_dfc, after you change string to character as in Ronaks answer

library(purrr)

map2_dfc(df, class_vector, ~ {class(.x)<-.y; .x})

# A tibble: 10 x 4
   letters  integers numbers logical
   <string>    <int>   <dbl> <lgl>  
 1 d              97 -0.621  TRUE   
 2 g              85 -2.21   TRUE   
 3 a              21  1.12   TRUE   
 4 b              54 -0.0449 TRUE   
 5 m              74 -0.0162 FALSE  
 6 s               7  0.944  FALSE  
 7 k              73  0.821  TRUE   
 8 q              79  0.594  FALSE  
 9 n              99  0.919  TRUE   
10 c              37  0.782  TRUE   

Per @GuedesBF’s suggestion: use rlang to convert the strings into functions.
Use Ronak’s class_vector.

library(rlang)
library(purrr)

map2_df(df, class_vector, function(col, typ) as_function(paste0("as.", typ))(col))

Output:

   letters integers numbers logical
   <chr>      <int>   <dbl> <lgl>  
 1 s             11  -0.782 TRUE   
 2 o             77  -0.246 TRUE   
 3 t             92   0.101 FALSE  
 4 a             44  -0.596 TRUE   
 5 h             15   0.337 TRUE   
 6 i              8   0.692 FALSE  
 7 b             28   0.520 FALSE  
 8 p             82   0.263 FALSE  
 9 f             61   1.34  TRUE   
10 j             81  -1.47  TRUE  

We can use a simple for loop in base R

for(i in seq_along(df)) class(df[[i]]) <- class_vector[i]

-output

> str(df)
'data.frame':   10 obs. of  4 variables:
 $ letters : chr  "t" "c" "n" "f" ...
 $ integers: int  56 68 27 42 47 79 62 2 84 12
 $ numbers : num  1.039 -1.25 2.262 -1.516 -0.575 ...
 $ logical : logi  FALSE TRUE FALSE TRUE FALSE TRUE ...

Or with lapply in base R

df[] <- lapply(seq_along(df), function(i) `class<-`(df[[i]], class_vector[i]))
> str(df)
'data.frame':   10 obs. of  4 variables:
 $ letters : 'string' chr  "k" "d" "o" "h" ...
 $ integers: int  85 58 88 3 38 93 63 20 34 89
 $ numbers : num  -0.718 0.903 1.738 -0.345 1.021 ...
 $ logical : logi  FALSE FALSE TRUE FALSE FALSE TRUE ...

Or using dplyr with mutate and across

library(dplyr)
df %>%
     mutate(across(everything(), 
     ~ `class<-`(., class_vector[match(cur_column(), names(df))])))
   letters integers     numbers logical
1        q       49  0.93598772    TRUE
2        c       74  0.53479870    TRUE
3        p       54  0.57934890    TRUE
4        h       11  0.44393120   FALSE
5        j       95  1.46833083    TRUE
6        g       13 -1.82314003    TRUE
7        n       41 -0.89846695    TRUE
8        f       75 -0.40110724   FALSE
9        e       18 -0.48233063   FALSE
10       i       26 -0.05029243   FALSE

Or if the ‘class_vector’ is a named vector i.e. named as the column names of the dataset, this is more simpler

names(class_vector) <- names(df)
df %>%
     mutate(across(everything(),  
       ~ `class<-`(., class_vector[cur_column()])))

There is no 'string' class in R. After changing 'string' to 'character' you may use class function to change the class of each column acorrding to the vector.

class_vector <- c("character",  "integer" ,"numeric" , "logical" )
df[] <- Map(`class<-`, df, class_vector)

str(df)
#'data.frame':  10 obs. of  4 variables:
# $ letters : chr  "d" "b" "j" "n" ...
# $ integers: int  94 27 72 60 71 26 31 90 18 99
# $ numbers : num  0.7803 0.0959 0.2431 0.0372 0.4021 ...
# $ logical : logi  FALSE TRUE TRUE FALSE TRUE TRUE ...