I have a function in R that takes in 3 parameters, say foo(x,y,z).
When I call the function, I really have a list of elements for x, and a list for y but only one element for z. If Z was a list, and I wanted to apply foo to each element, mapply(foo, x, y, z) works.
However, since z is not a list, mapply(foo,x,y,z) does not work.
More specifically, if x and y are lists of 3 elements each, the following does work however: mapply(foo, x, y, list(z, z, z)).
Is there a way I can perhaps combine mapply and sapply without me first making z into a list of 3 elements? I want z to just be reused!
Edit 1: I was asked for an example:
mylist1 <- list(c(5,4), c(7,9), c(8,3))
mylist2<- list(c(2,3), c(6,7), c(10,11))
item3 <- matrix(data = 15, nrow = 3, ncol = 3)
foo <- function(x,y,z){
return(x[1]+y[2]+z[2,2])
}
The following works:
> mapply(foo, mylist1, mylist2, list(item3,item3, item3))
[1] 23 29 34
The following does not work:
mapply(foo, mylist1, mylist2, item3)
Error in z[2, 2] : incorrect number of dimensions
Use the MoreArgs argument to mapply
mapply(foo, x = mylist1, y= mylist2, MoreArgs = list(z = item3))
## [1] 23 29 34
You just have to put the last item in a list, and R will recycle it just fine:
mapply(foo, mylist1, mylist2, list(item3))
Note that the documentation specifically says that the arguments you pass need to be:
arguments to vectorize over (vectors or lists of strictly positive length, or all of zero length)
and you were trying to pass a matrix.
Related
f1<-function(x,y){
f2<-function(a,b){
print("f2")
return(a+b)}
f2(x,y)
print("f1")
return(x-y)}
f1(8,5)
I was trying above code to figure out the steps of operating function within function, so instead of writing two separate functions, I write the above code. But I can't get the output for a+b (which is 13)
[1] "f2"
[1] "f1"
[1] 3
#[1] 13, this output is missing.
How should the code be corrected? Thank you.
*additional question: when I only write x-y instead of return(x-y) at the last line of the function f1, I got the same output. Is simply write x-y a bad practice or accpetable?
-------------------------Update:
I just find out a way to get all the four outputs by changing the 4th line from return(a+b) to print(a+b)
or to make it more simple, only use the x,yarguments:
f1<-function(x,y) {
f2<-function() {
print("f2")
print(x+y)
}
f2()
print("f1")
x-y
}
while I still don't understand why using return(x+y) or simply x+y at the 4th line could not get the output of 13?
When an expression is on a line by itself it will automatically print if you do it at the R console but that does not happen if it is within a function or within an expression. Use cat or print for displaying.
To return two objects return a list containing both of them as shown at below.
The value of the last line that is run in a function is returned so you rarely need return.
f1a <- function(x, y) {
f2 <- function(a, b) {
print("f2")
a + b
}
print("f1")
list(x - y, f2(x, y))
}
result <- f1a(8, 5)
## [1] "f1"
## [1] "f2"
result[[1]]
## [1] 3
result[[2]]
## [1] 13
result
## [[1]]
## [1] 3
##
## [[2]]
## [1] 13
Other things we could do would be to replace the list(...) line in the code above with one of the following. (The c versions would only be used if we knew that the arguments were always scalars.)
list(f1 = x - y, f2 = f2(x, y)) # named list
c(x - y, f2(x, y)) # 2 element numeric vector
c(f1 = x - y, f2 = f2(x, y)) # 2 element named numeric vector
cbind(f1 = x - y, f2 = f2(x, y)) # matrix w column names
data.frame(f1 = x - y, f2 = f2(x, y)) # data.frame
I would like to pass a function name as an argument in mapply:
f2 <- function(a, b) a + b^2
f <- function(a, b, func) func(a, b)
f(1, 3, f2) ## returns 10
mapply(f2, 1:2, 3) ## returns [1] 10 11
mapply(function(a, b) f(a, b, f2), 1:2, 3) ## returns [1] 10 11
mapply(f, 1:2, 3, f2) ## fails
The final mapply call generates the error
Error in dots[[3L]][[1L]] : object of type 'closure' is not subsettable
Is there any way to do this?
mapply assumes you want to iterate over all the vectors you pass after the first function. But you want to use the same value of f2 for every iteration. You can do that useing the MoreArgs= parameter
mapply(f, 1:2, 3, MoreArgs=list(func=f2))
You don't have the same problem with the 3 because R will perform vector recycling to expand 3 to c(3,3) to match the same length as c(1,2). Functions in R don't have the same implicit recycling behaviors. But if you want the value to always stay the same, it's better to put it in the MoreArgs parameter
1) Wrap the function in a list:
mapply(f, 1:2, 3, list(f2))
## [1] 10 11
2) Typically functions that have function arguments use match.fun so that one can pass either the function or a character string containing its name. For example, mapply itself does that so the above line of code could equally be written as: mapply("f", 1:2, 3, list(f2)) . If f were written that way then we could simply specify the name of f2 as a character string, namely "f2" .
f <- function(a, b, func) {
func <- match.fun(func)
func(a, b)
}
mapply(f, 1:2, 3, "f2")
## [1] 10 11
Suppose I have a collection of independent vectors, of the same length. For example,
x <- 1:10
y <- rep(NA, 10)
and I wish to turn them into a list whose length is that common length (10 in the given example), in which each element is a vector whose length is the number of independent vectors that were given. In my example, assuming output is the output object, I'd expect
> str(output)
List of 10
$ : num [1:2] 1 NA
...
> output
[[1]]
[1] 1 NA
...
What's the common method of doing that?
use mapply and c:
mapply(c, x, y, SIMPLIFY=FALSE)
[[1]]
[1] 1 NA
[[2]]
[1] 2 NA
..<cropped>..
[[10]]
[1] 10 NA
Another option:
split(cbind(x, y), seq(length(x)))
or even:
split(c(x, y), seq(length(x)))
or even (assuming x has no duplicate values as in your example):
split(c(x, y), x)
Here is a solution that allows you to zip arbitrary number of equi-length vectors into a list, based on position of the element
merge_by_pos <- function(...){
dotlist = list(...)
lapply(seq_along(dotlist), function(i){
Reduce('c', lapply(dotlist, '[[', i))
})
}
x <- 1:10
y <- rep(NA, 10)
z <- 21:30
merge_by_pos(x, y, z)
This question is a follow-up to a previous answer which raised a puzzle.
Reproducible example from the previous answer:
Models <- list( lm(runif(10)~rnorm(10)),lm(runif(10)~rnorm(10)),lm(runif(10)~rnorm(10)) )
lm1 <- lm(runif(10)~rnorm(10))
library(functional)
# This works
do.call( Curry(anova, object=lm1), Models )
# But so does this
do.call( anova, Models )
The question is why does do.call(anova, Models) work fine, as #Roland points out?
The signature for anova is anova(object, ...)
anova calls UseMethod, which should* call anova.lm which should call anova.lmlist, whose first line is objects <- list(object, ...), but object doesn't exist in that formulation.
The only thing I can surmise is that do.call might not just fill in ellipses but fills in all arguments without defaults and leaves any extra for the ellipsis to catch? If so, where is that documented, as it's definitely new to me!
* Which is itself a clue--how does UseMethod know to call anova.lm if the first argument is unspecified? There's no anova.list method or anova.default or similar...
In a regular function call ... captures arguments by position, partial match and full match:
f <- function(...) g(...)
g <- function(x, y, zabc) c(x = x, y = y, zabc = zabc)
f(1, 2, 3)
# x y zabc
# 1 2 3
f(z = 3, y = 2, 1)
# x y zabc
# 1 2 3
do.call behaves in exactly the same way except instead of supplying the arguments directly to the function, they're stored in a list and do.call takes care of passing them into the function:
do.call(f, list(1, 2, 3))
# x y zabc
# 1 2 3
do.call(f, list(z = 3, y = 2, 1))
# x y zabc
# 1 2 3
I think it is worth stressing that the names of the list elements do matter. Hadley mentioned it, but it can be an annoyance. Consider the next example:
x <- rnorm(1000)
y <- rnorm(1000)
z <- rnorm(1000) + 0.2
Models <- list()
Models$xy <- lm(z~x)
Models$yz <- lm(z~y)
# This will fail, because do.call will not assign anything to the argument "object" of anova
do.call(anova, Models)
# This won't
do.call(anova, unname(Models))
do.call passes the first element of the list to the first argument:
fun <- function(x,...) {
print(paste0("x=",x))
list(x, ...)
}
do.call(fun, list(1,2))
# [1] "x=1"
# [[1]]
# [1] 1
#
# [[2]]
# [1] 2
I have two lists looking like this:
mylist <- list(a=c(1:5),
b = c(5:12),
c = c(2:8))
list.id <- list(a=2, b=8, c=5)
I want to count the number of elements in mylist that are higher than the corresponding element in list.id and divide the result for the length of element in mylist. I have written this function.
perm.fun <- perm.fun2 = function(x,y){length(which(x[[i]] < y[[i]]))/length(x[[i]])}
However, when I do: lapply(mylist, perm.fun, list.id) I do not obtain the expected result.
Thanks
Using lapply, you would need to loop on the indices (1, 2, 3) so they can be used to extract the elements from both mylist and list.id:
perm.fun <- function(i, x, y) mean(x[[i]] > y[[i]])
lapply(seq_along(mylist), perm.fun, mylist, list.id)
But mapply is a much better tool for that task. From the doc:
mapply applies FUN to the first elements of each ... argument, the second elements, the third elements, and so on.
So your code can just be:
mapply(function(x, y) mean(x > y), mylist, list.id)
# a b c
# 0.6000000 0.5000000 0.4285714