2015-02-04 10 views
10

Approccio 1Quali sono i vantaggi di definire e chiamare una funzione all'interno di un'altra funzione in R?

f1 <- function(x) 
{ 
    # Do calculation xyz .... 

    f2 <- function(y) 
    { 
     # Do stuff... 
     return(some_object) 
    } 

    return(f2(x)) 
} 

Approach 2

f2 <- function(y) 
{ 
    # Do stuff... 

    return(some_object) 
} 

f3 <- function(x) 
{ 
    # Do calculation xyz .... 
    return(f2(x)) 
} 

assumere f1 e f3 sia fare gli stessi calcoli e dare lo stesso risultato.

Esistono significativi vantaggi nell'utilizzo di approccio 1, chiamando f1(), vs approccio 2, chiamando f3()?

è un certo approccio più favorevole:

  • grandi quantità di dati viene passato in e/o fuori f2?

  • La velocità è un grosso problema. Per esempio. f1 o f3 vengono richiamati ripetutamente nelle simulazioni.

(Approccio 1 sembra comune in confezioni, definente al suo interno un altro)

Un vantaggio di utilizzare l'approccio f1 è che f2 non esisterà fuori f1 volta f1 abbia finito di essere chiamato (e f2 è solo chiamato in f1 o f3).

risposta

8

vantaggi di definire f2 all'interno f1:

  • f2 visibile solo all'interno f1, utile se f2 serve solo per l'uso all'interno f1, anche se all'interno di spazi dei nomi di pacchetti che questo è discutibile dal momento che proprio non avrebbe esportare f2 se lo hai definito all'esterno
  • f2 ha accesso alle variabili entro f1, che può essere considerato una cosa buona o una cattiva:
    • buona, perché non c'è bisogno di passare le variabili attraverso la funzione di interfaccia ed è possibile utilizzare <<- per implementare cose come Memoizzazione, ecc
    • male, per le stesse ragioni ...

Svantaggi:

  • f2 deve essere ridefinito ogni volta che si chiama f1, che aggiunge un po 'di testa (non molto in alto, ma sicuramente ci)

La dimensione dei dati non dovrebbe avere importanza poiché R non copierà i dati a meno che non vengano modificati in nessuno dei due scenari.Come osservato negli svantaggi, la definizione di f2 al di fuori di f1 dovrebbe essere un po 'più veloce, soprattutto se si sta ripetendo un'operazione di sovraccarico altrimenti relativamente bassa molte volte. Ecco un esempio:

> fun1 <- function(x) { 
+ fun2 <- function(x) x 
+ fun2(x) 
+ } 
> fun2a <- function(x) x 
> fun3 <- function(x) fun2a(x) 
> 
> library(microbenchmark) 
> microbenchmark(
+ fun1(TRUE), fun3(TRUE) 
+) 
Unit: nanoseconds 
     expr min lq median uq max neval 
fun1(TRUE) 656 674.5 728.5 859.5 17394 100 
fun3(TRUE) 406 434.5 480.5 563.5 1855 100 

In questo caso si risparmia 250ns (edit: la differenza è in realtà 200ns, ci crediate o no il set supplementare di {} che fun1 ha costi un altro 50ns). Non molto, ma può essere aggiunto se la funzione interna è più complessa o se si ripete la funzione molte volte.

5

viene in genere utilizzato approccio 2. Alcune eccezioni sono

  1. chiusure di funzione:

    f = function() { 
        counter = 1 
        g = function() { 
         counter <<- counter + 1 
         return(counter) 
        } 
    } 
    counter = f() 
    counter() 
    counter() 
    

    chiusura funzione ci permette di ricordare lo stato.

  2. A volte è utile definire solo le funzioni poiché vengono utilizzate solo in un unico punto. Ad esempio, quando si utilizza optim, spesso si modifica una funzione esistente. Ad esempio,

    pdf = function(x, mu) dnorm(x, mu, log=TRUE) 
    f = function(d, lower, initial=0) { 
        ll = function(mu) { 
        if(mu < lower) return(-Inf) 
        else -sum(pdf(d, mu)) 
        } 
        optim(initial, ll) 
    } 
    
    f(d, 1.5) 
    

    La funzione ll utilizza i dati impostati d e un limite inferiore. Questo è sia conveniente in quanto potrebbe essere l'unica volta che usiamo/abbiamo bisogno della funzione ll.

Problemi correlati