Zeitfunktionen in R [geschlossen]

36
  1. Ich möchte die Zeit messen, die benötigt wird, um die Ausführung einer Funktion zu wiederholen. Sind replicate()und benutzen for-Schleifen gleichwertig? Beispielsweise:

    system.time(replicate(1000, f()));
    system.time(for(i in 1:1000){f()});
    

    Welches ist die bevorzugte Methode.

  2. In der Ausgabe von system.time(), ist sys+userdie tatsächliche CPU - Zeit , um das Programm zum Laufen? Ist elapsedein gutes Maß für die Zeitleistung des Programms?

Tim
quelle
3
Nur zur Veranschaulichung, da ich eindeutig viel zu spät bin, um den Kurs dieser Frage zu ändern: Dies ist die Art von Problem, die meiner Meinung nach am besten für StackOverflow geeignet ist.
Matt Parker
2
@Matt Ich bin damit einverstanden, dass Fragen, wie einmal ein Programm ist, gut für SO geeignet sind. Ich stimme auch zu, dass eine wörtliche Interpretation dieser Frage (wie sie in mehreren Antworten enthalten ist) sie hier im Lebenslauf nicht zum Thema machen würde. Es scheint jedoch ein gewisses statistisches Interesse daran zu bestehen , ein Timing-Experiment zu entwerfen und die Ergebnisse eines solchen Experiments zu analysieren .
whuber

Antworten:

19

Für ein effektives Timing von Programmen, insbesondere wenn Sie alternative Lösungen vergleichen möchten, benötigen Sie eine Steuerung! Ein guter Weg ist, die Prozedur, die Sie planen, in eine Funktion umzuwandeln. Rufen Sie die Funktion innerhalb einer Zeitschleife auf. Schreiben Sie eine Stub-Prozedur, indem Sie im Wesentlichen den gesamten Code aus Ihrer Funktion entfernen und einfach von dieser zurückkehren (lassen Sie jedoch alle Argumente in). Setzen Sie den Stub in Ihre Timing-Schleife ein und wiederholen Sie die Zeit. Hiermit wird der gesamte mit dem Timing verbundene Overhead gemessen. Subtrahieren Sie die Stichzeit von der Eingriffszeit, um das Netz zu erhalten: Dies sollte ein genaues Maß für die tatsächlich benötigte Zeit sein.

Da die meisten Systeme heutzutage ständig unterbrochen werden können, ist es wichtig, mehrere Zeitabläufe durchzuführen, um die Variabilität zu überprüfen. Anstatt einen langen Lauf von Sekunden zu machen, mache Läufe von jeweils etwa Sekunden. Es hilft, dies in einer Doppelschleife auf einmal zu tun. Dies ist nicht nur einfacher zu handhaben, es führt auch ein wenig negative Korrelation in jede Zeitreihe ein, wodurch die Schätzungen tatsächlich verbessert werden.NmN/m

Durch die Verwendung dieser Grundprinzipien des experimentellen Entwurfs können Sie im Wesentlichen die Unterschiede kontrollieren, die sich aus der Bereitstellung des Codes ergeben (z. B. den Unterschied zwischen einer for-Schleife und replicate ()). Das lässt dein Problem verschwinden.

whuber
quelle
25

In Bezug auf Ihre zwei Punkte:

  1. Es ist stilistisch. Ich mag, replicate()wie es funktioniert.
  2. Ich neige dazu, mich auf elapseddie dritte Zahl zu konzentrieren.

Was ich oft mache ist

N <- someNumber
mean(replicate( N, system.time( f(...) )[3], trimmed=0.05) )

um einen gekürzten Mittelwert von 90% von N Wiederholungen des Anrufens zu erhalten f().

(Herausgegeben, danke an Hadley, der ein Denker ist.)

Dirk Eddelbüttel
quelle
2
Meinst du nicht mean(replicate(N, system.time(f(...))[3]), trim = 0.05)?
Hadley
2
Wenn der Aufruf von f () lang ist, ist er in Ordnung. Wenn der f () -Aufruf jedoch kurz ist, erhöht wahrscheinlich ein Zeitsteuerungsaufruf-Overhead die Fehlermessung. Mit einem einzigen Aufruf von system.time () über viele Wiederholungen von f () kann man den Fehler des Aufrufs auf einen infinitesimalen Wert aufteilen (und er kehrt schneller zurück).
John
@ John: Danke, aber ich verstehe nicht ganz, was du gesagt hast. Ich frage mich immer noch, was besser ist, wenn ich f () innerhalb oder außerhalb von system.time () wiederhole.
Tim
Jeder Aufruf des Befehls system.time () benötigt eine variable Zeit, die zu einem Messfehler führt. Dies ist eine kleine Menge. Aber was ist, wenn f () ein sehr kurzer Aufruf ist? Dann kann dieser Fehler mit der Zeit, die zum Aufrufen von f () benötigt wird, in Konflikt gebracht werden. Wenn Sie also f () 1e5-mal innerhalb eines einzelnen system.time () -Aufrufs aufrufen, wird der Fehler in 1e5-Blöcke unterteilt. Wenn Sie system.time () für jedes f () aufrufen, kann dies sinnvoll sein, wenn die Zeit für f () gering ist. Natürlich spielt es keine Rolle, wenn alles, was Sie brauchen, das relative Timing ist.
John
Oh, und der zweite Teil ist, dass es schneller wäre, system.call () einmal aufzurufen.
John
10

Sie können auch Zeit mit Zeitschritten eingeben, die von zurückgegeben wurden Sys.time. Dies misst natürlich die Wandzeit, also die Rechenzeit in Echtzeit. Beispielcode:

Sys.time()->start;
replicate(N,doMeasuredComputation());
print(Sys.time()-start);

quelle
3

In Bezug auf die zu verwendende Timing-Metrik kann ich nicht zu den anderen Respondern hinzufügen.

In Bezug auf die zu verwendende Funktion verwende ich gerne den? Benchmark aus dem Paket rbenchmark .

Tal Galili
quelle
1

Sie machen verschiedene Dinge. Zeit, was Sie getan haben möchten. replicate () gibt einen Ergebnisvektor für jede Ausführung der Funktion zurück. Die for-Schleife funktioniert nicht. Daher sind sie keine äquivalenten Aussagen.

Darüber hinaus gibt es eine Reihe von Möglichkeiten, wie Sie etwas tun möchten. Dann finden Sie die effizienteste Methode.

John
quelle
mod-tipp: poste den zweiten teil als kommentar zur antwort des dirks.