deparse ()에 대한 빠른 대안


9

에 대한 반복 호출에 의존하는 패키지를 유지 관리합니다 deparse(control = c("keepNA", "keepInteger")). control항상 동일하며 표현이 다릅니다. deparse()와 동일한 옵션 세트를 반복적으로 해석하는 데 많은 시간을 소비하는 것 같습니다 .deparseOpts().

microbenchmark::microbenchmark(
    a = deparse(identity, control = c("keepNA", "keepInteger")),
    b = .deparseOpts(c("keepNA", "keepInteger"))
)
# Unit: microseconds
# expr min  lq  mean median  uq  max neval
#    a 7.2 7.4 8.020    7.5 7.6 55.1   100
#    b 3.0 3.2 3.387    3.4 3.5  6.0   100

일부 시스템에서는 중복 .deparseOpts()호출이 실제로 대부분의 런타임 deparse()( 화염 그래프 여기 )을 차지합니다 .

실제로 .deparseOpts()한 번만 호출 한 다음 숫자 코드를에 제공 deparse()하고 싶지만 .Internal()C 코드를 직접 호출 하거나 호출 하지 않으면 불가능한 것처럼 보입니다. 이 중 어느 것도 패키지 개발 관점에서 최적이 아닙니다.

deparse
# function (expr, width.cutoff = 60L, backtick = mode(expr) %in% 
#     c("call", "expression", "(", "function"), 
#     control = c("keepNA", "keepInteger", "niceNames", 
#         "showAttributes"), nlines = -1L) 
# .Internal(deparse(expr, width.cutoff, backtick, .deparseOpts(control), 
#     nlines))
# <bytecode: 0x0000000006ac27b8>
# <environment: namespace:base>

편리한 해결 방법이 있습니까?

답변:


4

1) 식별 기능과 동일하게 설정된 .deparseOpts의 변경된 버전을 찾기 위해 환경이 재설정 된 출발의 사본을 생성하는 함수를 정의하십시오. 에서 Run우리는 다음을 만들기 위해 그 기능을 실행 deparse2하고 실행합니다. 이것은 .Internal직접 실행을 피 합니다.

make_deparse <- function() {
  .deparseOpts <- identity
  environment(deparse) <- environment()
  deparse
}

Run <- function() {
  deparse2 <- make_deparse()
  deparse2(identity, control = 65)
}

# test
Run()

2) 이를 수행하는 또 다른 방법은 수정 된 사본의 사본을 넣을 환경을 작성하고 deparse해당 사본에 정의 .deparseOpts기능을 식별 하는 추적을 추가하는 생성자 함수를 정의하는 것입니다. 그런 다음 해당 환경을 반환하십시오. 그런 다음이를 사용하는 함수 Run가 있으며이 예제에서는이를 설명 하는 함수 를 만든 다음 실행하면 Run됩니다. 이것은 사용을 피합니다.Internal

make_deparse_env <- function() {
  e <- environment()
  deparse <- deparse
  suppressMessages(
    trace("deparse", quote(.deparseOpts <- identity), print = FALSE, where = e)
  )
  e
}

Run <- function() {
  e <- make_deparse_env()
  e$deparse(identity, control = 65)
}

# test
Run()

3) 세 번째 방법은 기본값 을 갖도록 설정하고 기본값을 65로 deparse설정하는 새 인수를 추가 하여 재정의 하는 것 입니다..deparseOptsidentitycontrol

make_deparse65 <- function() {
  deparse2 <- function (expr, width.cutoff = 60L, backtick = mode(expr) %in% 
    c("call", "expression", "(", "function"), 
    control = 65, nlines = -1L, .deparseOpts = identity) {}
  body(deparse2) <- body(deparse)
  deparse2
}

Run <- function() {
  deparse65 <- make_deparse65()
  deparse65(identity)
}

# test
Run()

와우, 너무 영리 해요 !!! 나는 그것을 생각하지 않았을 것입니다! 모든 시스템에서 벤치마킹을 기대합니다!
landau

내가 (1)을 적용하고 backtick인수를 사전 계산하면 구문 분석이 6 배 빨라집니다! 나는 그걸로 갈거야. 해결 방법에 대해 대단히 감사합니다!
landau

흠 ... 은 (1)에 의해 생성 된 함수 R CMD check.Internal()호출을 감지합니다 . 해결하기가 매우 쉽습니다 make_deparse()(expr, control = 64, backtick = TRUE). 사용할 때마다 구분자를 재구성하는 것은 어리석은 일이지만, deparse()이전에 사용 했던 순진한 것보다 훨씬 빠릅니다 .
landau

나를 위해 아닙니다. 난 그냥 함께 패키지를 만드는 시도 make_deparseRun기능 (1) 및 RAN R CMD buildR CMD check --as-cran에서 "R version 3.6.1 Patched (2019-11-18 r77437)"그것은 불평하지 않았고 내가 대안을 필요로하지 않았다. 다른 작업을하지 않거나 추가로이 문제를 일으키는 것이 확실합니까?
G. Grothendieck

1
코드가 최상위 수준에서 코드를 정의했기 때문에 발생했습니다 direct_deparse <- make_direct_deparse(). 답변에 표시된 코드는 그렇게하지 않도록주의하고 함수 내에서만 정의했습니다 Run.
G. Grothendieck
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.