2012-04-20 11 views
6

Ho un problema che mi coinvolge avvolgendo un ciclo while su un po 'di codice che credo possa essere vettorializzato in modo efficiente. Tuttavia, ad ogni passaggio, la mia condizione di arresto si basa sul valore in quella fase. Considerare questo esempio come un modello rappresentativo del mio problema:
Generare variabili casuali N (0,1) utilizzando rnorm() finché non si campiona un valore maggiore di un valore arbitrario, k.Esiste un metodo più efficiente rispetto ai cicli while per qualcosa che richiede il controllo condizionale?

EDIT: Un avvertimento del mio problema, discusso nei commenti, è che non posso sapere, a priori, una buona approssimazione di quanti campioni prendere prima della mia condizione di arresto.

Un approccio:

  1. Utilizzando un ciclo while, campioni opportunamente dimensionati normali vettori casuali (per esempio, rnorm(50) campionare 50 normali standard in un momento o rnorm(1) se k è vicino a zero). Controlla questo vettore per vedere se qualche osservazione è maggiore di k.

  2. Se sì, interrompere e restituire tutti i valori precedenti. In caso contrario, combinare il vettore dal punto 1 con un nuovo vettore di effettuare ripetendo il passaggio 1.

Un altro approccio sarebbe quello di specificare un numero eccessivo di completamente casuale disegna per quel dato k. Questo potrebbe significare se k = 2, campionare 1.000 variabili casuali normali usando rnorm(1000).

Sfruttando la vettorizzazione che R offre nel secondo caso dà risultati più veloci rispetto alla versione loop nei casi in cui il numero di overkill non è troppo più grande del necessario, ma nel mio problema, non ho una buona intuizione per come molte corse che devo fare, quindi dovrei essere prudente.

La domanda segue: Esiste un modo per eseguire una procedura altamente vettoriale, come il metodo 2, ma utilizzando il controllo condizionale come il metodo 1? Sta facendo piccole operazioni vettorializzate come rnorm(50) il modo "più veloce", se si considera che il metodo altamente vettoriale è elemento-per-elemento più veloce, ma più dispendioso?

+1

Non sono sicuro di quanto bene chiunque sarà in grado di rispondere a questa, dal momento che il codice vettorizzazione R richiede in genere la conoscenza abbastanza dettagliata di tutto il blocco di codice si sta cercando di migliorare. – joran

+0

Il codice stesso è vettorizzato, ma la mia condizione di arresto implica il controllo di ogni elemento, quindi sto perdendo molto del vantaggio di avere il codice completamente vettoriale. Speravo in un trucco R chiarificato che desse la velocità della suite 'apply', ma mi permette di fermarmi una volta che ho colpito le mie condizioni. –

+0

Usa il tuo terzo approccio. Non hai bisogno di un numero eccessivo di estrazioni. Conoscete la distribuzione e il valore che volete essere maggiore di, quindi conoscete la probabilità di campionare quel numero. Per esempio. se 'k = 3' allora dovresti ottenere ~ 3 numeri maggiori di' k' se esegui 'rnorm (1e3)'. 'which (rnorm (1e3))' ti dice il primo elemento che corrisponde. –

risposta

1

Ecco una implementazione del mio precedente suggerimento: usa il tuo primo approccio ma aumenta il numero di nuovi campioni tra ogni iterazione, ad esempio, invece di 50 nuovi campioni ad ogni iterazione, moltiplica il numero per due tra ciascuna iterazione: 50, quindi 100, 200, 400, ecc.

Con le dimensioni del campione che seguono una serie geometrica divergente, è possibile uscire in "poche" iterazioni.

sample.until.thresh <- function(FUN, exit.thresh, 
           sample.start = 50, 
           sample.growth = 2) { 

    sample.size <- sample.start 
    all.values  <- list() 
    num.iterations <- 0L 

    repeat { 
     num.iterations <- num.iterations + 1L 
     sample.values <- FUN(sample.size) 
     all.values[[num.iterations]] <- sample.values 

     above.thresh <- sample.values > exit.thresh 
     if (any(above.thresh)) { 
     first.above <- match(TRUE, above.thresh) 
     all.values[[num.iterations]] <- sample.values[1:first.above] 
     break 
     } 

     sample.size <- sample.size * sample.growth 
    } 

    all.values <- unlist(all.values) 

    return(list(num.iterations = num.iterations, 
       sample.size = length(all.values), 
       sample.values = all.values)) 
} 

set.seed(123456L) 
res <- sample.until.thresh(rnorm, 5) 
res$num.iterations 
# [1] 16 
res$sample.size 
# [1] 2747703 
+0

Questo è davvero un approccio molto carino. Aumentando incrementalmente la quantità che vettorializzo funziona abbastanza bene quando non so quanti campioni ho bisogno. Grazie! –

Problemi correlati