Ein kurzer Blick auf Geschwindigkeit

von Karl-Kuno Kunze

Dieser Artikel zeigt eine Anwendung vom Package compiler von Luke Tierney. Darüber hinaus versuche ich, for-Schleifen in etwas besseres Licht zu rücken.

Als ein glühender Verfechter von allem, was ply enthält, bin ich natürlich gegen alles, was for enthält. Ab und zu jedoch führt dieses Credo möglicherweise zu eleganterem, aber dennoch langsamerem Code. Im Folgenden schreiben wir ein paar Zeilen Code, die hoffentlich so nirgends stehen, und sehen uns die Laufzeiten an.

These

Es gibt nichts langsameres als eine for-Schleife. Schreiben wir also absichtlich langsamen Code:

SQvecFL <- function(x) {
  sq <- numeric(length(x))
  for (i in 1:length(x))
  {
    sq[i] <- x[i]^2 
  }
  sq
}
system.time(SQvecFL(1:1e6))
##    user  system elapsed 
##   1.650   0.021   1.671

Wir nehmen jedes einzelne Element des Vektors, quadrieren es und geben den Vektor anschließend wieder zurück. Das muss langsam sein!

Jetzt schreiben wir die Funktion neu, jedoch mit einer etwas beschleunigten Version von apply(): vapply().

SQvecvA <- function(x) {
  vapply(x, function(x) x^2, FUN.VALUE = c(1))
}
system.time(SQvecvA(1:1e6))
##    user  system elapsed 
##   0.707   0.005   0.711

Wie erwartet ist dies eleganter und schneller.

Antithese

Mithilfe des compiler-Paketes können wir die Laufzeiten noch verkürzen. Fangen wir mit der for-Schleife an:

library(compiler)
SQvecCompFL <- cmpfun(SQvecFL)
system.time(SQvecCompFL(1:1e6))
##    user  system elapsed 
##   0.487   0.010   0.499

Dies ist etwa ein Drittel der vorhergehenden Laufzeit.

Jetzt tunen wir die vapply() Funktion:

SQvecvAComp <- cmpfun(SQvecvA)
system.time(SQvecvAComp(1:1e6))
##    user  system elapsed 
##   0.631   0.001   0.632

Das sind nur magere 10% Ersparnis. Und es ist langsamer als die for-Schleife!

Synthese

Niemals würde irgendjemand solch ein Problem mit solchem Code lösen. Dies Zeile:

system.time((1:1e6)^2)
##    user  system elapsed 
##   0.004   0.000   0.005

beweist nachdrücklich, warum vektorwertiges Programmieren – wann immer möglich – eingesetzt werden sollte.

Dennoch: behalten Sie das Kompilieren im Hinterkopf. Der Code wird zwar nicht immer schneller, andererseits ist es auch nicht sehr aufwendig, eine Funktion zu kompilieren. Und schließlich darf man ab und zu auch eine for-Schleife schreiben…

________________________________________________________________________________________________

Sie sind an weiteren Tipps über die Programmiersprache R interessiert? Tragen Sie sich in unseren Newsletter ein und bleiben Sie auf dem Laufenden.

Interesse an einem Seminar beim Autor Karl-Kuno Kunze? Hier gelangen Sie zu unseren Trainings in Potsdam. Optional auch in Ihrem Unternehmen vor Ort. Sprechen Sie uns an!

 

Titelbild: Maik Schwertle/ pixelio.de