Codificación de variables categóricas I

Voy a hacer una serie de entradas sobre codificación de variables categóricas, mi idea es pasar desde la codificación parcial (OneHot Encoders para los modernos), hasta utilizar embeddings. Vamos al lío.

Tradicionalmente, si tenemos una variable categórica con 5 niveles se codifica en tantas variables cero uno como niveles menos uno, puesto que uno de los niveles se toma como referencia y se codifica con todo 0’s en las varaibles indicadoras.

Veamos un ejemplo con el conjunto de datos Prestige del paquete car en R.

library(car)
## Loading required package: carData
datos <- Prestige
DT::datatable(datos)

Tenemos la variable type que es categórica, con 3 categorías

table(datos$type)
## 
##   bc prof   wc 
##   44   31   23

Por defecto R usa la codificación parcial tomando como nivel de referencia el primero.

Aquí vemos como sería la codificación

contrasts(datos$type)
##      prof wc
## bc      0  0
## prof    1  0
## wc      0  1

Pero lo podemos cambiar

datos$type <- relevel(datos$type, ref="prof")
contrasts(datos$type)
##      bc wc
## prof  0  0
## bc    1  0
## wc    0  1

Otros tipos de codificación similares, son helmert o sum (deviation coding o sum to zero)

contrasts(datos$type) <- "contr.helmert"
contrasts(datos$type)
##      [,1] [,2]
## prof   -1   -1
## bc      1   -1
## wc      0    2
contrasts(datos$type) <- "contr.sum"
contrasts(datos$type)
##      [,1] [,2]
## prof    1    0
## bc      0    1
## wc     -1   -1

Este tipo de codificación viene del análisis ANOVA.

Volvamos al contraste por defecto

contrasts(datos$type) <- "contr.treatment"
contrasts(datos$type)
##      bc wc
## prof  0  0
## bc    1  0
## wc    0  1

Este tipo de codificación es el que hace que por ejemplo en un modelo lineal tengamos tantos coeficientes como niveles del factor menos 1.

foo_model <- lm(income ~ type, data = datos)
summary(foo_model)
## 
## Call:
## lm(formula = income ~ type, data = datos)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -5945.5 -2003.3  -466.2  1536.9 15319.5 
## 
## Coefficients:
##             Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  10559.5      621.7  16.986  < 2e-16 ***
## typebc       -5185.3      811.6  -6.389 6.16e-09 ***
## typewc       -5507.1      952.5  -5.782 9.40e-08 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 3461 on 95 degrees of freedom
##   (4 observations deleted due to missingness)
## Multiple R-squared:  0.3437, Adjusted R-squared:  0.3299 
## F-statistic: 24.87 on 2 and 95 DF,  p-value: 2.057e-09

Y de este modelo tenemos que el intercept se corresponde con la media del salario de proof , el intercept + typebc es la media de salario de bc y el intercept + typewc es la media de salario de wc

tapply(datos$income, datos$type, mean)
##      prof        bc        wc 
## 10559.452  5374.136  5052.304

Si quitamos el intercept tenemos la media directamente en el modelo.

foo_model_2 <-  lm(income ~ type - 1 , data = datos)

summary(foo_model_2)
## 
## Call:
## lm(formula = income ~ type - 1, data = datos)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -5945.5 -2003.3  -466.2  1536.9 15319.5 
## 
## Coefficients:
##          Estimate Std. Error t value Pr(>|t|)    
## typeprof  10559.5      621.7   16.99  < 2e-16 ***
## typebc     5374.1      521.8   10.30  < 2e-16 ***
## typewc     5052.3      721.7    7.00  3.6e-10 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 3461 on 95 degrees of freedom
##   (4 observations deleted due to missingness)
## Multiple R-squared:  0.8236, Adjusted R-squared:  0.818 
## F-statistic: 147.9 on 3 and 95 DF,  p-value: < 2.2e-16

En próximas entradas contaré algo de la codificación por impacto o la que se deriva de usar un modelo mixto.

 
comments powered by Disqus