Question

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!

Was it helpful?

Solution

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

OTHER TIPS

You should be using mapply instead of sapply

mapply(bear.correction,x,y)

[1]  90   0 270 180

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

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)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top