Crear nuevas columnas variables ficticias a partir de variables categóricas

Tengo varios conjuntos de datos con 75,000 observaciones y una variable de type que puede tomar un valor de 0-4. Quiero agregar cinco nuevas variables ficticias a cada conjunto de datos para todos los tipos. La mejor manera que se me ocurrió para hacer esto es la siguiente:

 # For the 'binom' data set create dummy variables for all types in all data sets binom.dummy.list<-list() for(i in 0:4){ binom.dummy.list[[i+1]]<-sapply(binom$type,function(t) ifelse(t==i,1,0)) } # Add and merge data binom.dummy.df<-as.data.frame(do.call("cbind",binom.dummy.list)) binom.dummy.df<-transform(binom.dummy.df,id=1:nrow(binom)) binom<-merge(binom,binom.dummy.df,by="id") 

Mientras esto funciona, es increíblemente lento (la función de fusión incluso se ha bloqueado varias veces). ¿Hay una manera más eficiente de hacer esto? ¿Tal vez esta funcionalidad es parte de un paquete con el que no estoy familiarizado?

R tiene un “sublengua” para traducir las fórmulas a la matriz de diseño, y en el espíritu del lenguaje puede aprovecharlo. Es rápido y conciso. Ejemplo: tiene un predictor cardinal x, un predictor categórico catVar y una respuesta y.

 > binom <- data.frame(y=runif(1e5), x=runif(1e5), catVar=as.factor(sample(0:4,1e5,TRUE))) > head(binom) yx catVar 1 0.5051653 0.34888390 2 2 0.4868774 0.85005067 2 3 0.3324482 0.58467798 2 4 0.2966733 0.05510749 3 5 0.5695851 0.96237936 1 6 0.8358417 0.06367418 2 

Usted acaba de hacer

 > A <- model.matrix(y ~ x + catVar,binom) > head(A) (Intercept) x catVar1 catVar2 catVar3 catVar4 1 1 0.34888390 0 1 0 0 2 1 0.85005067 0 1 0 0 3 1 0.58467798 0 1 0 0 4 1 0.05510749 0 0 1 0 5 1 0.96237936 1 0 0 0 6 1 0.06367418 0 1 0 0 

Hecho.

Drew, esto es mucho más rápido y no debería causar ningún locking.

 > binom <- data.frame(data=runif(1e5),type=sample(0:4,1e5,TRUE)) > for(t in unique(binom$type)) { + binom[paste("type",t,sep="")] <- ifelse(binom$type==t,1,0) + } > head(binom) data type type2 type4 type1 type3 type0 1 0.11787309 2 1 0 0 0 0 2 0.11884046 4 0 1 0 0 0 3 0.92234950 4 0 1 0 0 0 4 0.44759259 1 0 0 1 0 0 5 0.01669651 2 1 0 0 0 0 6 0.33966184 3 0 0 0 1 0 

¿Qué pasa con el uso de model.matrix ()?

 > binom <- data.frame(data=runif(1e5),type=sample(0:4,1e5,TRUE)) > head(binom) data type 1 0.1412164 2 2 0.8764588 2 3 0.5559061 4 4 0.3890109 3 5 0.8725753 3 6 0.8358100 1 > inds <- model.matrix(~ factor(binom$type) - 1) > head(inds) factor(binom$type)0 factor(binom$type)1 factor(binom$type)2 factor(binom$type)3 factor(binom$type)4 1 0 0 1 0 0 2 0 0 1 0 0 3 0 0 0 0 1 4 0 0 0 1 0 5 0 0 0 1 0 6 0 1 0 0 0 

Si está abierto a usar el paquete data.table , mltools tiene un método one_hot ().

 library(data.table) library(mltools) binom <- data.table(y=runif(1e5), x=runif(1e5), catVar=as.factor(sample(0:4,1e5,TRUE))) one_hot(binom) yx catVar_0 catVar_1 catVar_2 catVar_3 catVar_4 1: 0.90511891 0.83045050 0 0 1 0 0 2: 0.91375984 0.73273830 0 0 0 1 0 3: 0.01926608 0.10301409 0 0 1 0 0 4: 0.48691138 0.24428157 0 1 0 0 0 5: 0.60660396 0.09132816 0 0 1 0 0 --- 99996: 0.12908356 0.26157731 0 1 0 0 0 99997: 0.96397273 0.98959000 0 1 0 0 0 99998: 0.16818414 0.37460941 1 0 0 0 0 99999: 0.72610508 0.72055867 1 0 0 0 0 100000: 0.89710998 0.24155507 0 0 0 0 1 

ifelse está vectorizado, por lo que si entiendo tu código correctamente, no lo necesitas con sapply . Y no usaría merge, usaría SQLite o PostgreSQL.

Algunos datos de muestra también serían útiles 🙂

El paquete de recetas también puede ser bastante poderoso para hacer esto. El siguiente ejemplo es bastante detallado, pero puede ser realmente limpio tan pronto como agregue más pasos de preprocesamiento.

 library(recipes) binom <- data.frame(y = runif(1e5), x = runif(1e5), catVar = as.factor(sample(0:4, 1e5, TRUE))) # use the example from gappy head(binom) new_data <- recipe(y ~ ., data = binom) %>% step_dummy(catVar) %>% # add dummy variable prep(training = binom) %>% # apply the preprocessing steps (could be more than just adding dummy variables) bake(newdata = binom) # apply the recipe to new data head(new_data) 

Otros ejemplos de pasos son step_scale, step_center, step_pca, etc.

El paquete nnet para redes neuronales de una sola capa (que no entienden los factores) tiene un comando de conversión: class.ind.