studio - regresión con variables ficticias
Crear nuevas columnas variables ficticias a partir de variables categóricas (7)
¿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
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?
Drew, esto es mucho más rápido y no debería causar ningún bloqueo.
> 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
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.
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)
y x 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.
Si está abierto a usar el paquete mltools , 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)
y x 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 :-)