I'd like to use a "metadata" tibble to rename & recode another tibble. I've got the renaming piece, but I'm struggling to get mutate to apply a distinct function to each column. I'm guessing that across
will be involved, but not certain.
Here's a MRE:
library(tidyverse)
#Recode everything as a character.. just so we can change it back :)
bad <- iris %>%
as_tibble() %>%
mutate_all(as.character)
#Create a "metadata" tibble of what we want to rename/recode the columns as
meta <- tibble(
name = colnames(bad),
rename_as = c("s_l", "s_w", "p_l", "p_w", "spec"),
format_as = c(rep("as.numeric", 4), "as.character")
)
#Use the metadata tibble to rename/recode the bad tibble
bad %>%
#rename works fine
rename_all(~ meta$rename_as) %>%
#But how to specify which function applies to which column?
mutate(across(meta$rename_as, ~ meta$format_as))
Desired output:
'data.frame': 150 obs. of 5 variables:
$ s_l : num 5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
$ s_w : num 3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...
$ p_l : num 1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ...
$ p_w : num 0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ...
$ spec: chr "setosa" "setosa" "setosa" "setosa" ...
across()
, you can use cur_column()
to match meta$name
and find the corresponding format_as
.format_as
are character function names. do.call()
is used to trigger it off..names
in across()
is a glue specification that describes how to name the output columns. This can use {.col}
to stand for the selected column name. You can use it to achieve the renaming step.bad %>%
mutate(across(everything(), ~ do.call(meta$format_as[meta$name == cur_column()], list(.x)),
.names = "{meta$rename_as[meta$name == .col]}"),
.keep = "unused")
# # A tibble: 150 × 5
# s_l s_w p_l p_w spec
# <dbl> <dbl> <dbl> <dbl> <chr>
# 1 5.1 3.5 1.4 0.2 setosa
# 2 4.9 3 1.4 0.2 setosa
# 3 4.7 3.2 1.3 0.2 setosa
# 4 4.6 3.1 1.5 0.2 setosa
# 5 5 3.6 1.4 0.2 setosa
# 6 5.4 3.9 1.7 0.4 setosa
# 7 4.6 3.4 1.4 0.3 setosa
# 8 5 3.4 1.5 0.2 setosa
# 9 4.4 2.9 1.4 0.2 setosa
# 10 4.9 3.1 1.5 0.1 setosa
# ℹ 140 more rows
# ℹ Use `print(n = ...)` to see more rows
You can also create a named list of expressions to inject into the mutate
verb:
lexprs <- set_names(parse_exprs(glue_data(meta, "{format_as}({name})")), meta$rename_as)
bad |>
mutate(!!!lexprs, .keep = "unused")
> lexprs
$s_l
as.numeric(Sepal.Length)
$s_w
as.numeric(Sepal.Width)
$p_l
as.numeric(Petal.Length)
$p_w
as.numeric(Petal.Width)
$spec
as.character(Species)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With