2013-01-23 15 views
9

Ho definito una funzione personalizzata, in questo modo:Ripetizione di una funzione definita dall'utente utilizzando replicare() o sapply()

my.fun = function() { 

     for (i in 1:1000) { 
     ... 
     for (j in 1:20) { 
      ... 
     } 
     } 

return(output) 

} 

che restituisce una matrice di uscita, output, composta da 1000 righe e 20 colonne.

Che cosa devo fare è ripetere la funzione di dire 5 volte e per memorizzare i cinque output risultati in una nuova matrice di zecca, dicono final, ma senza l'utilizzo di un altro ciclo for (questo per rendere il codice più chiaro, e anche perché in un secondo momento vorrei provare a parallelizzare queste ulteriori 5 ripetizioni).

Quindi final dovrebbe essere una matrice con 5000 righe e 20 colonne (la logica dietro queste 5 ripetizioni è che all'interno dei due cicli forali utilizzo, tra le altre funzioni, sample).

Ho provato a utilizzare final <- replicate(5, my.fun()), che calcola correttamente le cinque repliche, ma poi devo "manualmente" inserire gli elementi in una nuova matrice 5000 x 20. C'è un modo più elastico per farlo? (forse usando sapply()?). Molte grazie

risposta

11

Così com'è, probabilmente si dispone di un array con tre dimensioni. Se volessi avere una lista, avresti aggiunto semplifica = FALSO. Prova questo:

do.call(rbind, replicate(5, my.fun(), simplify=FALSE)) 

Oppure si può utilizzare aperm nel caso in cui "finale" è ancora un array:

fun <- function() matrix(1:10, 2,5) 
final <- replicate(2, fun()) 
> final 
, , 1 

    [,1] [,2] [,3] [,4] [,5] 
[1,] 1 3 5 7 9 
[2,] 2 4 6 8 10 

, , 2 

    [,1] [,2] [,3] [,4] [,5] 
[1,] 1 3 5 7 9 
[2,] 2 4 6 8 10 

> t(matrix(aperm(final, c(2,1,3)), 5,4)) 
    [,1] [,2] [,3] [,4] [,5] 
[1,] 1 3 5 7 9 
[2,] 2 4 6 8 10 
[3,] 1 3 5 7 9 
[4,] 2 4 6 8 10 

Ci possono essere operazioni di matrice più economiche. Non l'ho ancora scoperto.

+0

Molte grazie per l'aiuto. A proposito, riguardo all'array delle tre dimensioni, avevi ragione :) – Stezzo

7

Se si sostituisce replicate con rlply dal pacchetto plyr, è possibile utilizzare do.call con rbind:

library(plyr) 
do.call(rbind, rlply(5, my.fun())) 

Se si preferisce non fare affidamento sulla confezione plyr, si può sempre fare:

do.call(rbind, lapply(1:5, function(i) my.fun())) 
7

Dipende dal pacchetto che si utilizza per il calcolo parallelo, ma ecco come lo farei (nasconderlo in un ciclo utilizzando sapply, proprio come replicate).

library(snowfall) 
sfInit(parallel = TRUE, cpus = 4, type = "SOCK") 
# sfExport() #export appropriate objects that will be needed inside a function, if applicable 
# sfLibrary() #call to any special library 
out <- sfSapply(1:5, fun = my.fun, simplify = FALSE) 
sfStop() 
+0

Grazie mille, questo è molto interessante, e dal modo in cui stavo progettando di usare 'nevicata'. – Stezzo

0

Prova questo:

final <- replicate(5, my.fun(), simplify = "matrix") 

si otterrà il risultato di 'finale' in forma di matrice.

Problemi correlati