sapply with custom function (series of if statements)

12,155

Solution 1

You should be using mapply() instead of sapply():

mapply(bear.correction,x,y)

Why? Your sapply() applies bear.correction() to each entry of x... but giving it the entire y vector as a second argument in each case, and so bear.correction() only looks at the first entry in y in all four cases. To "walk along" multiple entries in multiple vectors (or other data structures), use mapply().

Solution 2

You should be using mapply instead of sapply

mapply(bear.correction,x,y)

[1]  90   0 270 180

Solution 3

put a browser() in your function like this :

bear.correction<-  function(x,y){

  browser()
  if(x > 0 && y < 0){
    return(90)
  }else if(x < 0 && y < 0){
    return(180)
  }else  if(x < 0 && y > 0){
    return(270)
  }else   return(0)
}

you will see what give exactly as parametrs :

Browse[1]> x
[1] 1
Browse[1]> y
[1] -1  1  1 -1

So as others said here you need to use mapply to give scalar values, not atomic vector.

but I think here using plyr is really simpler (nice output format)

library(plyr)
dat <- data.frame(x=x,y=y)
ddply(dat,.(x,y),function(r) bear.correction(r$x,r$y))
   x  y  V1
1 -1 -1 180
2 -1  1 270
3  1 -1  90
4  1  1   0

Solution 4

If you wish to use apply you have to change a bit your function:

bear.correction<-  function(xy){
                                if(xy[1] > 0 && xy[2] < 0){
                                  return(90)
                                }else if(xy[1] < 0 && xy[2] < 0){
                                  return(180)
                                }else  if(xy[1] < 0 && xy[2] > 0){
                                  return(270)
                                }else   return(0)
                              }

The function now takes a vector of 2 values xy and uses the first like your old x and the second like your old y

x <- c(1,1,-1,-1)
y <- c(-1,1,1,-1)

xyx<-cbind(x,y)


apply(xyx,1, bear.correction)
Share:
12,155
Tom Evans
Author by

Tom Evans

Seabird Ecologist. My research has mostly used GPS tracking to follow foraging behaviour in seabirds. I usually analyse this data with R.

Updated on June 07, 2022

Comments

  • Tom Evans
    Tom Evans almost 2 years

    I want to run a function which looks at two vectors, returning different values depending on the signs of the values in the two vectors. I have written a function which works to compare two values, but then I want to run this on two vectors. So I used sapply, but I am getting different results than expected.

    bear.correction<-  function(x,y){
                                    if(x > 0 && y < 0){
                                      return(90)
                                    }else if(x < 0 && y < 0){
                                      return(180)
                                    }else  if(x < 0 && y > 0){
                                      return(270)
                                    }else   return(0)
                                  }
    

    The following give the expected (and desired) result:

      bear.correction(1,-1)
      bear.correction(1,1)
      bear.correction(-1,1)
      bear.correction(-1,-1)
    

    Result: 90, 0, 270, 180

    However when I try to do the same comparisons, but using vectors with sapply I get a different result:

      x <- c(1,1,-1,-1)
      y <- c(-1,1,1,-1)
      sapply(x,bear.correction,y)
    

    Result: 90, 90, 180, 180.

    I can't see what's wrong, so please help!

  • Tom Evans
    Tom Evans over 11 years
    Thanks Stephan. Good answer and clear explanation. I wasn't aware of mapply()
  • Tom Evans
    Tom Evans over 11 years
    Thanks, quick and succinct. Stephen gave a nice explanation too.
  • Tom Evans
    Tom Evans over 11 years
    Thanks, it's useful to have the debugging advice. The Pylr alternative is nice too. I haven't used pylr much, but it's a good package.
  • Tom Evans
    Tom Evans over 11 years
    Thanks. This is a nice solution too.
  • Gago-Silva
    Gago-Silva over 11 years
    For future reference on *apply functions check this question
  • Tom Evans
    Tom Evans over 11 years
    Thanks. That's a really helpful resource. I will bookmark that.