我一直在学习在线课程,并且参加了一个涉及使用 rlang 函数生成所需输出的练习。建议的解决方案涉及使用 for() 循环,但由于课程的早期部分涉及 purrr 和 map(),因此诉诸 for() 循环似乎是倒退了一步。
我有这样的小标题:(命名为“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
我写了这个函数:
demo_1 <- function(func_name, arg_list){
do.call(func_name, arg_list)
}
如果我这样调用函数:
demo_1(arguments$fname[[1]], as.list(strsplit(arguments$.args[[1]],",")))
我得到了预期的输出: [1] -0.4454785 0.6222901 -1.3134630
我一直在努力将这些提供给 map() 一个星期,但无法解决。 我如何将它们传递给 map() 以逐行处理整个 tibble?
谢谢。
感谢 akrun 的努力,但您的代码虽然有效,但并不是我希望实现的目标。
我正在寻找一个函数,它将函数名称作为字符串,将参数作为字符串,然后在函数内部将函数名称转换为实际的函数对象,并将参数字符串转换为一组参数,如 .参数列。最后使用类似 do.call() 的方法返回函数生成的值。
例如:
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)
}
创建后,我希望使用地图系列的某些变体将数据框的每一行传递给该函数。
我越来越近了,但我仍然需要一些帮助。这个功能几乎就在那里,但我不知道如何 map() 它或如何更改它以使其“可映射”。感激地收到进一步的建议:
demo_3 <- function(.row, .data){
x <- get(.data$fname[[.row]])
y <- parse_exprs(.data$.args[[.row]])
do.call(x,y)
}
这是我的最新迭代:
demo_4 <- function(.fname, .args){
x <- get(.fname)
y <- parse_exprs(.args)
do.call(x,y)
}
当使用两个字符串参数调用时:
> 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
当参考 arguments tibble 调用时: (我已经将 arguments$.args 列更改为使用分号分隔符而不是逗号分隔符。)
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
当使用 pmap() 调用时,其目的是处理 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.
不明白运行时显示的错误信息
rlang::last_error()
pmap() 是不是用错了函数? pmap() 的帮助告诉我,如果我使用数据框作为 .l 参数,被调用函数应该处理每一行。显然它没有,所以有些东西我没有看到。
建议?
使用
rowwise
library(dplyr)
arguments %>%
rowwise %>%
mutate(new = list(demo_1(fname, as.list(strsplit(.args,","))))) %>%
ungroup
-输出
# A tibble: 15 × 3
fname .args new
<chr> <chr> <list>
1 rnorm n=10,mean=0,sd=3 <dbl [3]>
2 rnorm n=100,mean=0,sd=3 <dbl [3]>
3 rnorm n=1000,mean=0,sd=3 <dbl [3]>
4 rnorm n=10000,mean=0,sd=3 <dbl [3]>
5 rnorm n=100000,mean=0,sd=3 <dbl [3]>
6 runif n=10,min=0,max=10 <dbl [3]>
7 runif n=100,min=0,max=10 <dbl [3]>
8 runif n=1000,min=0,max=10 <dbl [3]>
9 runif n=10000,min=0,max=10 <dbl [3]>
10 runif n=100000,min=0,max=10 <dbl [3]>
11 rexp n=10,rate=2 <dbl [2]>
12 rexp n=100,rate=2 <dbl [2]>
13 rexp n=1000,rate=2 <dbl [2]>
14 rexp n=10000,rate=2 <dbl [2]>
15 rexp n=100000,rate=2 <dbl [2]>
通过仔细查看 OP 的函数参数,输出不正确。即对于第一行,它应该返回 10 个观察值作为
n = 10
(仅显示前 2 行的输出,因为 n
值在其他行中很大)
library(purrr)
arguments %>%
slice(1:2) %>%
mutate(new = pmap(pick(everything()),
~ eval(rlang::parse_expr(sprintf('%s(%s)', ..1, ..2))))) %>%
as_tibble
-输出
# A tibble: 2 × 3
fname .args new
<chr> <chr> <list>
1 rnorm n=10,mean=0,sd=3 <dbl [10]>
2 rnorm n=100,mean=0,sd=3 <dbl [100]>
或不使用
eval/parse
library(tidyr)
arguments %>%
mutate(rn = row_number()) %>%
slice(1:2) %>%
separate_longer_delim(`.args`, delim=",") %>%
separate_wider_delim(`.args`, names = c("arg_name", "value"), delim = "=") %>%
type.convert(as.is = TRUE) %>%
reframe(fname = first(fname),
value = list(as.list(setNames(value, arg_name))), .by = 'rn') %>%
rowwise %>%
mutate(new = list(demo_1(fname, value))) %>%
ungroup
-输出
# A tibble: 2 × 4
rn fname value new
<int> <chr> <list> <list>
1 1 rnorm <named list [3]> <dbl [10]>
2 2 rnorm <named list [3]> <dbl [100]>
arguments <- structure(list(fname = c("rnorm", "rnorm", "rnorm", "rnorm",
"rnorm", "runif", "runif", "runif", "runif", "runif", "rexp",
"rexp", "rexp", "rexp", "rexp"), .args = c("n=10,mean=0,sd=3",
"n=100,mean=0,sd=3", "n=1000,mean=0,sd=3", "n=10000,mean=0,sd=3",
"n=100000,mean=0,sd=3", "n=10,min=0,max=10", "n=100,min=0,max=10",
"n=1000,min=0,max=10", "n=10000,min=0,max=10", "n=100000,min=0,max=10",
"n=10,rate=2", "n=100,rate=2", "n=1000,rate=2", "n=10000,rate=2",
"n=100000,rate=2")), class = "data.frame", row.names = c("1",
"2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13",
"14", "15"))