'vapply'가 'sapply'보다 안전한 이유는 무엇입니까?


84

문서에 따르면

vapply와 유사 sapply하지만 미리 지정된 반환 값 유형이 있으므로 사용하는 것이 더 안전 할 수 있습니다 [...].

일반적으로 더 안전한 이유에 대해 설명해 주시겠습니까?


추신 : 나는 답을 알고 있고 이미 피하는 경향이 sapply있습니다. 여기에 좋은 대답이 있었으면 좋겠어요. 그래서 동료들에게 그것을 가리킬 수 있습니다. 제발 "매뉴얼을 읽어라"라고 대답하지 마십시오.


1
더 예측 가능하여 코드가 덜 모호하고 더 강력 해집니다. 특히 대규모 프로젝트 (예 : 대규모 패키지)에서는 관련이 있습니다.
Paul Hiemstra 2012 년

1
FUN.VALUE의 vapply 수동 예제는 sapply 사용자에게 매우 복잡하고 위협적입니다.
jsta 2016

답변:


73

이미 언급했듯이 vapply두 가지 작업을 수행합니다.

  • 약간의 속도 향상
  • 제한된 반환 유형 검사를 제공하여 일관성을 향상시킵니다.

두 번째 요점은 오류가 발생하기 전에 발견하고 더 강력한 코드로 이어지기 때문에 더 큰 이점입니다. 이 반환 값 검사 는 반환 값이 예상 한 것과 일치하는지 확인하기 위해 sapplyfollowed 를 사용하여 개별적으로 수행 할 수 stopifnot있지만 vapply조금 더 쉽습니다 (사용자 지정 오류 검사 코드가 범위 내의 값을 검사 할 수 있기 때문에 더 제한적일 경우 등). ).

다음 vapply은 결과가 예상대로인지 확인 하는 예입니다 . 이것은 PDF 스크래핑 중에 방금 작업 한 것과 유사 findD합니다.원시 텍스트 데이터의 패턴을 일치시키기 위해 (예 : split엔티티 별 목록이 있고 각 엔티티 내의 주소와 일치하는 정규식이 있습니다. 간혹 PDF가 순서가 맞지 않게 변환되어 불량을 일으킨 엔티티).

> input1 <- list( letters[1:5], letters[3:12], letters[c(5,2,4,7,1)] )
> input2 <- list( letters[1:5], letters[3:12], letters[c(2,5,4,7,15,4)] )
> findD <- function(x) x[x=="d"]
> sapply(input1, findD )
[1] "d" "d" "d"
> sapply(input2, findD )
[[1]]
[1] "d"

[[2]]
[1] "d"

[[3]]
[1] "d" "d"

> vapply(input1, findD, "" )
[1] "d" "d" "d"
> vapply(input2, findD, "" )
Error in vapply(input2, findD, "") : values must be length 1,
 but FUN(X[[3]]) result is length 2

제가 학생들에게 말했듯이 프로그래머가되는 것은 당신의 사고 방식을 "오류는 성가시다"에서 "오류는 내 친구"로 바꾸는 것입니다.

길이가 0 인 입력
한 가지 관련된 점은 입력 길이가 0이면 sapply입력 유형에 관계없이 항상 빈 목록을 반환한다는 것입니다. 비교:

sapply(1:5, identity)
## [1] 1 2 3 4 5
sapply(integer(), identity)
## list()    
vapply(1:5, identity)
## [1] 1 2 3 4 5
vapply(integer(), identity)
## integer(0)

를 사용하면 vapply특정 유형의 출력이 보장되므로 길이가 0 인 입력에 대해 추가 검사를 작성할 필요가 없습니다.

벤치 마크

vapply 결과가 예상되는 형식을 이미 알고 있기 때문에 조금 더 빠를 수 있습니다.

input1.long <- rep(input1,10000)

library(microbenchmark)
m <- microbenchmark(
  sapply(input1.long, findD ),
  vapply(input1.long, findD, "" )
)
library(ggplot2)
library(taRifx) # autoplot.microbenchmark is moving to the microbenchmark package in the next release so this should be unnecessary soon
autoplot(m)

자동 플롯


15

과 관련된 추가 키 입력 vapply은 나중에 혼란스러운 결과를 디버깅하는 시간을 절약 할 수 있습니다. 호출하는 함수가 다른 데이터 유형을 반환 할 수 있다면 vapply반드시 사용해야합니다.

떠오르는 한 가지 예 sqlQueryRODBC패키지에 있습니다. 쿼리를 실행하는 동안 오류가 발생하면이 함수는 character메시지와 함께 벡터를 반환 합니다. 예를 들어, 테이블 이름 벡터를 반복하고 tnames각 테이블의 숫자 열 'NumCol'에서 최대 값을 다음과 같이 선택한다고 가정합니다.

sapply(tnames, 
   function(tname) sqlQuery(cnxn, paste("SELECT MAX(NumCol) FROM", tname))[[1]])

모든 테이블 이름이 유효하면 numeric벡터 가 생성됩니다 . 그러나 테이블 이름 중 하나가 데이터베이스에서 변경되고 쿼리가 실패하면 결과가 모드로 강제 변환됩니다 character. 그러나 vapplywith를 사용하면 FUN.VALUE=numeric(1)여기에서 오류가 중지되고 줄 아래 어딘가에 표시되는 것을 방지 할 수 있습니다.


13

당신이 항상 당신의 결과가 특별한 무언가가되기를 원한다면… vapply이것이 발생하는지 확인하지만 sapply반드시 그런 것은 아닙니다.

a<-vapply(NULL, is.factor, FUN.VALUE=logical(1))
b<-sapply(NULL, is.factor)

is.logical(a)
is.logical(b)

4
내가 할 수있는 가장 확실한 것은 생각 logical(1)좋아 FALSE 보이는 유형 지정하는 대신 "OFF"에 대한 옵션을 설정으로,이 경우에는
비행 양
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.