Thay thế nhanh hơn cho depough ()


9

Tôi duy trì một gói dựa trên các cuộc gọi lặp đi lặp lại deparse(control = c("keepNA", "keepInteger")). controlluôn luôn giống nhau, và biểu thức khác nhau. deparse()dường như dành nhiều thời gian để lặp đi lặp lại việc diễn giải cùng một bộ tùy chọn với .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

Trên một số hệ thống, các .deparseOpts()cuộc gọi dự phòng thực sự chiếm phần lớn thời gian chạy của deparse()( biểu đồ ngọn lửa ở đây ).

Tôi thực sự chỉ muốn gọi .deparseOpts()một lần và sau đó cung cấp mã số deparse(), nhưng điều đó dường như là không thể nếu không gọi .Internal()hoặc gọi trực tiếp mã C, cả hai đều không tối ưu theo quan điểm phát triển gói.

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>

Có một cách giải quyết thuận tiện?

Câu trả lời:


4

1) Xác định một hàm tạo ra một bản sao của môi trường đã được thiết lập lại để tìm phiên bản đã thay đổi của .deparseOpts đã được đặt bằng với chức năng nhận dạng. Trong Runchúng ta sau đó chạy mà chức năng để tạo ra một deparse2và thực hiện điều đó. Điều này tránh chạy .Internaltrực tiếp.

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

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

# test
Run()

2) Một cách khác để làm điều này là xác định hàm xây dựng tạo môi trường để đặt một bản sao đã sửa đổi deparsevà thêm dấu vết vào bản sao đó xác định lại .deparseOptslàm hàm nhận dạng. Sau đó trả lại môi trường đó. Sau đó chúng ta có một số hàm sử dụng nó và với ví dụ này, chúng ta tạo một hàm Runđể thể hiện nó và sau đó chỉ cần thực thi Run. Điều này tránh phải sử dụng.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) Cách tiếp cận thứ ba là xác định lại deparsebằng cách thêm một đối số mới sẽ đặt .deparseOptsmặc định identityvà đặt controlmặc định là 65.

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

Wow, thật là thông minh !!! Tôi chưa bao giờ nghĩ về điều đó! Thực sự mong được điểm chuẩn trên tất cả các hệ thống của tôi!
Landau

Khi tôi áp dụng (1) và tính toán trước backtickđối số, depars nhanh hơn 6 lần! Tôi đang đi với điều đó. Cảm ơn rất nhiều cho cách giải quyết!
Landau

Hmm ..., rõ ràng, R CMD checkphát hiện .Internal()cuộc gọi trong các chức năng được tạo bởi (1). Khá dễ dàng để làm việc xung quanh, tôi chỉ cần make_deparse()(expr, control = 64, backtick = TRUE). Thật ngớ ngẩn khi tái tạo lại bộ khử mùi mỗi khi tôi sử dụng nó, nhưng nó vẫn nhanh hơn nhiều so với sự ngây thơ deparse()mà tôi đang sử dụng trước đây.
Landau

Không dành cho tôi. Tôi đã cố gắng tạo ra một gói với chỉ make_deparseRunchức năng trong (1) và ran R CMD buildR CMD check --as-crandưới "R version 3.6.1 Patched (2019-11-18 r77437)"và nó đã không phàn nàn và tôi không cần bất kỳ cách giải quyết. Bạn có chắc chắn rằng bạn không làm điều gì đó khác biệt hoặc ngoài ra đang gây ra điều này?
G. Grothendieck

1
Nó được gây ra bởi mã của bạn xác định nó ở cấp cao nhất : direct_deparse <- make_direct_deparse(). Mã được hiển thị trong câu trả lời là cẩn thận không làm điều đó và chỉ xác định nó trong một hàm, tức là bên trong Run.
G. Grothendieck
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.