在函数中使用 do.call() 更正 R map() 函数的参数规范

问题描述 投票:0回答:1

我一直在学习在线课程,并且参加了一个涉及使用 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 参数,被调用函数应该处理每一行。显然它没有,所以有些东西我没有看到。

建议?

r dictionary purrr rlang do.call
1个回答
0
投票

使用

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"))
© www.soinside.com 2019 - 2024. All rights reserved.