uso de la declaración switch ()

106

Estoy un poco confundido acerca de la declaración de cambio en R. Simplemente buscando en Google la función obtengo un ejemplo de la siguiente manera:

Un uso común de switch es bifurcar según el valor de carácter de uno de los argumentos de una función.

 > 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

Sin embargo, esto parece ser lo mismo que tener un montón de ifdeclaraciones designadas para cadatype

¿Eso es todo lo que hay que hacer switch()? ¿Alguien puede darme más ejemplos y mejores aplicaciones?

LostLin
fuente
10
Sí, eso es todo.
Andrie

Respuestas:

119

Bueno, el tiempo para el rescate de nuevo. Parece que switches generalmente más rápido que las ifdeclaraciones. Entonces, y el hecho de que el código sea más corto / ordenado con una switchdeclaración se inclina a favor de 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

Actualización Con el comentario de Joshua en mente, probé otras formas de comparar. El microbenchmark parece el mejor. ... y muestra tiempos similares:

> 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

Actualización final A continuación se muestra lo versátil que switches:

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

Esto mapea case2y case3a 2.5y el valor por defecto (sin nombre) a 99. Para obtener más información, intente?switch

Tommy
fuente
3
Usar un bucle for como ese puede causar problemas con la recolección de basura. La diferencia es mucho menor con una mejor función de evaluación comparativa: benchmark(test1('trimmed'), test2('trimmed'), replications=1e6).
Joshua Ulrich
@JoshuaUlrich ... ¿qué benchmarkfunción estás usando? ¿No parece el obvio del paquete "benchmark"?
Tommy
1
Según stackoverflow.com/questions/6262203/… "microbenchmark" es aún mejor.
Tommy
@JoshuaUlrich - Actualicé la respuesta con resultados de microbencmark, pero son muy similares a los originales. Realmente no veo cómo rbenchmark solucionaría el problema de GC, pero parece tener más gastos generales al llamar evaly replicate.
Tommy
al igual que estoy a un lado, ¿puedo tener varios casos con la misma salida? ieswitch(type, c(this,that)=do something)
LostLin