I've been working a on-line course and I've come to an exercise involving using rlang functions to produce the desired output. The suggested solution involved using a for() loop, but since an earlier part of the course involved purrr and map(), it seemed like a step backward to resort to a for() loop.
I have a tibble like so: (named "arguments")
# A tibble: 15 × 2
fname .args
<chr> <chr>
1 rnorm n=10,mean=0,sd=3
2 rnorm n=100,mean=0,sd=3
3 rnorm n=1000,mean=0,sd=3
4 rnorm n=10000,mean=0,sd=3
5 rnorm n=100000,mean=0,sd=3
6 runif n=10,min=0,max=10
7 runif n=100,min=0,max=10
8 runif n=1000,min=0,max=10
9 runif n=10000,min=0,max=10
10 runif n=100000,min=0,max=10
11 rexp n=10,rate=2
12 rexp n=100,rate=2
13 rexp n=1000,rate=2
14 rexp n=10000,rate=2
15 rexp n=100000,rate=2
I wrote this function:
demo_1 <- function(func_name, arg_list){
do.call(func_name, arg_list)
}
If I call the function like so:
demo_1(arguments$fname[[1]], as.list(strsplit(arguments$.args[[1]],",")))
I get the expected output: [1] -0.4454785 0.6222901 -1.3134630
I've been struggling to feed these to map() for a week now, but can't work it out. How do I pass these to map() to process the entire tibble, row by row?
Thanks.
Thanks to akrun for your efforts, but your code, while it works, is not what I was hoping to achieve.
I was looking to write a function which takes the function name as a string and the arguments as a string, then inside the function turn the function name into an actual function object and the arguments string into a set of arguments as appear in the .args column. Finally use something like do.call() to return the values generated by the function.
For example:
demo_2 <- function(.fname, .fargs){
.... stuff I don't yet understand goes here
fname <- ensym(.fname)?, enquo(.fname)?
fargs <- ensym(.fargs)?, enquo(.fargs)?
do.call(fname, fargs)
}
Once that has been created I wished to use some variant of the map family to pass each row of the data frame to that function.
I'm getting closer, but I still need some help. This function is nearly there, but I don't know how to map() it or how to change it to make it "map-able". Further advice gratefully received:
demo_3 <- function(.row, .data){
x <- get(.data$fname[[.row]])
y <- parse_exprs(.data$.args[[.row]])
do.call(x,y)
}
Here is my latest iteration:
demo_4 <- function(.fname, .args){
x <- get(.fname)
y <- parse_exprs(.args)
do.call(x,y)
}
When called with two string arguments:
> demo_4("rnorm", "n=10;mean=0;sd=3")
[1] 0.4136818 1.3341674 2.1483943 -6.3195926 3.5595125 -0.9285594 -0.1743377 -0.7416142 -1.1671383 -2.6037147
When called with reference to the arguments tibble: (I've changed the arguments$.args column to use a semi-colon separator instead of a comma separator.)
demo_4(arguments$fname[1], arguments$.args[1])
[1] 4.1047325 1.4324751 -0.8754805 -0.4997726 -0.8513174 5.6490628 -2.7174594 4.4089390 0.1218752 -0.3962111
When calling with pmap() where the intention is to process each row in the tibble:
pmap(arguments, demo_4)
Error in `pmap()`:
ℹ In index: 1.
Caused by error in `.f()`:
! unused argument (fname = .l[[1]][[i]])
Run `rlang::last_error()` to see where the error occurred.
I don't understand the error message displayed when I run
rlang::last_error()
Is pmap() the wrong function to use? The help for pmap() tells me that if I use a data frame as the .l argument the called function should process each row. Plainly it doesn't so there's something I'm not seeing.
Suggestions?
Use
rowwise-output
Update
By looking closely at the OP's function arguments, the output is not correct. i.e. for the first row, it should return 10 observations as
n = 10(showing the output for only the first 2 rows asnvalues are large in other rows)-output
Or without using the
eval/parse-output
data