I have a csv that defines one row per variable (referring to real data variables that are defined in another dataset). After light massaging, I have a named vector like fxs
.
I then can iterate over the variables, and execute the appropriate function. Is there another way I should consider? Perhaps with rlang::exec()
and/or purrr::map_*()
. I like that I can wrap the two main lines with separate tryCatch()
blocks to more accurately describe if there was an error parsing the function, or an error executing the function.
fxs <- c(
"Sepal.Length" = "\\(x) x * 1",
"Sepal.Width" = "\\(x) x * 10",
"Petal.Length" = "\\(x) x * 100"
)
d <- iris[1:5, 1:3]
for (variable in colnames(d)) {
fx <- base::eval(base::parse(text = fxs[[variable]]))
d[[variable]] <- fx(d[[variable]])
}
d
I was thinking it looks a lot like the inside of a dplyr::mutate()
statement. Maybe it's better to try to convert the csv into statements passed to ...
. I haven't done anything beyond this proof-of-concept, so I have a lot of flexibility if someone has a different approach.
d |>
dplyr::mutate(
Sepal.Length = Sepal.Length * 1,
Sepal.Width = Sepal.Width * 10,
Petal.Length = Petal.Length * 100,
)
Desired output:
Sepal.Length Sepal.Width Petal.Length
1 5.1 35 140
2 4.9 30 140
3 4.7 32 130
4 4.6 31 150
5 5.0 36 140
CodePudding user response:
We may use cur_column()
to subset the expression within across
library(dplyr)
d %>%
dplyr::mutate(
dplyr::across(
.cols = dplyr::all_of(names(fxs)),
.fns = ~ eval(parse(text = fxs[[dplyr::cur_column()]]))(.x)
)
)
-output
Sepal.Length Sepal.Width Petal.Length
1 5.1 35 140
2 4.9 30 140
3 4.7 32 130
4 4.6 31 150
5 5.0 36 140
Or using exec
library(purrr)
d %>%
dplyr::mutate(
dplyr::across(
.cols = dplyr::all_of(names(fxs)),
.fns = ~ rlang::exec(
rlang::parse_expr(fxs[[dplyr::cur_column()]]),
.x
)
)
)
If the functions are all doing the multiplication, instead create a named vector
or list
of values to be multiplied and avoid the eval/parse
nm1 <- c(Sepal.Length = 1, Sepal.Width = 10, Petal.Length = 100)
d %>%
dplyr::mutate(
dplyr::across(
.cols = dplyr::all_of(names(nm1)),
.fns = ~ nm1[dplyr::cur_column()] * .x
)
)