Performing a function's criterion within another - r

This is fairly difficult for me to explain, however, I wish to use a function that's within a function, that can be used towards the variables.
For example, given that the function looks similar to this:
test <- function(a, b, c){
a <- ...
b <- ...
c <- ...
}
#used likeso:
test(a = ..., b = ..., c = ...)
Is it possible to use it likeso:
test(a = ..., c(b = ...))
And what's an example of how this function would look like? I'm looking for a function like this because I'm trying to index a function within a function, that can be used like the second function above.
I know that this can be achieved with two separate function, though, I'm asking as to whether its possible with one function, whilst having another function indexed within it?

Use do.call like this:
test <- function(a, b, c) a + b + c
do.call("test", list(a = 1, b = 2, c = 3))
## [1] 6

Related

R: mapply with vector argument

I have a function of this form:
foo<-function(x,y){
if(length(y)==1){
return(x*y)
}
else{
return(x-y[1]*y[2])
}
}
and for the y argument I pass either a number or a vector of numbers:
> #test function:
> foo(1,2)
[1] 2
> foo(1,c(1,2))
[1] -1
Now I wish to use mapply to this function, but I run into problems when I wish to pass a vector for the y argument:
df<-data.frame(
"a"<-floor(runif(6, 1,10)),
"b"<-floor(runif(6, 18,80)),
"c"<-floor(runif(6, 1,80)),
"d"<-floor(runif(6, 100,800)),
"e"<-floor(runif(6, 1000,4000)),
"f"<-floor(runif(6, 1,10)),
"g"<-floor(runif(6, 5,80))
)
names(df)=c("a","b","c","d","e","f","g")
The following works fine:
> mapply(FUN=foo,df["a"],df["b"])
,but I run into trouble when I try to do the following:
> mapply(FUN=foo,df["a"],cbind(df["b"],df["c"]))
I'm very grateful for tips on how to better use an argument that have verying length, or how to pass the argument to mapply!
There are a lot of possible fixes here. Fundamentally, you need to turn 2nd input into mapply into a list with two elements in each list. One way to achieve that is to do something like:
tmp <- as.data.frame(t(df[c('b', 'c')]))
result <- mapply(FUN=foo,df["a"], tmp)
since a data frame is a list. This is going to run the function on all combinations of df["a"] and tmp. The elements you want will be along the diagonal (1st element of df['a'] with the first element of tmp, so the final answer is
diag(result)
BTW, when you are inside a function such as data.frame, use = for assignment instead of <-. You also do not need the quotes around the letters (they are being ignored). so you're call to data.frame should look like
df<-data.frame(
a = floor(runif(6, 1,10)),
b = floor(runif(6, 18,80)),
c = floor(runif(6, 1,80)),
d = floor(runif(6, 100,800)),
e = floor(runif(6, 1000,4000)),
f = floor(runif(6, 1,10)),
g = floor(runif(6, 5,80))
)
Which allows you to avoid having to name the data frame after you define it.
Update without diagonal call
f1 <- function(x) {
if(length(x) ==2 ) x[1] * x[2]
else x[1] - x[2]*x[3]
}
apply(df[,c("a","b", "c")], 1, f1)

using separate matrices in a loop and saving the results in a data frame

I have a few matrices that all of them are the same in number of rows and columns and dimanames of them are exactly the same too. I read them like this for example
a<-read.csv("a.txt",row.names = 1,header=T,sep="\t")
b<-read.csv("b.txt",row.names = 1,header=T,sep="\t")
c<-read.csv("c.txt",row.names = 1,header=T,sep="\t")
d<-read.csv("d.txt",row.names = 1,header=T,sep="\t")
e<-read.csv("e.txt",row.names = 1,header=T,sep="\t")
Now I want to get similarity index between a & b, a & c,...,b & c, ..., c & d, d
& e using this code
library(igraph)
library(BiRewire)
jaccard.index<-birewire.similarity( a,b)
Then I want to save the result as a data frame like this for example
mat1 mat2 simil.index
a b 0.9142
a c 0.8126
a d 0.5066
b e 0.9526
I don't know how can I use these separate matrices in a loop and saving the result like that. Anyone help me on this problem?
Prepare the function to compute pairwise similarities
myfun <- function(x, y) {
birewire.similarity(eval(parse(text = x)), eval(parse(text = y)))
}
Build the possible combinations (you said your matrices are named as the first 5 letters of the alphabet, but you can put any names in place of letters[1:5]):
myletters <- combn(letters[1:5], 2)
Build the dataframe binding by column the combinations and the results of the function that is applied to such combinations:
data.frame(t(myletters),
simil.index = mapply(myfun, myletters[1,], myletters[2,]))

Specify which argument is supplied by X in lapply

I've got a function, e.g. fun(a, b = 1, c = 3, ...), that takes a number of arguments, some of which have default values. I would like to call this function using lapply(X, FUN, ...), but specify explicitly which argument I would like X to supply. In the example above, the X vector could be supplied for a or b or c, or xyz in the ....
Normally I might call lapply(1:5, fun, a = 4) and I imagine it would use 1:5 as the b argument.
Is there a way to make that more explicit?
What if I want to use the default argument for b and use 1:5 for c?
What if I want to use 1:5 as an xyz argument in the ...?
Normally I might call lapply(1:5, fun, a = 4) and I imagine it would use 1:5 as the b argument.
Yes, your imagination is correct. lapply uses positional matching to pass its X parameter to the function. Normal rules of argument matching apply, which means exact matching of named parameters takes precedence.
An alternative would of course be to wrap fun in an anonymous function:
lapply(1:5, function(b, a, ...) fun(a = a, b = b, ...), a = 4)
One way to handle you use case would be to simply call your own function inside the custom function which lapply exposes to you:
lst <- list(v1=c(1:3), v2="Hello", v3=5)
result <- lapply(lst, function(x) {
y <- FUN(x, a, b, c, ...) # Here FUN() is your own function
return(y)
})

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).

Apply family of functions for functions with multiple arguments

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

Resources