0

assume I have a user defined fun

fun <- function(i,j,k){}

I am looking for a function(), that

function(fun, c(x1, x2), c(y1,y2), c(z1,z2))

performs as

fun(x1,y1,z1)
fun(x1,y2,z1)
fun(x2,y1,z1)
fun(x2,y2,z1)    
fun(x1,y1,z2)
fun(x1,y2,z2)
fun(x2,y1,z2)
fun(x2,y2,z2)

I though apply family may do the job. However I did not find the right one.

=====================================================================

Here is a real example I am working on, however still cannot be solved.

data <- read.table(header = TRUE, stringsAsFactors = FALSE,
                   text = "ID x1 x2  y1  y2
                   1   a  T 100  2
                   2   b  T 210  4
                   3   b  F 112  5
                   4   a  F 121  1
                   5   b  F 412  1")

boxplot <- function(i,j){
  print(ggplot(data, 
               aes_string(x=colnames(data)[i], 
                   y=colnames(data)[j],
                   col=colnames(data)[i]))+
                 geom_boxplot())
}

then you can use boxplot(2,4) to make a plot, so does boxplot(3,4), boxplot(2,5), boxplot(3,5).

Then I tried both do.call and apply methods from answers.

do.call(boxplot, as.list(unname(expand.grid(c(2, 3), c(4,5)))))

or

apply(expand.grid(c(2,3), c(4,5)),1,boxplot)

however they did not work as expected. the do.call method only returns one plot, and the apply one retures 8 plot but all have y axis as ID.

======================================================

the for loop made it work. Any comments?

for (i in 2:3) {
  for (j in 4:5) {
  boxplot(i,j)
  }
}
Hanfu
  • 35
  • 8

3 Answers3

2

Try this:

sum3 <- function(x, y, z) x+y+z  # test function
mapply(sum3, 1:3, 11:13, 21:23)
## [1] 33 36 39

Here sum3(1, 11, 21) is 33, sum3(2, 12, 22) is 36 and sum3(3, 13, 23) is 39. There are more examples on the ?mapply help page.

This also works and returns a list:

Map(sum3, 1:3, 11:13, 21:23)
G. Grothendieck
  • 254,981
  • 17
  • 203
  • 341
  • Actually, `mapply` is exactly what was asked. It passes distinct arguments, not a single vector. The `sum` function can accept any number of arguments. – Ryan C. Thompson Nov 03 '15 at 23:51
  • Hi G thanks for your answer. My question may not be clear. The result I expect for your example would be a total of 9 sum3(), which go through all combinations of three numbers from three groups. – Hanfu Nov 04 '15 at 14:36
  • Hi G I added an example. Let me know if my question is clarified. – Hanfu Nov 04 '15 at 19:29
1

xIt would be nice if you provided a reproducible example so we can verify possible solutions, but I think you can get what you want with exapand.grid and do.call. How about

do.call(fun, as.list(unname(expand.grid(c(x1, x2), c(y1,y2), c(z1,z2)))))

Do if you had

fun <- function(i,j,k){i+j+k}
x1<-1; x2<-2;
y1<-10; y2<-20;
z1<-100; z2<-200;

You would get

[1] 111 112 121 122 211 212 221 222
# x1+y1+z1, x2+y1+z1, x1+y2+z1, x2+y3+z1, ...
Community
  • 1
  • 1
MrFlick
  • 195,160
  • 17
  • 277
  • 295
  • feels good to see that my reasoning somehow resonates with seasoned stack overflow members :) – Bg1850 Nov 03 '15 at 23:52
  • Thanks Mr. Flick. You got a reproducible great example didn't ya ;) – Hanfu Nov 04 '15 at 14:38
  • Hi Mr. Flick I added an example to the question and your method does not quite work out. May you take a second look at it? – Hanfu Nov 04 '15 at 19:24
  • In your example, what corresponds to the vector of `x` and `y` values? I don't see two sources there. What are the exact series of functions calls that you want? Also, I assumed your function would be properly vectored but your example is not. That could be fixed by `Vectorize()` but it's unclear exactly what your desired output is. Normally you can only print one plot at a time without doing extra work, – MrFlick Nov 04 '15 at 19:30
  • I would like x to be column x1 and x2, and y to be column y1 and y2. And I would like to call them by assign i and j as the column numbers. With given data, column x1 and x2 would be refered by i = c(2,3), and column y1 and y2 would be refered by j=c(4,5). I hope this clarify the sources question. I will look into function vectorization. However, is there ways to produce multiple plots at once? Thanks! – Hanfu Nov 05 '15 at 18:56
  • Hey Mr. Flick I used a for loop to get what I want.. do not know how to format it in comments for (i in 2:3) { for (j in 4:5) { print(ggplot(data, aes_string(x=colnames(data)[i], y=colnames(data)[j], col=colnames(data)[i]))+ geom_boxplot()) } } – Hanfu Nov 05 '15 at 19:39
0

If I understood this correctly,this should be pretty simple

apply(expand.grid(c(x1, x2), c(y1,y2), c(z1,z2)),1,fun)

edit : adding example

x <-c(13,14)
y <- c(21,22)
z<- c(35,36)
apply(expand.grid(x,y,z),1,mean)
[1] 23.00000 23.33333 23.33333 23.66667 23.33333 23.66667 23.66667 24.00000
Bg1850
  • 3,032
  • 2
  • 16
  • 30
  • glad that it helped . – Bg1850 Nov 04 '15 at 18:30
  • Hi BG I added my real example to the question and the method doen not quite work out. May you take a second look at it? – Hanfu Nov 04 '15 at 19:24
  • I assume this has to do something with your boxplot function , you can only use functions which are vectorized like 'mean' in this . – Bg1850 Nov 04 '15 at 20:09