Idioma para la grabación de estilo ifelse para múltiples categorías

Me topo con esto con la suficiente frecuencia como para darme cuenta de que tiene que haber una buena expresión idiomática. Supongamos que tengo un data.frame con muchos atributos, incluido “producto”. También tengo una clave que traduce productos a marca + tamaño. Los códigos de productos 1-3 son Tylenol, 4-6 son Advil, 7-9 son Bayer, 10-12 son generics.

¿Cuál es la forma más rápida (en términos de tiempo humano) para codificar esto?

Tiendo a usar ifelse nesteds si hay 3 o menos categorías, y escribo la tabla de datos y la fusiono si hay más de 3. ¿Alguna idea mejor? Stata tiene un comando de recode bastante ingenioso para este tipo de cosas, aunque creo que promueve el entrecruzamiento del código de datos demasiado.

 dat <- structure(list(product = c(11L, 11L, 9L, 9L, 6L, 1L, 11L, 5L, 7L, 11L, 5L, 11L, 4L, 3L, 10L, 7L, 10L, 5L, 9L, 8L)), .Names = "product", row.names = c(NA, -20L), class = "data.frame") 

Uno podría usar una lista como una matriz asociativa para definir la brand -> product code mapeo de brand -> product code , es decir:

 brands <- list(Tylenol=1:3, Advil=4:6, Bayer=7:9, Generic=10:12) 

Una vez que tenga esto, puede invertirlo para crear un product code -> brand lista de product code -> brand (podría tomar mucha memoria), o simplemente usar una función de búsqueda:

 find.key <- function(x, li, default=NA) { ret <- rep.int(default, length(x)) for (key in names(li)) { ret[x %in% li[[key]]] <- key } return(ret) } 

Estoy seguro de que hay mejores formas de escribir esta función (¡el ciclo for me molesta!), Pero al menos está vectorizado, por lo que solo requiere un pase único en la lista.

Usarlo sería algo así como:

 > dat$brand <- find.key(dat$product, brands) > dat product brand 1 11 Generic 2 11 Generic 3 9 Bayer 4 9 Bayer 5 6 Advil 6 1 Tylenol 7 11 Generic 8 5 Advil 9 7 Bayer 10 11 Generic 11 5 Advil 12 11 Generic 13 4 Advil 14 3 Tylenol 15 10 Generic 16 7 Bayer 17 10 Generic 18 5 Advil 19 9 Bayer 20 8 Bayer 

Las soluciones recode y levels<- son muy buenas, pero también son significativamente más lentas que esta (y una vez que has find.key esto es más fácil para los humanos que recode y a la par con los levels<- ):

 > microbenchmark( recode=recode(dat$product,recodes="1:3='Tylenol';4:6='Advil';7:9='Bayer';10:12='Generic'"), find.key=find.key(dat$product, brands), levels=`levels<-`(factor(dat$product),brands)) Unit: microseconds expr min lq median uq max 1 find.key 64.325 69.9815 76.8950 83.8445 221.748 2 levels 240.535 248.1470 274.7565 306.8490 1477.707 3 recode 1636.039 1683.4275 1730.8170 1855.8320 3095.938 

(No puedo hacer que la versión del switch un punto de referencia adecuado, pero parece ser más rápido que todo lo anterior, aunque es incluso peor para los humanos que la solución de recode ).

Puede convertir su variable en un factor y cambiar sus niveles por levels<- function. En un comando podría ser como:

 `levels<-`( factor(dat$product), list(Tylenol=1:3, Advil=4:6, Bayer=7:9, Generic=10:12) ) 

En pasos:

 brands <- factor(dat$product) levels(brands) <- list(Tylenol=1:3, Advil=4:6, Bayer=7:9, Generic=10:12) 
    Intereting Posts