Verwendung der switch () - Anweisung

106

Ich bin ein wenig verwirrt über die switch-Anweisung in R. Wenn ich einfach die Funktion google, erhalte ich ein Beispiel wie folgt:

Eine übliche Verwendung von switch besteht darin, gemäß dem Zeichenwert eines der Argumente zu einer Funktion zu verzweigen.

 > centre <- function(x, type) {
 + switch(type,
 +        mean = mean(x),
 +        median = median(x),
 +        trimmed = mean(x, trim = .1))
 + }
 > x <- rcauchy(10)
 > centre(x, "mean")
 [1] 0.8760325
 > centre(x, "median")
 [1] 0.5360891
 > centre(x, "trimmed")
 [1] 0.6086504

Dies scheint jedoch nur das Gleiche zu sein, als würde nur eine Reihe von ifAussagen für jede bestimmttype

Ist das alles was dazu gehört switch()? Kann mir jemand weitere Beispiele und bessere Anwendungen geben?

LostLin
quelle
10
Ja, das ist alles.
Andrie

Antworten:

118

Nun, wieder Zeit für die Rettung. Es scheint switchim Allgemeinen schneller als ifAussagen. Das und die Tatsache, dass der Code mit einer switchAussage kürzer / ordentlicher ist, spricht für switch:

# Simplified to only measure the overhead of switch vs if

test1 <- function(type) {
 switch(type,
        mean = 1,
        median = 2,
        trimmed = 3)
}

test2 <- function(type) {
 if (type == "mean") 1
 else if (type == "median") 2
 else if (type == "trimmed") 3
}

system.time( for(i in 1:1e6) test1('mean') ) # 0.89 secs
system.time( for(i in 1:1e6) test2('mean') ) # 1.13 secs
system.time( for(i in 1:1e6) test1('trimmed') ) # 0.89 secs
system.time( for(i in 1:1e6) test2('trimmed') ) # 2.28 secs

Update Mit Joshuas Kommentar habe ich andere Möglichkeiten zum Benchmarking ausprobiert. Die Mikrobank scheint die beste zu sein. ... und es zeigt ähnliche Zeiten:

> library(microbenchmark)
> microbenchmark(test1('mean'), test2('mean'), times=1e6)
Unit: nanoseconds
           expr  min   lq median   uq      max
1 test1("mean")  709  771    864  951 16122411
2 test2("mean") 1007 1073   1147 1223  8012202

> microbenchmark(test1('trimmed'), test2('trimmed'), times=1e6)
Unit: nanoseconds
              expr  min   lq median   uq      max
1 test1("trimmed")  733  792    843  944 60440833
2 test2("trimmed") 2022 2133   2203 2309 60814430

Letztes Update Hier sehen Sie, wie vielseitig es switchist:

switch(type, case1=1, case2=, case3=2.5, 99)

Diese Karten case2und case3zu 2.5und die (unbenannt) standardmäßig 99. Weitere Informationen erhalten Sie?switch

Tommy
quelle
3
Die Verwendung einer solchen for-Schleife kann Probleme mit der Speicherbereinigung verursachen. Der Unterschied ist bei einer besseren Benchmarking-Funktion viel geringer : benchmark(test1('trimmed'), test2('trimmed'), replications=1e6).
Joshua Ulrich
@JoshuaUlrich ... welche benchmarkFunktion benutzt du? Nicht die offensichtliche aus dem "Benchmark" -Paket, wie es scheint?
Tommy
@JoshuaUlrich - Ich habe die Antwort mit den Ergebnissen von aktualisiert microbencmark, aber sie sind meinen ursprünglichen sehr ähnlich. Ich sehe nicht wirklich, wie rbenchmark das GC-Problem umgehen würde, aber es scheint mehr Overhead zu haben, wenn man evalund anruft replicate.
Tommy
Kann ich, abgesehen davon, mehrere Fälle mit derselben Ausgabe haben? dhswitch(type, c(this,that)=do something)
LostLin
4

Kurz gesagt, ja . Aber es gibt Zeiten, in denen Sie das eine gegenüber dem anderen bevorzugen. Google "case switch vs. if else". Es gibt bereits einige Diskussionen über SO. Hier ist auch ein gutes Video, das im Kontext von MATLAB darüber spricht:

http://blogs.mathworks.com/pick/2008/01/02/matlab-basics-switch-case-vs-if-elseif/

Persönlich, wenn ich 3 oder mehr Fälle habe, gehe ich normalerweise einfach mit Fall / Schalter.

John Colby
quelle