0

I have 2 function in R, the first is :

cyii=function(a,b,L) 
{
  d=outer(a,b,`-`);I=outer(a,b,`==`)
  d=d[upper.tri(d,diag=T)];I=I[upper.tri(I,diag=T)]
  L[1]^2*exp(-0.25*d^2/L[2]^2) +  I*L[3]^2
}

The second function called the first function many time

zii=list()
  for(i in 1:(n-1))
  {
    zii[[i]]=cyii(v1,v1,H[c(5*i-4,5*i-3,5*n-3+i)])
  }

Where v1 is any vector of numbers and H is a vector of parameters. Below is a reproducable example.

dput(v1)=c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
dput(H)=c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15)
n=3

Is there a possible way to use the apply function or any other in order to avoid using the for loop, given that for every n I need to provide the first function with diffrent values from H

cdeterman
  • 19,630
  • 7
  • 76
  • 100
raK1
  • 519
  • 1
  • 4
  • 13
  • In your "cyii" function you need "L" (i.e. "H[i]") after the creation of "d" and "I". If instead of computing "d" and "I" inside your "cyii" you move the computations once and before your "zii" loop, I guess you'll save some time. Also, pre-allocate "zii" as `vector("list", n - 1)` to avoid the copies made during the growing of "zii". – alexis_laz Mar 25 '16 at 22:19
  • Your question "is there a possible way to use the apply function or any other in order to avoid using the for loop" makes no sense if the goal is to [increase performance](http://stackoverflow.com/a/2276001/4770166). Using the apply family renders the code more compact and less error-prone, but it does not result in a faster code if the for loop is written properly. – RHertel Mar 26 '16 at 08:49
  • Absolutely, apply functions are not always faster, but as effectively all the answers in the link you post suggests, there are many reasons to use apply functions when you can anyway. Also worth noting that all but the top voted answer gives examples of *apply function being faster than for loops. – Brian Albert Monroe Mar 26 '16 at 10:50
  • @kor, for a very simple way to improve performance for this operation, insert `cyii <- compiler::cmpfun(cyii)` after declaring the `cyii` function. This tells R to compile the function instead of just interpreting it. Check out the `compiler` package and `?compiler::cmpfun` for details. This will make it a little faster with very little extra work. – Brian Albert Monroe Mar 26 '16 at 10:55
  • @BrianAlbertMonroe can compiler::cmpfun() be used for any function ? – raK1 Mar 26 '16 at 17:23
  • Yep, but remember that a lot of R named functions are already written in C and highly optimized, so using `cmpfun` on something like `sum2 <- function(X){ sum(X) }` will do nothing. The more arithmetic you do, the more improvement you'll get, the more calls to R functions you do, the less it'll matter. There should be something in the man pages about this, google is your friend here :) – Brian Albert Monroe Mar 26 '16 at 17:50

1 Answers1

1

Yes, shouldn't be a problem at all

# What you supplied
cyii=function(a,b,L) 
{
  d=outer(a,b,`-`);I=outer(a,b,`==`)
  d=d[upper.tri(d,diag=T)];I=I[upper.tri(I,diag=T)]
  L[1]^2*exp(-0.25*d^2/L[2]^2) +  I*L[3]^2
}

v1=c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
H=c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15)
n=3


zii=list()
  for(i in 1:(n-1))
  {
    zii[[i]]=cyii(v1,v1,H[c(5*i-4,5*i-3,5*n-3+i)])
  }

# Change it up a little to use 'lapply'

N <- 1:(n-1)

z2 <- lapply(N, function(i){
    cyii(v1,v1,H[c(5*i-4,5*i-3,5*n-3+i)])
})

identical(zii,z2)
#[1] TRUE
  • it seems that the for loop is faster than the lappy, does it meen that I need to vectorize ? – raK1 Mar 25 '16 at 21:13
  • Also if I want to sum in the apply function , how can I do that ? – raK1 Mar 25 '16 at 21:21
  • Always vectorize when you can, and always use `*apply` instead of a `for` loop when you can. That being said, the example you give though only iterates twice, so I don't imagine there would be any noticeable difference in speed due to the for loop, and I don't know how minimal an example this is to tell you to change around your code more than in my answer. – Brian Albert Monroe Mar 25 '16 at 21:33
  • Sum how, inter-list element or intra-list element. Either change `cyii(v1,v1,H[c(5*i-4,5*i-3,5*n-3+i)])` to `sum(cyii(v1,v1,H[c(5*i-4,5*i-3,5*n-3+i)]))` for the former, or `do.call(sum, z2)` for the latter. – Brian Albert Monroe Mar 25 '16 at 21:35
  • is there a way to add each elemnt seprately in the list ? – raK1 Mar 25 '16 at 23:05
  • Elements in each list item are accessed like any other elements `z2[[1]][1]` gives you the first element of the first item of the list, `z2[[1]][2]` the second and so on – Brian Albert Monroe Mar 26 '16 at 06:40