sapply с пользовательской функцией (серия операторов if)

Я хочу запустить функцию, которая смотрит на два вектора, возвращая разные значения в зависимости от знаков значений в двух векторах. Я написал функцию, которая работает для сравнения двух значений, но затем я хочу запустить ее на двух векторах. Итак, я использовал sapply, но получаю другие результаты, чем ожидалось.

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

Следующее дает ожидаемый (и желаемый) результат:

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

Результат: 90, 0, 270, 180

Однако, когда я пытаюсь провести те же сравнения, но используя векторы с sapply, я получаю другой результат:

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

Результат: 90, 90, 180, 180.

Я не вижу, что случилось, пожалуйста, помогите!


person Tom Evans    schedule 07.01.2013    source источник
comment
Прошу прощения, @agstudy, я думал, что можно принять несколько ответов, но, видимо, нет. Я думаю, что ответ Стефана Колосса был лучшим, хотя все остальные тоже работают, отсюда и мои положительные комментарии.   -  person Tom Evans    schedule 07.01.2013
comment
нет проблем. Надеюсь, это поможет.   -  person agstudy    schedule 07.01.2013


Ответы (4)


Вы должны использовать mapply() вместо sapply():

mapply(bear.correction,x,y)

Почему? Ваш sapply() применяет bear.correction() к каждой записи _6 _..., но дает ему весь y вектор в качестве второго аргумента в каждом случае, и поэтому bear.correction() смотрит только на первую запись в y во всех четырех случаях. Чтобы «пройтись» по множеству записей в множественных векторах (или других структурах данных), используйте mapply().

person Stephan Kolassa    schedule 07.01.2013
comment
Спасибо, Стефан. Хороший ответ и четкое объяснение. Я не знал о mapply () - person Tom Evans; 07.01.2013

Вы должны использовать mapply вместо sapply

mapply(bear.correction,x,y)

[1]  90   0 270 180
person Gago-Silva    schedule 07.01.2013
comment
Спасибо, быстро и лаконично. Стивен тоже дал хорошее объяснение. - person Tom Evans; 07.01.2013
comment
Для дальнейшего использования * функций применения проверьте это вопрос - person Gago-Silva; 07.01.2013
comment
Спасибо. Это действительно полезный ресурс. Я добавлю это в закладки. - person Tom Evans; 07.01.2013

поместите browser() в свою функцию следующим образом:

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

вы увидите, что дают именно в виде параметров:

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

Итак, как говорили здесь другие, вам нужно использовать mapply для задания скалярных значений, а не атомарного вектора.

но я думаю, что здесь использовать plyr действительно проще (хороший формат вывода)

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
person agstudy    schedule 07.01.2013
comment
Спасибо, полезный совет по отладке. Альтернатива Pylr тоже хороша. Я нечасто использовал pylr, но это хороший пакет. - person Tom Evans; 07.01.2013

Если вы хотите использовать apply, вам нужно немного изменить свою функцию:

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

Теперь функция принимает вектор из 2 значений xy и использует первое, как ваш старый x, а второе, как ваш старый y.

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

xyx<-cbind(x,y)


apply(xyx,1, bear.correction)
person ECII    schedule 07.01.2013
comment
Спасибо. Это тоже хорошее решение. - person Tom Evans; 07.01.2013