2011-11-18 6 views
9

는 (배경 정보는 : ifelse는 하나가 반환됩니다에도 불구하고, 표현의 두평가 편집이 :.이 잘못된 진술 토미의 답변을 참조하십시오.)은 벡터화되지 않은 상황에서 적법한 것이고 그 반대의 경우도 있습니까?

이 이해가 ifelse를 사용 할 수있는 예를 들어 있는가 비 벡터화 된 상황에서? 나는 우리가 작은 효율성 증가에 대해 신경 쓰지 않을 때 "가독성"이 유효한 대답 일 수 있다고 생각하지만, 그 외에도 if을 사용할 때 더 빠른/동등한 /보다 나은 다른 방식으로 ifelse을 사용하면됩니다. else이 작업을 수행합니까?

마찬가지로 벡터화 된 상황에서 ifelse은 항상 가장 유용한 도구입니까? 두 표현식 모두 평가되는 것이 이상하게 보입니다. 순차적으로 하나씩 반복하고 정상적으로 if을 수행 한 다음 else을 수행하는 것이 빠른가요? 표현을 평가하는 데 오랜 시간이 걸릴 때만 의미가 있다고 생각합니다. 명백한 루프를 포함하지 않는 다른 대안이 있습니까?

감사

답변

14

첫째, ifelse은하지 항상 두 표현식을 평가 수행 - 테스트 벡터에서 모두 TRUEFALSE 요소가있는 경우에만.

ifelse(TRUE, 'foo', stop('bar')) # "foo" 

그리고 내 생각에

는 :

ifelse하지는 벡터화되지 않은 상황에서 사용해야합니다. 그것은 항상 느린 더 오류가 발생하기 쉬운ifelse/elseif 이상 사용 :하지만 벡터화 된 상황에서

# This is fairly common if/else code 
if (length(letters) > 0) letters else LETTERS 

# But this "equivalent" code will yield a very different result - TRY IT! 
ifelse(length(letters) > 0, letters, LETTERS) 

, ifelse은 좋은 선택이 될 수 있습니다 -하지만 조심 결과의 길이 속성 수 있음 당신이 기대하는 것 (위와 같이, 나는 그 점에서 ifelse이라고 생각합니다)이 아닙니다.

예를 들면 다음과 같습니다. tst은 길이가 5이고 클래스가 있습니다. 나는 결과가 길이가 10이고 클래스가 없다고 기대할 것이다. 그러나 그것은 어떤 일이 일어나지 않는다. - 그것은 호환되지 않는 클래스와 길이 5를 얻는다.

# a logical vector of class 'mybool' 
tst <- structure(1:5 %%2 > 0, class='mybool') 

# produces a numeric vector of class 'mybool'! 
ifelse(tst, 101:110, 201:210) 
#[1] 101 202 103 204 105 
#attr(,"class") 
#[1] "mybool" 

왜 길이가 10 일 것으로 예상됩니까? R "주기"에있는 대부분의 기능은 짧은 벡터가 더 이상 일치하기 때문에 :

1:5 + 1:10 # returns a vector of length 10. 

...하지만 ifelse에만 사이클에게 예를/인수는 TST 인수의 길이와 일치 없습니다.

이 아닌 클래스 (및 다른 속성)가이 아닌 테스트 객체에서 복사되는 이유는 무엇입니까? 논리 벡터를 반환하는 <은 (일반적으로 숫자) 인수에서 클래스와 특성을 복사하지 않기 때문에. 그것은 일반적으로 매우 잘못 될 것이기 때문에 그렇게하지 않습니다.

1:5 < structure(1:10, class='mynum') # returns a logical vector without class 

마지막으로, "스스로해라"하는 것이 더 효율적일까요?글쎄, ifelseif과 같은 프리미티브가 아니며, NA을 처리하기 위해 특별한 코드가 필요합니다. NA이 없으면 직접 할 수 있습니다.

tst <- 1:1e7 %%2 == 0 
a <- rep(1, 1e7) 
b <- rep(2, 1e7) 
system.time(r1 <- ifelse(tst, a, b))   # 2.58 sec 

# If we know that a and b are of the same length as tst, and that 
# tst doesn't have NAs, then we can do like this: 
system.time({ r2 <- b; r2[tst] <- a[tst]; r2 }) # 0.46 secs 

identical(r1, r2) # TRUE 
+0

감사합니다. 지금은 이걸 볼 시간이 없지만 오늘 밤 나중에 할 것입니다. 의견 및 사례에 감사드립니다. –

+0

훌륭한 조언과 예제. 감사! –

+1

'ifelse'는 벡터 재활용을 수행합니다 -'yes' 또는'no' 변수 중 하나라도'test'와 길이가 같지 않으면 재활용됩니다. 즉, 예제의 끝에있는 테스트 코드는 모든 벡터의 길이가 동일한 경우에만 동일한 결과를 산출합니다. 예를 들어이 입력 데이터를보십시오 :'tst <- sample (c (TRUE, FALSE), 1e2, replace = TRUE); a <-1 : 100; b <- - (1:50); ' – Andrie

4

두 번째 요점은 "최고"를 어떻게 정의할까요? 나는 ifelse()가 더 읽기 쉬운 해결책 중 하나라고 생각하지만 항상 가장 빠를 수는 없습니다. 특히, 나는 부울 조건을 작성하고 함께 추가하면 성능 이점을 얻을 수 있음을 발견했습니다. 다음은 간단한 예입니다.

> x <- rnorm(1e6) 
> system.time(y1 <- ifelse(x > 0,1,2)) 
    user system elapsed 
    0.46 0.08 0.53 
> system.time(y2 <- (x > 0) * 1 + (x <= 0) * 2) 
    user system elapsed 
    0.06 0.00 0.06 
> identical(y1, y2) 
[1] TRUE 

속도가 가장 큰 관심사라면 부울 방식이 더 나을 수 있습니다. 그러나, 대부분의 나의 목적을 위해 - 나는 ifelse()을 충분히 빠르며 쉽게 찾을 수있다. 귀하의 마일리지는 분명히 다를 수 있습니다.

+0

부울 버전 작성에 부끄러움을 금치 못합니다. 빠르기 때문에가 아니라 31337이기 때문입니다. 하지만 일단 익숙해지면 코드는 if를 사용하는 코드만큼 쉽게 읽고 이해할 수 있습니다. –

+0

@Chase 좋은 점 –

+0

중복 테스트가 없기 때문에'y3 <- (x <= 0) + 1'을 사용하는 것이 더 빠릅니다. –

관련 문제