Apply family of functions for functions with multiple arguments - r

I would like to use a function from the apply family (in R) to apply a function of two arguments to two matrices. I assume this is possible. Am I correct? Otherwise, it would seem that I have to put the two matrices into one, and redefine my function in terms of the new matrix.
Here's an example of what I'd like to do:
a <- matrix(1:6,nrow = 3,ncol = 2)
b <- matrix(7:12,nrow = 3,ncol = 2)
foo <- function(vec1,vec2){
d <- sample(vec1,1)
f <- sample(vec2,1)
result <- c(d,f)
return(result)
}
I would like to apply foo to a and b.

(Strictly answering the question, not pointing you to a better approach for you particular use here....)
mapply is the function from the *apply family of functions for applying a function while looping through multiple arguments.
So what you want to do here is turn each of your matrices into a list of vectors that hold its rows or columns (you did not specify). There are many ways to do that, I like to use the following function:
split.array.along <- function(X, MARGIN) {
require(abind)
lapply(seq_len(dim(X)[MARGIN]), asub, x = X, dims = MARGIN)
}
Then all you have to do is run:
mapply(foo, split.array.along(a, 1),
split.array.along(b, 1))
Like sapply, mapply tries to put your output into an array if possible. If instead you prefer the output to be a list, add SIMPLIFY = FALSE to the mapply call, or equivalently, use the Map function:
Map(foo, split.array.along(a, 1),
split.array.along(b, 1))

You could adjust foo to take one argument (a single matrix), and use apply in the function body.
Then you can use lapply on foo to sample from each column of each matrix.
> a <- matrix(1:6,nrow = 3,ncol = 2)
> b <- matrix(7:12,nrow = 3,ncol = 2)
> foo <- function(x){
apply(x, 2, function(z) sample(z, 1))
}
> lapply(list(a, b), foo)
## [[1]]
## [1] 1 6
## [[2]]
## [1] 8 12

Related

Perform a series of operations on a vector in R without a loop

I've got a vector that I want to perform the same operation on multiple times in series, modifying one argument, and I can't figure out a way to do it without a loop.
For example, say I want to take the vector c(1, 2, 3) and I want to perform a series of logs on it. In a loop, I would do this:
foo <- 30:32
for(anum in c(2,3,4)){
foo <- log(foo, base = anum)
}
A way to do it without a loop would be:
30:32 |>
log(base = 2) |>
log(base = 3) |>
log(base = 4)
What I'm wanting is to have a function that will take 2:4 as an argument and do this. So something like:
30:32 |> serialfunction(log, 2:4)
Does a function like this exist?
Thanks!
There's not really a built-in function that does exactly that. But you can do this with Reduce. For example
Reduce(function(x, y) {log(x, base=y)}, 2:4, init=30:32)
# [1] 0.2669627 0.2713007 0.2754373
You could create serial function with
serialfunction <- function(x, fun, y) {
Reduce(function(x, y) {fun(x, y)}, y, init=x)
}
30:32 |> serialfunction(log, 2:4)
# [1] 0.2669627 0.2713007 0.2754373

Function mapped to reduce function to concatenate vectors together

I'm trying to write a function that maps a function to reduce to concatenate a list of vectors together into 1 with the very first entry and the very last entry.
For example,
reduce(list(1:10, 11:20, 21:100), r_cat, .init = NULL)
should return a vector equal to
1:100
This is what I have so far.
r_cat = function(x, y) {
out <- y[[1]]
for(i in seq(2, length(y))) {
out <- x(out, y[[i]])
}
out
}
Any thoughts?
No need to write a new function, unlist solves your problem:
List <- list(1:10, 11:20, 21:100)
unlist(List)
If you want to use Reduce from R base, then you can use c
Reduce("c", List)
You can also get the same result plugging c into reduce from purrr
library(purrr)
reduce(List, c)

R - how do I run each function in a list of functions with parameters given by a vector

Suppose I have a list of functions and a vector of parameter values:
functions <- list(a = function(x) x *2, b = function(x) x*3, c = function(x) x * 4)
paramVector <- c(2, 2, 1)
Now I want the following functionality of calling each function with the corresponding parameter and collating the result into a vector:
result <- c()
for (idx in 1:length(functions)) {
result[idx] <- functions[[idx]](paramVector[idx])
}
result
Is there a way to do this without the for loop?
To iterate over the functions and paramVector objects at the same time, use Map. For example
Map(function(f,p) f(p), functions, paramVector)
Note that Map() always returns a list. You can also use mapply() which will attempt to simplify to a vector
mapply(function(f,p) f(p), functions, paramVector)

foreach: Keep names

Is there a way to make foreach() return a named list/data.frame. E.g.
foo <- list(a = 1, b = 2)
bar <- foreach (x = foo) %do% { x * 2 }
returns list(2, 4). I would want it to return list(a = 2, b = 4).
Plus, is there a way to access the name from within the loop body?
(I'm not interested in a solution which assigns the names after the foreach loop.)
Regards
I was using your solution until I needed to use a nested foreach (with the %:% operator). I came up with this:
foo <- list(a = 1, b = 2)
bar <- foreach (x = foo, .final = function(x) setNames(x, names(foo))) %do% {
x * 2
}
The trick is to use the .final argument (which is a function applied once at the final result) to set the names. This is nicer because it doesn't use a temporary variable and is overall cleaner. It works with nested lists so that you can preserve the names accross several layers of the structure.
Note that this only works correctly if foreach has the argument .inorder=T (which is the default).
Thanks for your recommendations. This is what I came up with:
foo <- list(a = 1, b = 2)
bar <- foreach (x = foo, n = names(foo), .combine = c) %do% {
rv <- list()
rv[[n]] <- x * 2
rv
}
I used to work with foreach, but having switched to purrr I am not looking back.
purrr provides a family of mapping functions which make working with named lists (and lists, and data.frames...) a complete breeze. All mapping operations preserve names.
library("purrr")
foo <- list(a = 1, b = 2)
bar <- map(foo, ~ .x * 2)
# $a
# [1] 2
# $b
# [1] 4
Concise and clear, you can't really beat that.
Plus, is there a way to access the name from within the loop body?
There sure is: ?imap
bar <- imap(foo, function(elem, name) {
print(paste("Processing", name))
elem * 2
})
Or anonymous style:
bar <- imap(foo, ~ {print(paste("Processing", .y)) ; .x * 2})

R: sequentially applying an arbitrarty list of functions with arguments to a matrix

I have a list of filtering functions f1,f2,f3,f4,.... which take a matrix m and a number of options as input and return a subset of the rows of matrix as output. Now I would like to be able to define in an orderly way some meta-filtering function settings metaf1, metaf2, metaf3,... which would specify the sequential application of a specified nr of filtering functions, e.g. first f2 and then f3, using given options for each. I would like to store these filtering settings in a list of say class "metafiltering", and then have another function apply the filtering steps specified in a given metafiltering object. My idea would be able to in this way allow filtering settings to be stored and applied in an orderly way. How would I achieve this in the most elegant way in R? Or is there perhaps other convenient methods to achieve something like this?
EDIT: to give an example, say I have matrix
m=replicate(10, rnorm(20))
and filtering functions (these are just examples, obviously mine are more complicated :-) )
f1=function(m,opt1,opt2) {
return(m[(m[,2]>opt1)&(m[,1]>opt2),])
}
f2=function(m,opt1) {
return(m[(m[,3]>opt1),])
}
And I have defined the following metafiltering settings of specific class which would specify two functions which would have to be applied sequentially to matrix m
metafilterfuncs=list(fun1=f1(opt1=0.1,opt2=0.2),fun2=f2(opt1=0.5))
class("metafilterfuncs")="metafiltering"
The question I have then is how I could apply the filtering steps of an arbitrary metafiltering function object to given matrix m using the specified functions and settings?
You can do something like this :
You define a sort of functions pieplines where you give a priority for each function.
pipelines <- c(f1=100,f2=300,f3=200)
I define 3 dummy functions here for test:
f1 <- function(m,a) m + a
f2 <- function(m,b) m + b
f3 <- function(m,c) m + c
For each function , you store the argument in another list :
args <- list(f1=c(a=1),f2=c(b=2),f3=c(c=3))
Then you apply your functions :
m <- matrix(1:2,ncol=2)
for (func in names(pipelines[order(pipelines)]))
{
m <- do.call(func,list(m,args[[func]]))
}
pryr has a function, compose, like what you need, but it doesn't quite cut it. The compose function requires the functions to be given one by one, not in a list, and it cannot take arguments. It's also oddly placed in that package. A similar function can be found in plyr, namely each. But this function does not apply functions sequentially, but individually and outputs a named vector (list?).
agstudy provided a solution above, but it suffers from a problem: it can only take scalar arguments because it gives the arguments in a named vector. The solution to this is to use a named list instead. So, here's an improved function to replace the one in pryr.
compose2 = function(x, funcs, args, msg_intermediate = F) {
if (length(funcs) != length(args)) stop("length of functions and arguments must match")
for (i in seq_along(funcs)) {
x = do.call(what = funcs[[i]], args = c(x, args[[i]]))
if ((i != length(funcs)) && msg_intermediate) message(x)
}
x
}
msg_intermediate is a nice debugging argument that messages the intermediate results, so one can easier understand what happens.
Test it:
adder = function(x, n) x + n
compose2(0,
funcs = list(adder, adder, adder),
args = list(list(n = 1), list(n = 2), list(n = 3)),
msg_intermediate = T
)
Outputs:
1
3
[1] 6
This is what you get when you take 0, then add 1 (=1), then add 2 (=3), then add 3 (=6).
The args argument for compose2 takes a list of lists, so that one can supply non-scalar function arguments. Here's an example:
add_div = function(x, n, d) (x + n) / d
compose2(0,
funcs = list(add_div, add_div, add_div),
args = list(list(n = 1, d = 1), list(n = 2, d = 2), list(n = 3, d = 3)),
msg_intermediate = T
)
Output:
1
1.5
[1] 1.5
Which is what you get when you take 0, add 1, divide by 1 (=1), then take 1, add 2 then divide by 2 (=1.5), then take 1.5, add 3 and then divide by 3 (=1.5).

Resources