2009-07-23 4 views

Antwort

2

Für Schleifen in R sind notorisch langsam, aber hier ist es ein anderes Thema. Es ist viel schneller, den Ergebnisvektor res vorzugeben, res, sondern an res bei jeder Iteration anzuhängen.

Unten können wir die Geschwindigkeit der obigen Version mit einer Version vergleichen, die einfach mit einem Vektor, res, der Länge N beginnt und das i-te Element während der Schleife ändert.

fn1 <- function(N) { 
    res <- c() 
    for (i in 1:N) { 
    x <- rnorm(2) 
    res <- c(res,x[2]-x[1]) 
    } 
    res 
} 
fn2 <- function(N) { 
    res <- rep(0,N) 
    for (i in 1:N) { 
    x <- rnorm(2) 
    res[i] <- x[2]-x[1] 
    } 
    res 
} 
> N <- 50000 
> system.time(res1 <- fn1(N)) 
    user system elapsed 
    6.568 0.256 6.826 
> system.time(res2 <- fn2(N)) 
    user system elapsed 
    0.452 0.004 0.496 

Auch als Sharpie points out, können wir dies etwas schneller machen, indem unter Verwendung von R-Funktionen wie apply (oder seine Verwandten, sapply und lapply).

fn3 <- function(N) { 
    sapply(1:N, function(i){ x <- rnorm(2); return(x[2] - x[1]) }) 
} 
> system.time(res3 <- fn3(N)) 
    user system elapsed 
    0.397 0.004 0.397 
+0

Was mit der zweiten Antwort falsch ist, dass R Liste thread: res <- rnorm (10^6) -rnorm (10^6)? – ars

+0

@ars: Sie haben absolut Recht - das gibt die schnellste Lösung (um eine Größenordnung). Der beste Rat wäre 1. Verwenden Sie Funktionen, die natürlich auf Vektoren arbeiten (wie rnorm); 2. Wenn das nicht möglich ist, verwenden Sie eine * apply-Funktion; 3. Wenn das nicht möglich ist, verwenden Sie eine for-Schleife mit Vorbelegung. –

9

Die Effizienz der Schleifen kann als Looping durch sie auf einmal und nicht enorm in R durch die Verwendung der Funktionen anwenden erhöht werden, die im wesentlichen ganzen Vektoren von Daten verarbeiten. Für die Schleife oben gezeigt, gibt es zwei grundlegende Operationen während jeder Iteration geschieht:

# A vector of two random numbers is generated 
x <- rnorm(2) 

# The difference between those numbers is calculated 
x[2] - x[1] 

In diesem Fall wird die entsprechende Funktion sapply() wäre. sapply() arbeitet auf einer Liste von Objekten, wie beispielsweise der Vektor, der durch die Schleifenanweisung erzeugt 1:N und liefert einen Vektor der Ergebnisse:

sapply(1:N, function(i){ x <- rnorm(2); return(x[2] - x[1]) }) 

anzumerken, dass der Indexwert i während der Funktionsaufruf zur Verfügung und nimmt nacheinander auf den Werten zwischen 1 und N, jedoch ist es in diesem Fall nicht erforderlich.

Der Einstieg in die Gewohnheit, zu erkennen, wo apply kann über for verwendet werden, ist eine sehr wertvolle viele R-Bibliotheken für parallele Berechnung bieten Plug-and-Play-Parallelisierung durch apply Funktionen qualifikations. Die Verwendung von apply kann oft den Zugriff auf signifikante Leistungssteigerungen auf Multicore-Systemen mit null Refactoring von Code ermöglichen.

2

Manchmal wird keine Schleife benötigt. Da rnorm iid Probe (theoretisch) gibt, werden Sie das gleiche Ergebnis erzielen (Sampling X-Y wobei X und Y N (0,1)), indem Sie:

res <- rnorm(N)-rnorm(N) 
4

Aufbauend auf meinen Kommentar zu chris_dubois Antwort, hier ist einige Timing-Informationen:

> system.time(res <- rnorm(50000) - rnorm(50000)) 
user system elapsed 
0.06 0.00 0.06 

Kontrast dies mit fn3 aus derselben Antwort:

> system.time(res3 <- fn3(50000)) 
user system elapsed 
1.33 0.01 1.36 

Die erste Sache ist, dass meine Runde zu bemerken top ist langsamer als chris_dubois 'Maschine.:)

Der zweite und wichtigere Punkt ist, dass der Vektor Ansatz, ganz hier anwendbar, eine Größenordnung schneller ist. (Auch von Richie Cotton in einem Kommentar zu derselben Antwort darauf hingewiesen).

Das bringt mich zum letzten Punkt: Es ist ein Mythos dass apply und seine Freunde sind viel schneller als for Schleifen in R. Sie in der gleichen Größenordnung sind in den meisten Messungen ich gesehen habe. Weil sie nur for Loops hinter den Kulissen sind. Siehe auch diesen Beitrag:

http://yusung.blogspot.com/2008/04/speed-issue-in-r-computing-apply-vs.html

Professor Brian Ripley Laut "apply() ist nur ein Wrapper für eine Schleife." Der einzige Vorteil für die Verwendung von apply() ist, dass es Ihren Code sauberer macht!

Genau. Sie sollten apply verwenden, wenn es mehr expressive ist, besonders wenn Sie in einem funktionalen Stil programmieren. Nicht weil es schneller ist.

+0

Gute Punkte. Meine ursprüngliche Absicht für diese Frage war es, die Idee zu unterstreichen, dass Vorallokation eine gute Sache sein kann. Wie Sie bereits gesagt haben, kann dieses spezielle Beispiel einfach mit Vektoroperationen durchgeführt werden. Es wäre schön, ein paar andere Beispiele zu haben, wo Leute Alternativen zur Optimierung von R-Code zeigen (ähnlich wie http://wiki.r-project.org/rwiki/doku.php?id=tips:programming:code_optim2&s=optimization). Gedanken? –

+0

Hey, das ist eine gute Idee - ich kenne dieses Wiki leider nicht. Ich weiß, dass ich auf eine paar Schleifen zu Vektoroptimierungen gestoßen bin, indem ich Code gelesen habe, der von anderen geschrieben wurde - zuletzt habe ich einen Code von Hagerty zum Konstruieren von Variogrammen gesehen. Ich neige dazu, anzunehmen, dass es allgemein bekannt ist und für andere nicht bemerkenswert ist, aber es ist besser, auf der Seite des Dokumentierens zu irren. Ich werde meine Dateien durchgehen und etwas Bestimmtes finden, das ich hoffentlich bis zum Wochenende ins Wiki einfügen kann. Hast du irgendwelche Gedanken darüber, wie du es strukturierst? Sollten wir nur eine "Vektorisierungstipps" -Seite erstellen und sie bei Bedarf ausbrechen? – ars

+1

'apply' könnte so schnell wie eine for-Schleife sein, aber' lapply' und (besonders) 'vapply' sind in der Regel schneller, da sie in C implementiert sind und den Aufruf der Funktion' FUN' optimiert haben. Aber das ist nur wichtig, wenn die tatsächliche Zeit in 'FUN' gering ist. – Tommy

0

Vielleicht wäre der effizienteste Ersatz für Ihre Funktion einfach sein:

fn <- function(n) rnorm(N,0,sqrt(2)) 

die als Einnahme Unterschied von iid normalen variates doppelt so schnell ist. Allgemeiner gesagt, wenn Ihr Ziel einfache Simulationen ist, beschleunigen Vektor-/Array-Vorbelegung und Aufrufe von nativen Funktionen den Prozess erheblich.

Wenn Sie Monte-Carlo-Simulationen für statistische Schätzungen (zum Beispiel MCMC) ausgeführt werden sollen, hat R eine Reihe von nativen Paketen. Für die allgemeine stochastische Simulation sind mir keine R-Pakete bekannt, aber Sie könnten Simpy (http://simpy.sourceforge.net/) ausprobieren, was ausgezeichnet ist.