Creating a Function in R with Variable Number of Arguments,

Creating a function in R with variable number of arguments,

d <- function(...){
x <- list(...) # THIS WILL BE A LIST STORING EVERYTHING:
sum(...) # Example of inbuilt function
}

d(1,2,3,4,5)

[1] 15

Passing variable number of arguments to R function

We can use do.call. args is a vector, do.call needs a list of arguments, we can convert args to list using as.list.

do.call(test, as.list(args))
#[1] 4

Creating a variable number of arguments, function

So from what I've gathered, you want to have a list with x dataframes and find the maximum value of all observations and all variables in each dataframe.
Why don't you do the following:

# Create list with 10 dataframes
df_list <- list()
for (i in 1:10) {
df_list[[i]] <- data.frame(matrix(rnorm(100), ncol = 10))
colnames(df_list[[i]]) <- LETTERS[1:10]
}

# Find maximum value of all data.frames
sapply(df_list, FUN = max)

This creates a list with 10 dataframes, each with 10 observations and 10 variables. Then it loops over every data.frame to obtain the maximum value of each of those. At the end, a vector with the maximum values is returned.

How to provide dynamic number of arguments to a function inside a function in R?

If the change the apply to do.call, it would work as expected. Note that apply with MARGIN = 2, loop over the columns of 'df' individually, whereas the 'f1' needs the values of all those available columns (or else use the default values) to calculate the ((a + b) * c)

f2 <- function(...){
arglist = list(...)
df = expand.grid(arglist)
do.call(f1, df)
}

and the f1

f1 <- function(a=1,b=1,c=2){
(a+b)*c

}

-testing

> f2(a = 10)
[1] 22
> f2(c = 10)
[1] 20
> f2(a = 5, c= c(5, 10))
[1] 30 60

Use variables as arguments in functions in R

Using the tidyverse:

stp_f<-function(ivar,idur,ie){
x <- mydata %>%
group_by(get(ivar)) %>%
summarise(
sumdur = sum(get(idur)),
sumev = sum(get(ie)),
failrate = sumev / sumdur
) %>%
rename(var = `get(ivar)`)

x
}

stp_f("sex","adur","ae")
stp_f("sex","bdur","be")
stp_f("sex","cdur","ce")

Outputs:

> stp_f("sex","adur","ae")
# A tibble: 2 x 4
var sumdur sumev failrate
<chr> <dbl> <dbl> <dbl>
1 female 6 2 0.333
2 male 80 3 0.0375

> stp_f("sex","bdur","be")
# A tibble: 2 x 4
var sumdur sumev failrate
<chr> <dbl> <dbl> <dbl>
1 female 61 1 0.0164
2 male 101 3 0.0297

> stp_f("sex","cdur","ce")
# A tibble: 2 x 4
var sumdur sumev failrate
<chr> <dbl> <dbl> <dbl>
1 female 60 1 0.0167
2 male 178 2 0.0112

How to write a function with an unspecified number of arguments where the arguments are column names

1) Wrap the code in eval(substitute(...code...)) like this:

example.fun <- function(data, ...) {
eval(substitute(within(data, pasted <- paste(...))))
}

# test
df <- data.frame(x = c(1, 2), y = c("a", "b"))
example.fun(df, x, y)
## x y pasted
## 1 1 a 1 a
## 2 2 b 2 b

1a) A variation of that would be:

example.fun.2 <- function(data, ...) {
data.frame(data, pasted = eval(substitute(paste(...)), data))
}
example.fun.2(df, x, y)

2) Another possibility is to convert each argument to a character string and then use indexing.

example.fun.3 <- function(data, ...) {
vnames <- sapply(substitute(list(...))[-1], deparse)
data.frame(data, pasted = do.call("paste", data[vnames]))
}
example.fun.3(df, x, y)

3) Other possibilities are to change the design of the function and pass the variable names as a formula or character vector.

example.fun.4 <- function(data, formula) {
data.frame(data, pasted = do.call("paste", get_all_vars(formula, data)))
}
example.fun.4(df, ~ x + y)

example.fun.5 <- function(data, vnames) {
data.frame(data, pasted = do.call("paste", data[vnames]))
}
example.fun.5(df, c("x", "y"))

How to obtain a variable number of arguments by ... or by a list in R

You can handle the direct input of data frames, both named and unnamed, like this:

helper_df_compare = function( ..., a_default_arg = "def" ){

dots <- rlang::list2(...)
args <- as.list(match.call())[-1]
if(is.null(names(dots))) names(dots) <- rep('', length(dots))
for(i in seq_along(dots)) {
if(!nzchar(names(dots)[i])) names(dots)[i] <- as.character(args[[i]])
}


rbind(
do.call(janitor::compare_df_cols, c(dots, return = "mismatch")) %>%
mutate( column_name = paste("!!!", column_name) ),
do.call(janitor::compare_df_cols, c(dots, return = "match"))
) %>%
mutate_all( ~str_replace_all(.,c(
"integer"="int", "numeric"="num", "character"="chr", "factor"="fct",
"POSIXct, POSIXt"="POSIXct"
) ) )
}

This allows

helper_df_compare(people, people2, people3)
#> column_name people people2 people3
#> 1 !!! age int num int
#> 2 height num num num
#> 3 lastnames chr chr chr
#> 4 names chr chr chr

and this:

helper_df_compare(A = people, B = people2, C = people3)
#> column_name A B C
#> 1 !!! age int num int
#> 2 height num num num
#> 3 lastnames chr chr chr
#> 4 names chr chr chr


Related Topics



Leave a reply



Submit