Purrr:: Map function to create columns and assign names stored in a vector

Hello,
I would like to use the map function from the purrr package to add columns with specific names defined in a vector.
I have found a workaround with a for loop but I'd like to to use the purrr package instead
Thank you for your help

library(glue)

names_col<-c("A","B","C")
df<-data.frame() # create a dataframe 

# For each name create a column

for (n in names_col){
  df$col<-numeric() 
  names(df)[names(df) == "col"] <- glue("{n}") 
}


colnames(df)
#> [1] "A" "B" "C"

Created on 2023-04-26 with reprex v2.0.2

Here's an alternative to {purrr} and for() to create an empty data frame with variable names defined from a character vector. It exploits the ability to create a matrix without column names.

make_df <- function(x){
  d = data.frame(matrix(ncol = length(x)))
  colnames(d) = x
  return(d[-1,])
}

names_col <- c("A", "B", "C")

make_df(names_col)
#> [1] A B C
#> <0 rows> (or 0-length row.names)

Created on 2023-04-26 with reprex v2.0.2

Hi Angela,

Given that map() process each iteration parallelly(i.e. applying same treatment to each element you want to iterate), and not passing result from one iter to the next, it is not easy to achieve such goal, adding columns, with map. It is applicable when generating a data frame:

> vec <- letters[1:3] 
> vec
[1] "a" "b" "c"
> df <- vec %>% map_dfc(~{list(NA) %>% set_names(.x)})
> df 
# A tibble: 1 × 3
  a     b     c    
  <lgl> <lgl> <lgl>
1 NA    NA    NA   

As to adding columns, I think making good use of bind_cols() is well-enough.

> bind_cols(mtcars, df)
                     mpg cyl  disp  hp drat    wt  qsec vs am gear carb  a  b  c
Mazda RX4           21.0   6 160.0 110 3.90 2.620 16.46  0  1    4    4 NA NA NA
Mazda RX4 Wag       21.0   6 160.0 110 3.90 2.875 17.02  0  1    4    4 NA NA NA
Datsun 710          22.8   4 108.0  93 3.85 2.320 18.61  1  1    4    1 NA NA NA
Hornet 4 Drive      21.4   6 258.0 110 3.08 3.215 19.44  1  0    3    1 NA NA NA

Creating the df from a vector without a loop is more recommended:

> named_vec <- set_names(vec, vec)
> data.frame(as.list(named_vec))
  a b c
1 a b c

if you want the df be empty, try

> named_vec_na <- set_names(rep(NA, length(vec)), vec)
> data.frame(as.list(named_vec_na))
   a  b  c
1 NA NA NA

Or you can just creating a tibble-data.frame with the bang-bang-bang syntax in R, it is a little bit tricky.

> tibble(!!!named_vec_na)
# A tibble: 1 × 3
  a     b     c    
  <lgl> <lgl> <lgl>
1 NA    NA    NA  

The above code equals

tibble(
  "{names(named_vec_na)[1]}" := named_vec_na[1],
  "{names(named_vec_na)[2]}" := named_vec_na[2],
  "{names(named_vec_na)[3]}" := named_vec_na[3]
)

Same skill can also applied to mutate a data frame

> mtcars %>% mutate(!!!named_vec_na) 
                     mpg cyl  disp  hp drat    wt  qsec vs am gear carb  a  b  c
Mazda RX4           21.0   6 160.0 110 3.90 2.620 16.46  0  1    4    4 NA NA NA
Mazda RX4 Wag       21.0   6 160.0 110 3.90 2.875 17.02  0  1    4    4 NA NA NA
Datsun 710          22.8   4 108.0  93 3.85 2.320 18.61  1  1    4    1 NA NA NA
Hornet 4 Drive      21.4   6 258.0 110 3.08 3.215 19.44  1  0    3    1 NA NA NA
Hornet Sportabout   18.7   8 360.0 175 3.15 3.440 17.02  0  0    3    2 NA NA NA
Valiant             18.1   6 225.0 105 2.76 3.460 20.22  1  0    3    1 NA NA NA

When discarding the intermediate variables, code can be simple as

> tibble(!!!set_names(rep(NA, length(vec)), vec))

> mtcars %>% mutate(!!!set_names(rep(NA, length(vec)), vec))

This topic was automatically closed 21 days after the last reply. New replies are no longer allowed.

If you have a query related to it or one of the replies, start a new topic and refer back with a link.