简体   繁体   中英

passing ellipsis arguments to map function purrr package, R

I want to use ellipsis parameters inside map function of purrr package. this is a toy example:

f1<-function(x,a=NA,b=NA,prs=seq(0, 1, 0.25),SW=T){
  if(SW){
    res<-data.frame(name1=a,name2=b,t(quantile(x, prs, na.rm = T)),  mean=mean(x, na.rm = T), sd=sd(x, na.rm = T),
                    NAs=length(x[is.na(x)]),n=length(x[!is.na(x)]),SWp=shapiro.test(x)$p.value,stringsAsFactors =F)
  }else
  {
    res<-data.frame(name1=a,name2=b,t(quantile(x, prs, na.rm = T)),  mean=mean(x, na.rm = T), sd=sd(x, na.rm = T),
                    NAs=length(x[is.na(x)]),n=length(x[!is.na(x)]),stringsAsFactors =F)
  }
return(res)
}

f1(c(NA,rnorm(25),NA),SW=F)
f1(c(NA,rnorm(25),NA))

now I want to use f1 inside another function f2:

f2<-function(df,...){
  res<-map_df(colnames(df),~f1(df[,.],a=.,...))
  return(res)
}

where ... is intended mainly to manipulate SW and a or b parameters in f1 function. however f2 is not doing what I want as can be seen here

f2(iris[,-5])
f2(iris[,-5],SW=F)

I appreciate any guide in how to use addecuatelly ... inside map

You just need to pass the ellipses through the map_df() call as well. Otherwise they can't get into the inner f1() call.

f2 <- function(df, ...){
  res <- map_df(colnames(df), ~f1(df[,.], a=., ...), ...)
  return(res)
}

You can also capture the ellipses early on in your second function, and use do.call to add them to your first function later on. This makes it more explicit where and how they are used.

f2 <- function(df, ...){
  params <- list(...)
  res <- map_df(colnames(df), ~ do.call(
    f1, c(list(x = df[,.], a=.), params)))
  return(res)
}

MrFlick solution did not work for me: I think indeed you also need to pass the ... to the anonymous function, which then requires using function(x,...) instead of ~ (as suggested by @dmi3kno).

That means you need the quite surprising triple ... call:

map(x, function(x, ...) mean(x, trim=0, ...), ...)

Example:

library(purrr)
x <- list(c(1,2), c(1,2,NA))
fo1 <- function(...) map(x, ~mean(., trim=0, ...), ...)
fo2 <- function(...) map(x, function(x, ...) mean(x, trim=0, ...), ...)

fo1()
#> Warning in if (na.rm) x <- x[!is.na(x)]: the condition has length > 1 and only
#> the first element will be used

#> Warning in if (na.rm) x <- x[!is.na(x)]: the condition has length > 1 and only
#> the first element will be used
#> [[1]]
#> [1] 1.5
#> 
#> [[2]]
#> [1] 1.5

fo2()
#> [[1]]
#> [1] 1.5
#> 
#> [[2]]
#> [1] NA
fo2(na.rm=TRUE)
#> [[1]]
#> [1] 1.5
#> 
#> [[2]]
#> [1] 1.5

Created on 2020-11-16 by the reprex package (v0.3.0)

For this issue, I've found that rlang::exec() allows you to pass ... to purrr::map() when combined with an anonymous function, like this:

f2 <- function(df, ...){
  res <- map(colnames(df), function(x) rlang::exec("f1", df[,x], ...))
  return(res)
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM