Kalkışa daha hızlı alternatif ()


9

Tekrarlanan çağrılara dayanan bir paket tutuyorum deparse(control = c("keepNA", "keepInteger")). controlher zaman aynıdır ve ifade değişir. deparse()aynı seçenek grubunu tekrar tekrar yorumlamak için çok zaman harcıyor gibi görünüyor .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

Bazı sistemlerde, gereksiz .deparseOpts()çağrılar aslında çalışma süresinin çoğunu alır deparse()( burada alev grafiği ).

Gerçekten sadece bir .deparseOpts()kez aramak ve daha sonra sayısal kodu tedarik etmek istiyorum deparse(), ama her .Internal()ikisi de bir paket geliştirme perspektifinden en uygun olan C kodu doğrudan çağırmadan veya çağırmadan imkansız görünüyor .

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>

Uygun bir çözüm var mı?

Yanıtlar:


4

1) .deparseOpts öğesinin kimlik işlevine eşit olacak şekilde değiştirilmiş bir sürümünü bulmak için ortamı sıfırlanmış bir çıkış kopyasını üreten bir işlevi tanımlayın. Gelen Runbiz daha sonra oluşturmak için bu işlevi çalıştırmak deparse2ve bu yürütün. Bu .Internaldoğrudan çalışmayı önler .

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

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

# test
Run()

2) Bunu yapmanın başka bir yolu da, değiştirilmiş bir kopyasını koymak ve kimlik fonksiyonu olarak deparseyeniden tanımlayan bu kopyaya bir iz eklemek için bir ortam oluşturan bir yapıcı işlevi tanımlamaktır .deparseOpts. Sonra o ortamı geri getirin. Daha sonra onu kullanan bir fonksiyonumuz var ve bu örnek Runiçin onu göstermek için bir fonksiyon yaratıp sadece yürütüyoruz Run. Bu kullanmak zorunda kalmaz.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) Üçüncü yaklaşım, varsayılan değeri olan ve varsayılan değeri 65 deparseolan yeni bir argüman ekleyerek yeniden tanımlamaktır ..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()

Vay canına, bu çok akıllı !!! Ben bunu hiç düşünemezdim! Gerçekten tüm sistemlerimde kıyaslamayı dört gözle bekliyorum!
landau

(1) 'i uygulayıp backtickargümanı önceden hesapladığımda, ayrılma 6 kat daha hızlı! Ben bununla gidiyorum. Geçici çözüm için çok teşekkürler!
landau

Hmm ... görünüşe göre, (1) tarafından üretilen fonksiyonlarda çağrıyı R CMD checktespit ediyor .Internal(). Etrafında çalışmak oldukça kolay, ihtiyacım var make_deparse()(expr, control = 64, backtick = TRUE). Her kullandığımda yolcuyı yeniden inşa etmek aptalca, ama yine de daha önce kullandığım saflıktan çok daha hızlı deparse().
landau

Benim için değil. (1) ' de sadece make_deparseve Runfonksiyonları ile bir paket oluşturmayı denedim ve koştum R CMD buildve R CMD check --as-cranaltında "R version 3.6.1 Patched (2019-11-18 r77437)"ve şikayet etmedi ve herhangi bir geçici çözüm gerekmedi. Farklı bir şey yapmadığınızdan veya buna neden olan bir şey yapmadığınızdan emin misiniz?
G. Grothendieck

1
Üst düzeyde tanımlayarak Kodunuzdaki neden oldu: direct_deparse <- make_direct_deparse(). Yanıtta gösterilen kod, bunu yapmamaya dikkat etti ve sadece bir işlev içinde, yani içinde tanımladı Run.
G. Grothendieck
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.