Using do.call to call a list of functions - r

I am having trouble figuring out how to use do.call to call and run a list of functions.
for example:
make.draw = function(i){i;function()runif(i)}
function.list = list()
for (i in 1:3) function.list[[i]] = make.draw(i)
will result in
> function.list[[1]]()
[1] 0.2996515
> function.list[[2]]()
[1] 0.7276203 0.4704813
> function.list[[3]]()
[1] 0.9092999 0.7307774 0.4647443
what I want to do is create a function that calls all three functions in the list at one go. from what I understand as.call() can be used to do this but I am having trouble connecting the dots and getting 6 uniform random draws from function.list.

Did you want something like this?
lapply(function.list, do.call, list())
# [[1]]
# [1] 0.5777857
# [[2]]
# [1] 0.8970102 0.5892031
# [[3]]
# [1] 0.4712016 0.2624851 0.2353192

make.draw = function(i){runif(i)}
Map(make.draw, 1:3)
#[[1]]
#[1] 0.03442084
#[[2]]
#[1] 0.6899443 0.8896434
#[[3]]
#[1] 0.3899678 0.2845898 0.4920698

Related

Capture and evaluate function arguments within function body

I would like to capture a function's arguments within its body to help with logging. I have found that match.call() and sys.call() work when the argument value is explicitly stated in the function call, but don't output an evaluated value when an object name is used.
Here's a simplified example:
gauss_vector <- function(number) {
sys_args <- as.list(sys.call())
match_args <- as.list(match.call())
output <- rnorm(n = number)
list(sys_args,
match_args,
output)
}
When this function is called like this:
gauss_vector(number = 5)
The resulting list includes the value 5.
[[1]]
[[1]][[1]]
gauss_vector
[[1]]$number
[1] 5
[[2]]
[[2]][[1]]
gauss_vector
[[2]]$number
[1] 5
[[3]]
[1] 0.9663434 0.8051087 0.1576298 0.3189806 -2.3110680
However, when the function is called like this:
n <- 5
gauss_vector(number = n)
The resulting list only includes n.
[[1]]
[[1]][[1]]
gauss_vector
[[1]]$number
n
[[2]]
[[2]][[1]]
gauss_vector
[[2]]$number
n
[[3]]
[1] -0.6017670 -0.7631405 0.7793892 -0.7529637 1.3022802
Is there a way to capture the evaluated figure rather than the object name when the function is called in the second way?
You could eval all the arguments passed to the function.
gauss_vector <- function(number) {
sys_args <- as.list(sys.call())
sys_args[-1] <- lapply(sys_args[-1], eval)
match_args <- as.list(match.call())
match_args[-1] <- lapply(match_args[-1], eval)
output <- rnorm(n = number)
list(sys_args,match_args,output)
}
gauss_vector(n)
#[[1]]
#[[1]][[1]]
#gauss_vector
#[[1]][[2]]
#[1] 5
#[[2]]
#[[2]][[1]]
#gauss_vector
#[[2]]$number
#[1] 5
#[[3]]
#[1] 0.6998265 0.4037748 1.8558809 -0.1343624 -1.5600925

R: Repeating elements of a list for usage in purrr::pmap()

This is just a "cosmetical" thing, but I just can't get it to work. :(
I have a nested list that I want to pass to pmap(). Some elements are repeated within the sublists. I'm looking for an elegant way to repeat elements multiple times within a sublist.
Simplified example with less elements:
arg_list <- list(url = x,
category = c("/activity",
"/current",
"/desktop",
"/login/user",
"/message",
"/forum"),
action = list(c("ACTIVITY_RESUME", "ACTIVITY_PAUSE"),
c("FRAGMENT_RESUME", "FRAGMENT_PAUSE"),
c("FRAGMENT_RESUME", "FRAGMENT_PAUSE"),
c("onResume", "onPause"),
c("onResume", "onPause"),
c("onResume", "onPause"))
get_durations <- function(x, category, action) { ... }
durations <- pmap(.l = arg_list, safely(get_durations))
For example, I want to repeat c("onResume", "onPause") three times, instead of typing it by hand.
I tried various variations of rep(list(c("onResume", "onPause")), times = 3) but I wasn't able to extract the elements as neccessary.
Thank you! :)
rep(list(c("onResume", "onPause")), times = 3) should work. What seems to be issue?
If you need to repeat different vectors a different number of times, you can use map2 (Note the usage of flatten to convert the final list-of-lists to a list of vectors):
map2( list(c("ACTIVITY_RESUME", "ACTIVITY_PAUSE"),
c("FRAGMENT_RESUME", "FRAGMENT_PAUSE"),
c("onResume", "onPause")),
1:3, ~rep(list(.x), .y) ) %>% purrr::flatten()
# [[1]]
# [1] "ACTIVITY_RESUME" "ACTIVITY_PAUSE"
#
# [[2]]
# [1] "FRAGMENT_RESUME" "FRAGMENT_PAUSE"
#
# [[3]]
# [1] "FRAGMENT_RESUME" "FRAGMENT_PAUSE"
#
# [[4]]
# [1] "onResume" "onPause"
#
# [[5]]
# [1] "onResume" "onPause"
#
# [[6]]
# [1] "onResume" "onPause"

R - Naming multiple functions in a for loop

I have the following data frame:
> coc_comp_model[1:3,]
Relationship Output Input |r-Value| Y-Intercept Gradient
1 DG-r ~ DG-cl DG-r DG-cl 0.8271167 0.0027217513 12.9901380
2 CA3-r ~ CA3-cl CA3-r CA3-cl 0.7461309 0.0350767684 27.6107963
3 CA2-r ~ CA2-cl CA2-r CA2-cl 0.9732584 -0.0040992226 35.8299582
I want to create simple functions for each row of the data frame. here's what I've tried:
for(i in 1:nrow(coc_comp_model)) {
coc_glm_f[i] <- function(x)
x*coc_comp_model$Gradient[i] + coc_comp_model$Y-Intercept[i]
}
also tried making a vector of functions, which also does ont work either.
Thanks for reading this/helping.
Something like this:
myfunc<-function(datrow, x){
x*as.numeric(datrow[6]) + as.numeric(datrow[5] )
}
Then you can use apply to call it on each row, changing x as desired:
apply(hzdata, 1, myfunc, x = 0.5)
note: using dput() to share your data is much easier than a pasting in a subset.
There is no such thing as a vector of functions. There are 6 atomic vector types in R: raw, logical, integer, double, complex, and character, plus there is the heterogeneous list type, and finally there is the lesser known expression type, which is basically a vector of parse trees (such as you get from a call to the substitute() function). Those are all the vector types in R.
printAndType <- function(x) { print(x); typeof(x); };
printAndType(as.raw(1:3));
## [1] 01 02 03
## [1] "raw"
printAndType(c(T,F));
## [1] TRUE FALSE
## [1] "logical"
printAndType(1:3);
## [1] 1 2 3
## [1] "integer"
printAndType(as.double(1:3));
## [1] 1 2 3
## [1] "double"
printAndType(c(1i,2i,3i));
## [1] 0+1i 0+2i 0+3i
## [1] "complex"
printAndType(letters[1:3]);
## [1] "a" "b" "c"
## [1] "character"
printAndType(list(c(T,F),1:3,letters[1:3]));
## [[1]]
## [1] TRUE FALSE
##
## [[2]]
## [1] 1 2 3
##
## [[3]]
## [1] "a" "b" "c"
##
## [1] "list"
printAndType(expression(a+1,sum(1,2+3*4),if (T) 1 else 2));
## expression(a + 1, sum(1, 2 + 3 * 4), if (T) 1 else 2)
## [1] "expression"
If you want to store multiple functions in a single object, you have to use a list, and you must use the double-bracket indexing operator in the lvalue to assign to it:
fl <- list();
for (i in 1:3) fl[[i]] <- (function(i) { force(i); function(a) a+i; })(i);
fl;
## [[1]]
## function (a)
## a + i
## <environment: 0x600da11a0>
##
## [[2]]
## function (a)
## a + i
## <environment: 0x600da1ab0>
##
## [[3]]
## function (a)
## a + i
## <environment: 0x600da23f8>
sapply(fl,function(f) environment(f)$i);
## [1] 1 2 3
sapply(fl,function(f) f(3));
## [1] 4 5 6
In the above code I also demonstrate the proper way to closure around a loop variable. This requires creating a temporary function evaluation environment to hold a copy of i, and the returned function will then closure around that evaluation environment so that it can access the iteration-specific i. This holds true for other languages that support dynamic functions and closures, such as JavaScript. In R there is an additional requirement of forcing the promise to be resolved via force(), otherwise, for each generated function independently, the promise wouldn't be resolved until the first evaluation of that particular generated function, which would at that time lock in the current value of the promise target (the global i variable in this case) for that particular generated function. It should also be mentioned that this is an extremely wasteful design, to generate a temporary function for every iteration and evaluate it, which generates a new evaluation environment with a copy of the loop variable.
If you wanted to use this design then your code would become:
coc_glm_f <- list();
for (i in 1:nrow(coc_comp_model)) {
coc_glm_f[[i]] <- (function(i) { force(i); function(x) x*coc_comp_model$Gradient[i] + coc_comp_model$`Y-Intercept`[i]; })(i);
};
However, it probably doesn't make sense to create a separate function for every row of the data.frame. If you intended the x parameter to take a scalar value (by which I mean a one-element vector), then you can define the function as follows:
coc_glm_f <- function(x) x*coc_comp_model$Gradient + coc_comp_model$`Y-Intercept`;
This function is vectorized, meaning you can pass a vector for x, where each element of x would correspond to a row of coc_comp_model. For example:
coc_comp_model <- data.frame(Relationship=c('DG-r ~ DG-cl','CA3-r ~ CA3-cl','CA2-r ~ CA2-cl'),Output=c('DG-r','CA3-r','CA2-r'),Input=c('DG-cl','CA3-cl','CA2-cl'),`|r-Value|`=c(0.8271167,0.7461309,0.9732584),`Y-Intercept`=c(0.0027217513,0.0350767684,-0.0040992226),Gradient=c(12.9901380,27.6107963,35.8299582),check.names=F);
coc_glm_f(seq_len(nrow(coc_comp_model)));
## [1] 12.99286 55.25667 107.48578

Setting an object to itself

I am new to R and have a question on the function posted here: R RStudio Resetting debug / function environment. Why are the objects set to themselves (e.g. "getmean = getmean" etc.)? Couldn't it simply be written as follows: list(set, get, setmean, getmean)
The difference is that
aa <- list(set, get, setmean, getmean)
is an unnamed list and
bb <- list(set=set, get=get, setmean=setmean, getmean=getmean)
is a named list. Compare names(aa) and names(bb).
And that = is not assignment. It's really just giving a label to a list item. It's one of the reasons R programmers try to only use <- for assignment and leave = with this special meaning. You could have easily also done
cc <- list(apple=set, banana=get, ornage=setmean, grape=getmean)
cc$apple()
It doesn't have to be the exact same name.
Because list(set, get, setmean, getmean) won't tag the list elements with the correct names. Here's an example of the difference between tagged and untagged lists:
> list(1, 2, 3)
[[1]]
[1] 1
[[2]]
[1] 2
[[3]]
[1] 3
> list(foo=1, bar=2, baz=3)
$foo
[1] 1
$bar
[1] 2
$baz
[1] 3
Note that in the context of argument lists, = is used to supply named arguments, it does not do any assignments (unlike <-). Thus list(foo=1, bar=2, baz=3) is very different from list(foo<-1, bar<-2, baz<-3).
The question has been answered, but you could also do this to achieve the same result.
> object <- c('set', 'get', 'setmean', 'getmean')
> setNames(object = as.list(object), nm = object)
# $set
# [1] "set"
#
# $get
# [1] "get"
#
# $setmean
# [1] "setmean"
#
# $getmean
# [1] "getmean"
The quotations are dependent on what these values actually are.
And you can set different names with like this
> setNames(as.list(object), letters[1:4])
# $a
# [1] "set"
#
# $b
# [1] "get"
#
# $c
# [1] "setmean"
#
# $d
# [1] "getmean"
setNames comes in handy when working with lapply.

Passing more than one parameter to an anonymous function in R

Why doesn't this work? or is just the way R works?
Thanks
JJ
a <- c(1,2,3)
b <- 5
lapply(a, function(x) print(x)) # works
lapply(a, function(x,b) print(b)) # doesn't work.
I get --
Error in FUN(c(1, 2, 3)[[1L]], ...) :
argument "b" is missing, with no default
lapply only passes one argument on, because it's only designed to have one argument vary. If you just want to pass extra arguments along, put them as additional options to lapply:
lapply(a, function(x,y) print(y), y=b)
[1] 5
[1] 5
[1] 5
[[1]]
[1] 5
[[2]]
[1] 5
[[3]]
[1] 5
From the lapply help file:
... optional arguments to FUN.
If you want more than one varying argument to be passed to your function, look at mapply.
You could try putting a and b together in a list as follows:
lapply(list(a, b), function(x) print(b))
or specifying an argumant to pass b to as in:
lapply(a, function(x, y=b) print(y))
But I'm not really sure what you're after.

Resources