Tabla de contenidos

  1. Carga de liberías
  2. Lectura de base de datos
  3. Exploración de los datos
  4. Variable objetivo
  5. Selección de variables explicativas
  6. Base de entrenamiento y validación
  7. Modelo MARS
  8. Estadísticos de desempeño
  9. Conclusiones

Carga de librerías

# Lectura de archivos
#install.packages("readr")
library(readr)

# Transformación BoxCox
#install.packages("MASS")
library(MASS)

# Manipulación de datos 
#install.packages("tidyverse")
library(tidyverse)

# Separación de data 
#install.packages("caTools")
library(caTools)

# Indicadores de rendimiento
#install.packages("Metrics")
library(Metrics)

# Modelo MARS
#install.packages("earth")
library(earth)

Lectura de base de datos

BDDenemdu <- read_delim("BDDenemdu_personas_2021_anual.csv", 
                        delim = ";", escape_double = FALSE, trim_ws = TRUE)

Exploración de los datos

# Número de registros 
dim(BDDenemdu)[1]
## [1] 361790
# Número de variables 
dim(BDDenemdu)[2]
## [1] 151
# Tipo de variables
glimpse(BDDenemdu)
## Rows: 361,790
## Columns: 151
## $ area         <dbl> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ~
## $ ciudad       <dbl> 10150, 10150, 10150, 10150, 10150, 10150, 10150, 10150, 1~
## $ conglomerado <chr> "000802", "000802", "000802", "000802", "002101", "002101~
## $ panelm       <chr> "016", "016", "016", "016", "002", "002", "002", "002", "~
## $ vivienda     <chr> "02", "02", "02", "02", "02", "02", "07", "07", "07", "05~
## $ hogar        <dbl> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ~
## $ p01          <chr> "01", "02", "03", "04", "01", "02", "01", "02", "03", "01~
## $ p02          <dbl> 1, 2, 1, 2, 2, 1, 1, 2, 1, 1, 2, 1, 2, 2, 1, 1, 2, 2, 2, ~
## $ p03          <dbl> 58, 47, 27, 17, 84, 50, 48, 45, 23, 59, 62, 25, 23, 53, 3~
## $ p04          <dbl> 1, 2, 3, 3, 1, 3, 1, 2, 3, 1, 2, 3, 3, 1, 1, 1, 2, 3, 3, ~
## $ p05a         <dbl> 2, 10, 10, 2, 10, 1, 10, 10, 10, 1, 1, 1, 2, 1, 1, 1, 1, ~
## $ p05b         <dbl> 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 1~
## $ p06          <dbl> 1, 1, 6, 6, 4, 3, 5, 5, 6, 1, 1, 6, 6, 3, 6, 1, 1, NA, NA~
## $ p07          <dbl> 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, NA, NA~
## $ p08          <dbl> NA, NA, NA, 1, NA, NA, NA, NA, NA, NA, NA, NA, 6, NA, NA,~
## $ p09          <dbl> 5, 11, 2, NA, 1, 5, 3, 3, 3, 2, 2, 2, NA, 5, 2, 2, 2, NA,~
## $ p10a         <dbl> 9, 6, 9, 7, 6, 6, 9, 6, 7, 9, 9, 9, 9, 6, 10, 10, 9, NA, ~
## $ p10b         <dbl> 3, 6, 6, 2, 6, 6, 4, 5, 3, 3, 3, 3, 5, 6, 2, 3, 5, NA, NA~
## $ p11          <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N~
## $ p12a         <dbl> 2, NA, 1, NA, NA, NA, 2, NA, NA, 1, 1, 1, 1, NA, 1, 1, 1,~
## $ p12b         <dbl> NA, NA, 30910100, NA, NA, NA, NA, NA, NA, 21020204, 20910~
## $ p15          <dbl> 6, 6, 6, 6, 7, 7, 6, 6, 6, 7, 7, 7, 7, 6, 6, 6, 6, NA, NA~
## $ p15aa        <dbl> 2, 2, 2, 1, 1, 1, 1, 3, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ~
## $ p15ab        <dbl> 30351, 30351, 30351, NA, NA, NA, NA, 170, 170, NA, NA, NA~
## $ cod_inf      <dbl> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, NA, NA~
## $ p20          <dbl> 1, 2, 2, 2, 2, 1, 2, 2, 2, 1, 2, 1, 2, 1, 1, 1, 1, NA, NA~
## $ p21          <dbl> NA, 12, 12, 12, 12, NA, 12, 12, 12, NA, 12, NA, 12, NA, N~
## $ p22          <dbl> NA, 2, 2, 2, 2, NA, 2, 2, 2, NA, 2, NA, 2, NA, NA, NA, NA~
## $ p23          <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N~
## $ p24          <dbl> 50, NA, NA, NA, NA, 60, NA, NA, NA, 40, NA, 40, NA, 40, 4~
## $ p25          <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N~
## $ p26          <dbl> 4, NA, NA, NA, NA, 1, NA, NA, NA, 1, NA, 1, NA, 1, 1, 5, ~
## $ p27          <dbl> 4, NA, NA, NA, NA, 4, NA, NA, NA, 4, NA, 4, NA, 4, 4, 4, ~
## $ p28          <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N~
## $ p29          <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N~
## $ p30          <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N~
## $ p31          <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N~
## $ p32          <dbl> NA, 11, 8, 11, 11, NA, 2, 2, 2, NA, 11, NA, 11, NA, NA, N~
## $ p33          <dbl> NA, NA, 20, NA, NA, NA, 4, 20, 8, NA, NA, NA, NA, NA, NA,~
## $ p34          <dbl> NA, 9, NA, 9, 12, NA, NA, NA, NA, NA, 12, NA, 9, NA, NA, ~
## $ p35          <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N~
## $ p36          <dbl> NA, 4, NA, 3, 4, NA, NA, NA, NA, NA, 2, NA, 3, NA, NA, NA~
## $ p37          <dbl> NA, NA, 1, NA, NA, NA, 1, 2, 2, NA, NA, NA, NA, NA, NA, N~
## $ p38          <dbl> NA, NA, 5, NA, NA, NA, 2, NA, NA, NA, NA, NA, NA, NA, NA,~
## $ p39          <dbl> NA, NA, 20, NA, NA, NA, 8, NA, NA, NA, NA, NA, NA, NA, NA~
## $ p40          <dbl> 1629, NA, 8620, NA, NA, 8010, 4711, NA, NA, 8690, NA, 511~
## $ p41          <dbl> 7522, NA, 2261, NA, NA, 5414, 5223, NA, NA, 3255, NA, 311~
## $ p42          <dbl> 6, NA, 1, NA, NA, 2, 2, NA, NA, 6, NA, 2, NA, 1, 6, 2, 2,~
## $ p42a         <dbl> 2, NA, NA, NA, NA, NA, NA, NA, NA, 2, NA, NA, NA, NA, 2, ~
## $ p43          <dbl> NA, NA, NA, NA, NA, 2, NA, NA, NA, NA, NA, 2, NA, 1, NA, ~
## $ p44a         <dbl> NA, NA, NA, NA, NA, 2, NA, NA, NA, NA, NA, 2, NA, 2, NA, ~
## $ p44b         <dbl> NA, NA, NA, NA, NA, 2, NA, NA, NA, NA, NA, 2, NA, 2, NA, ~
## $ p44c         <dbl> NA, NA, NA, NA, NA, 2, NA, NA, NA, NA, NA, 2, NA, 2, NA, ~
## $ p44d         <dbl> NA, NA, NA, NA, NA, 2, NA, NA, NA, NA, NA, 1, NA, 1, NA, ~
## $ p44e         <dbl> NA, NA, NA, NA, NA, 2, NA, NA, NA, NA, NA, 2, NA, 1, NA, ~
## $ p44f         <dbl> NA, NA, NA, NA, NA, 1, NA, NA, NA, NA, NA, 1, NA, 1, NA, ~
## $ p44g         <dbl> NA, NA, NA, NA, NA, 2, NA, NA, NA, NA, NA, 2, NA, 2, NA, ~
## $ p44h         <dbl> NA, NA, NA, NA, NA, 2, NA, NA, NA, NA, NA, 2, NA, 2, NA, ~
## $ p44i         <dbl> NA, NA, NA, NA, NA, 1, NA, NA, NA, NA, NA, 1, NA, 1, NA, ~
## $ p44j         <dbl> NA, NA, NA, NA, NA, 1, NA, NA, NA, NA, NA, 1, NA, 1, NA, ~
## $ p44k         <dbl> NA, NA, NA, NA, NA, 1, NA, NA, NA, NA, NA, 1, NA, 1, NA, ~
## $ p45          <dbl> 30, NA, NA, NA, NA, 18, NA, NA, NA, 15, NA, 3, NA, 7, 10,~
## $ p46          <dbl> 9, NA, NA, NA, NA, 1, NA, NA, NA, 6, NA, 1, NA, 1, 6, 1, ~
## $ p47a         <dbl> 1, NA, NA, NA, NA, 1, NA, NA, NA, 1, NA, 2, NA, 2, 1, 1, ~
## $ p47b         <dbl> 1, NA, NA, NA, NA, 20, NA, NA, NA, 1, NA, NA, NA, NA, 1, ~
## $ p48          <dbl> 2, NA, NA, NA, NA, 1, NA, NA, NA, 1, NA, NA, NA, NA, 3, 2~
## $ p49          <dbl> 1, NA, NA, NA, NA, 1, NA, NA, NA, 1, NA, NA, NA, NA, 1, 1~
## $ p50          <dbl> 2, NA, NA, NA, NA, 1, NA, NA, NA, 1, NA, 1, NA, 1, 1, 1, ~
## $ p51a         <dbl> 40, NA, NA, NA, NA, 60, NA, NA, NA, 40, NA, 40, NA, 40, 4~
## $ p51b         <dbl> 10, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N~
## $ p51c         <dbl> 0, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA~
## $ p52          <dbl> 4921, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,~
## $ p53          <dbl> 8331, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,~
## $ p54          <dbl> 6, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA~
## $ p54a         <dbl> 2, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA~
## $ p55          <dbl> 3, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA~
## $ p56a         <dbl> 1, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA~
## $ p56b         <dbl> 1, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA~
## $ p57          <dbl> 2, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA~
## $ p58          <dbl> 1, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA~
## $ p59          <dbl> 1, NA, NA, NA, NA, 1, NA, NA, NA, 5, NA, 5, NA, 1, 1, 1, ~
## $ p60a         <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N~
## $ p60b         <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N~
## $ p60c         <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N~
## $ p60d         <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N~
## $ p60e         <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N~
## $ p60f         <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N~
## $ p60g         <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N~
## $ p60h         <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N~
## $ p60i         <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N~
## $ p60j         <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N~
## $ p60k         <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N~
## $ p61b1        <dbl> 2, 5, 5, 5, 5, 1, 5, 5, 5, 1, 5, 1, 2, 1, 1, 1, 1, NA, NA~
## $ p63          <dbl> 999999, NA, NA, NA, NA, NA, NA, NA, NA, 999999, NA, NA, N~
## $ p64a         <dbl> 2, NA, NA, NA, NA, NA, NA, NA, NA, 2, NA, NA, NA, NA, 2, ~
## $ p64b         <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N~
## $ p65          <dbl> 999999, NA, NA, NA, NA, NA, NA, NA, NA, 999999, NA, NA, N~
## $ p66          <dbl> NA, NA, NA, NA, NA, 999999, NA, NA, NA, NA, NA, 999999, N~
## $ p67          <dbl> NA, NA, NA, NA, NA, 999999, NA, NA, NA, NA, NA, 999999, N~
## $ p68a         <dbl> NA, NA, NA, NA, NA, 1, NA, NA, NA, NA, NA, 1, NA, 1, NA, ~
## $ p68b         <dbl> NA, NA, NA, NA, NA, 999999, NA, NA, NA, NA, NA, 0, NA, 99~
## $ p69          <dbl> 999999, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N~
## $ p70a         <dbl> 2, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA~
## $ p70b         <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N~
## $ p71a         <dbl> 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, NA, NA~
## $ p71b         <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N~
## $ p72a         <dbl> 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, NA, NA~
## $ p72b         <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 999999, NA, NA, N~
## $ p73a         <dbl> 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, NA, NA~
## $ p73b         <dbl> 200, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, ~
## $ p74a         <dbl> 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, NA, NA~
## $ p74b         <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N~
## $ p75          <dbl> 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, NA, NA~
## $ p76          <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N~
## $ p77          <dbl> 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, NA, NA~
## $ p78          <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N~
## $ sd01         <dbl> NA, NA, 2, NA, NA, NA, 2, 2, 2, NA, NA, NA, NA, NA, NA, N~
## $ sd021        <dbl> NA, NA, 2, NA, NA, NA, 2, 2, 2, NA, NA, NA, NA, NA, NA, N~
## $ sd022        <dbl> NA, NA, 2, NA, NA, NA, 2, 2, 2, NA, NA, NA, NA, NA, NA, N~
## $ sd023        <dbl> NA, NA, 1, NA, NA, NA, 1, 1, 1, NA, NA, NA, NA, NA, NA, N~
## $ sd024        <dbl> NA, NA, 1, NA, NA, NA, 1, 1, 1, NA, NA, NA, NA, NA, NA, N~
## $ sd025        <dbl> NA, NA, 2, NA, NA, NA, 2, 2, 2, NA, NA, NA, NA, NA, NA, N~
## $ sd026        <dbl> NA, NA, 2, NA, NA, NA, 2, 2, 2, NA, NA, NA, NA, NA, NA, N~
## $ sd027        <dbl> NA, NA, 2, NA, NA, NA, 2, 2, 2, NA, NA, NA, NA, NA, NA, N~
## $ sd028        <dbl> NA, NA, 2, NA, NA, NA, 2, 2, 2, NA, NA, NA, NA, NA, NA, N~
## $ sd029        <dbl> NA, NA, 2, NA, NA, NA, 2, 2, 2, NA, NA, NA, NA, NA, NA, N~
## $ sd0210       <dbl> NA, NA, 2, NA, NA, NA, 2, 2, 2, NA, NA, NA, NA, NA, NA, N~
## $ sd0211       <dbl> NA, NA, 2, NA, NA, NA, 2, 2, 2, NA, NA, NA, NA, NA, NA, N~
## $ sd03         <dbl> NA, NA, 2, NA, NA, NA, 1, 9, 9, NA, NA, NA, NA, NA, NA, N~
## $ ced01a       <dbl> 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, ~
## $ estrato      <chr> "2712", "2712", "2712", "2712", "2713", "2713", "2713", "~
## $ fexp         <dbl> 7.918958e+14, 7.918958e+14, 7.918958e+14, 7.918958e+14, 7~
## $ nnivins      <dbl> 5, 4, 5, 4, 4, 4, 5, 4, 4, 5, 5, 5, 5, 4, 5, 5, 5, NA, NA~
## $ ingrl        <dbl> 999999, NA, NA, NA, NA, 999999, NA, NA, NA, 999999, NA, 9~
## $ ingpc        <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N~
## $ condact      <dbl> 6, 9, 7, 9, 9, 6, 7, 7, 7, 6, 9, 6, 9, 6, 6, 6, 6, 0, 0, ~
## $ empleo       <dbl> 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, ~
## $ desempleo    <dbl> 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ~
## $ secemp       <dbl> 1, NA, NA, NA, NA, 1, NA, NA, NA, 1, NA, 1, NA, 1, 1, 1, ~
## $ grupo1       <dbl> 7, NA, NA, NA, NA, 5, NA, NA, NA, 3, NA, 3, NA, 4, 2, 2, ~
## $ rama1        <dbl> 3, NA, NA, NA, NA, 14, NA, NA, NA, 17, NA, 8, NA, 15, 17,~
## $ prov         <dbl> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ~
## $ dominio      <dbl> 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, ~
## $ pobreza      <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N~
## $ epobreza     <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N~
## $ upm          <chr> "010150000802", "010150000802", "010150000802", "01015000~
## $ id_vivienda  <chr> "0101500008020160207", "0101500008020160207", "0101500008~
## $ id_hogar     <chr> "01015000080201602107", "01015000080201602107", "01015000~
## $ id_persona   <chr> "0101500008020160210107", "0101500008020160210207", "0101~
## $ periodo      <dbl> 202107, 202107, 202107, 202107, 202101, 202101, 202101, 2~
## $ mes          <chr> "07", "07", "07", "07", "01", "01", "01", "01", "01", "06~

Variable objetivo

# Estadísticos principales de la variable ingreso laboral
summary(BDDenemdu$ingrl)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max.    NA's 
##      -1     150     350   11954     600  999999  215257
# Diagrama de caja de la variable ingreso laboral
boxplot(BDDenemdu$ingrl, horizontal = TRUE)

# Histograma de la variable ingreso laboral
hist(BDDenemdu$ingrl, freq = FALSE, main = "", xlab = "")

Imputación de valores atípicos

# Se eliminan registros faltantes y no positivos

df <- BDDenemdu
df <- df[!is.na(df$ingrl),]
df <- df[df$ingrl > 0,]

# Se eliminan registros con ingreso laboral superiores a los $3K 

df[df$ingrl > 3000,] %>% nrow()
## [1] 2733
df3k <- df[df$ingrl < 3000,]

# Se aplica una transformación de BoxCox con lambda (l = 0) - se puede optimizar el parámetro

df3k$ingrl <- log(df3k$ingrl) 
df <- df3k

# Distribución de la variable objetivo

summary(df$ingrl)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   0.000   5.136   5.900   5.696   6.392   8.006
# Gráfico de cajas

boxplot(df$ingrl, horizontal = TRUE, main = "Diagrama de cajas ingreso laboral transformado")

# Histograma

hist(df$ingrl, freq = FALSE, main = "Histogrmama ingreso laboral transformado", xlab = "")

# Función de densidad

dx <- density(df$ingrl)

plot(dx, lwd = 1,
     main = "Funcion de densidad de la variable ingreso laboral tranformado")


Selección de variables explicativas

Inicialmente se trabajará con una muestra de variables sociodemográficas tomadas con referencia del trabajo de Fernández F. Modelo de estimación de ingresos para clientes poco o nada vinculados con ABANCA, 2018. Adicional, únicamente con aquellas variables que no presentes valores faltantes para obtener un mejor ajuste en el modelo.

Las variables a probar en el modelo son las siguientes:

  1. p02: Sexo
  2. p03: Edad
  3. p06: Estado civil
  4. p10a: Nivel de instrucción
  5. p45: Años que trabaja
  6. p44j: Recibe 13er sueldo
  7. p44k: Recibe 14to sueldo
  8. p44g: Recibe seguro médico
  9. p44f: Recibe seguro social
  10. p40: Rama de actividad
  11. p50: Número de trabajos
  12. p51a: Horas de trabajo principal
# Base para modelamiento

df <- df[,c("id_persona", "p02", "p03", "p06", "p10a", "p45", "p44j", "p44k", 
            "p44g","p44f","p40","p50","p51a", "ingrl")]

# Tratamiento de valores faltantes 

# Se elimina los NA de la variable estado civil p06 al tener poca representatividad

df <- df %>% filter(!is.na(p06))

# Se elimina los valores faltantes en las variables Recibe 13er sueldo, Recibe 14to sueldo,
# Recibe seguro social al desconocer la categoría de referencia y sí al tratar de reemplazar 
# los valores por una categoría en específico se provocaría un desbalanceo en la muestra

df <- df %>% filter(!is.na(p44j))

# Tratamiento del tipo de datos

# Sexo es una variable cualitativa
round(prop.table(table(df$p02)),2)
## 
##    1    2 
## 0.62 0.38
df$p02 <- factor(df$p02, levels = c(1, 2), labels = c("1","2"))

# Estado civil es una variable cualitativa
round(prop.table(table(df$p06)),2)
## 
##    1    2    3    4    5    6 
## 0.31 0.07 0.04 0.02 0.23 0.33
df$p06 <- factor(df$p06, levels = c(1,2,3,4,5,6), labels = c("1","2","3","4","5","6"))

# Nivel de instrucción es una variable cualitativa
round(prop.table(table(df$p10a)),3)
## 
##     1     2     4     5     6     7     8     9    10 
## 0.010 0.001 0.187 0.034 0.292 0.127 0.041 0.265 0.043
df$p10a <- factor(df$p10a, levels = c(1,2,3,4,5,6,7,8,9,10), labels = c("1","2","3","4","5","6","7","8","9","10"))

# Recibe 13er sueldo es una variable cualitativa
round(prop.table(table(df$p44j)),2)
## 
##    1    2 
## 0.54 0.46
df$p44j <- factor(df$p44j, levels = c(1,2), labels = c("1","2"))

# Recibe 14to sueldo es una variable cualitativa
round(prop.table(table(df$p44k)),2)
## 
##    1    2 
## 0.54 0.46
df$p44k <- factor(df$p44k, levels = c(1,2), labels = c("1","2"))

# Recibe seguro médico una variable cualitativa
round(prop.table(table(df$p44g)),2)
## 
##    1    2 
## 0.01 0.99
df$p44g <- factor(df$p44g, levels = c(1,2), labels = c("1","2"))

# Recibe seguro social una variable cualitativa
round(prop.table(table(df$p44f)),2)
## 
##    1    2 
## 0.55 0.45
df$p44f <- factor(df$p44f, levels = c(1,2), labels = c("1","2"))

# Rama de actividad es cualitativa
df$p40 <- as.character(df$p40)


# Nombre de las variables

names(df) <- c("idPersona", "sexo", "edad", "estadoCivil", "nivInstruccion", "aniosTrabajando", 
               "recibe13Sueldo", "recibe14Sueldo", "recibeSeguroMedico", "recibeSeguroSocial",
               "actividad", "numTrabajos", "horasTrabajo", "ingreso")


# Resumen de variables 

summary(df)
##   idPersona         sexo           edad       estadoCivil nivInstruccion 
##  Length:75948       1:47326   Min.   :12.00   1:23736     6      :22168  
##  Class :character   2:28622   1st Qu.:28.00   2: 5603     9      :20141  
##  Mode  :character             Median :37.00   3: 3034     4      :14238  
##                               Mean   :37.91   4: 1234     7      : 9665  
##                               3rd Qu.:47.00   5:17338     10     : 3230  
##                               Max.   :89.00   6:25003     8      : 3102  
##                                                           (Other): 3404  
##  aniosTrabajando  recibe13Sueldo recibe14Sueldo recibeSeguroMedico
##  Min.   : 0.000   1:40677        1:40686        1:  817           
##  1st Qu.: 2.000   2:35271        2:35262        2:75131           
##  Median : 6.000                                                   
##  Mean   : 9.625                                                   
##  3rd Qu.:15.000                                                   
##  Max.   :70.000                                                   
##                                                                   
##  recibeSeguroSocial  actividad          numTrabajos     horasTrabajo   
##  1:41530            Length:75948       Min.   :1.000   Min.   :  1.00  
##  2:34418            Class :character   1st Qu.:1.000   1st Qu.: 40.00  
##                     Mode  :character   Median :1.000   Median : 40.00  
##                                        Mean   :1.063   Mean   : 39.37  
##                                        3rd Qu.:1.000   3rd Qu.: 40.00  
##                                        Max.   :2.000   Max.   :120.00  
##                                                                        
##     ingreso     
##  Min.   :0.000  
##  1st Qu.:5.704  
##  Median :6.116  
##  Mean   :6.091  
##  3rd Qu.:6.646  
##  Max.   :8.006  
## 

Base de entrenamiento y validación

set.seed(12345)

# Sets para entrenamiento y validación
sample <- sample.split(df$idPersona, SplitRatio = .75)

# Base de entrenamiento
train <- subset(df, sample == TRUE)

# Base de validación
test <- subset(df, sample == FALSE)

Modelo MARS (Multivariate Adaptive Regression Splines)

# Estimación del modelo 

marsModel <- earth(ingreso ~ edad + aniosTrabajando + horasTrabajo + sexo 
                             + recibe13Sueldo + estadoCivil
                             + numTrabajos + nivInstruccion, data = train)


# Estadísticos generales

marsModel
## Selected 15 of 15 terms, and 11 of 20 predictors
## Termination condition: RSq changed by less than 0.001 at 15 terms
## Importance: recibe13Sueldo2, horasTrabajo, nivInstruccion10, ...
## Number of terms at each degree of interaction: 1 14 (additive model)
## GCV 0.2465879    RSS 14031.6    GRSq 0.6203334    RSq 0.6207066
# Coeficientes estimados

marsModel$coefficients
##                            ingreso
## (Intercept)           6.3794855790
## recibe13Sueldo2      -0.6048215256
## h(horasTrabajo-40)    0.0055778876
## h(40-horasTrabajo)   -0.0383522880
## nivInstruccion10      0.7069858395
## nivInstruccion9       0.3284876862
## h(edad-35)           -0.0008341021
## h(35-edad)           -0.0151703175
## nivInstruccion4      -0.1382061875
## sexo2                -0.0775922999
## nivInstruccion8       0.1950333263
## h(aniosTrabajando-3)  0.0007381790
## h(3-aniosTrabajando) -0.0315627932
## numTrabajos           0.1241224623
## estadoCivil6         -0.0641367358
# Error cuadrático medio 

actual <- test$ingreso
marsResults <- predict(marsModel, test)

cat("Error cuadrático medio: ", rmse(marsResults, actual))
## Error cuadrático medio:  0.4907597

Estadísticos de desempeño

Las medidas estadísticas que el modelo estimado presentan son:

  1. \(R^{2} = 62\%\). Representa el porcentaje de la variabilidad del ingreso laboral explicada por su información sociodemográfica.
  2. \(R^{2} \text{Ajustado} = 62\%\). Resulta de una correción del \(R^{2}\), y su interpretación es similar.
  3. \(RMSE = 0,49\). El error cuadrático mide qué tanto se parece el ingreso laboral estimado versus el ingreso laboral real.

Se puede observar que los estadísticos que presenta el modelo son aceptables.

Adicional, se han calculado rangos del ingreso laboral medio y su estimación:

rank <- data.frame(cbind(exp(actual), exp(marsResults)))
names(rank) <- c("ingresoReal", "ingresoEstimado") 

rank <- rank %>% mutate(rangoIngresoReal = case_when(
                                       between(ingresoReal, 0, 490)  ~ "[0, 490)",
                                       between(ingresoReal, 490, 690) ~ "[490, 690)",
                                       between(ingresoReal, 690, 1000) ~ "[690, 1000)",
                                       between(ingresoReal, 1000, 1200) ~ "[1000, 1200)",
                                       between(ingresoReal, 1200, 1600) ~ "[1200, 1600)",
                                       ingresoReal > 1600 ~ "[1600, 3000)"
                                      ),
                          rangoIngresoEstimado = case_when(
                          between(ingresoEstimado, 0, 490)  ~ "[0, 490)",
                          between(ingresoEstimado, 490, 690) ~ "[490, 690)",
                          between(ingresoEstimado, 690, 1000) ~ "[690, 1000)",
                          between(ingresoEstimado, 1000, 1200) ~ "[1000, 1200)",
                          between(ingresoEstimado, 1200, 1600) ~ "[1200, 1600)",
                          ingresoEstimado > 1600 ~ "[1600, 3000)",
                        )
                        
                        ) 

rankMedioReal <- rank %>% group_by(rangoIngresoReal) %>% summarise(ingresoRealMedio = mean(ingresoReal))
rankMedioEstimado <- rank %>% group_by(rangoIngresoEstimado) %>% summarise(ingresoEstimadoMedio = mean(ingresoEstimado))

rankMedio <- cbind(rankMedioReal, rankMedioEstimado)
rankMedio <- rankMedio[, c("rangoIngresoReal", "ingresoRealMedio", "ingresoEstimadoMedio")]

rankMedio <- rankMedio %>%  mutate(orden_rango = case_when(rangoIngresoReal == "[0, 490)" ~ 1,
                                  rangoIngresoReal == "[490, 690)" ~ 2,
                                  rangoIngresoReal == "[690, 1000)" ~ 3,
                                  rangoIngresoReal == "[1000, 1200)" ~ 4,
                                  rangoIngresoReal == "[1200, 1600)" ~ 5,
                                  rangoIngresoReal == "[1600, 3000)" ~ 6,
                                  )) %>% arrange(orden_rango)

rankMedio
##   rangoIngresoReal ingresoRealMedio ingresoEstimadoMedio orden_rango
## 1         [0, 490)         300.2756             275.1556           1
## 2       [490, 690)         575.8452             605.5678           2
## 3      [690, 1000)         835.0622             828.5498           3
## 4     [1000, 1200)        1098.0786            1099.5683           4
## 5     [1200, 1600)        1366.1162            1309.6130           5
## 6     [1600, 3000)        2048.1458            1605.8369           6

El gráfico anterior muestra el perfil de ingreso que genera el modelo, se puede observar que es preciso para los rangos de ingreso medio. Sin embargo, para el rango de entre \([1600, 3000)\) presenta una subestimación, es decir, el ingreso estimado es menor a $2000.


Conclusiones

  1. Los estadísticos de rendimiento del modelo se consideran adecuados.
  2. La comparativa del valor medio del ingreso laboral estimado versus el real, indica un buen performance del modelo.
  3. La transformación de la variable objetivo juega un papel importante al momento de la estimación, se puede jugar con los parámetros para obtener una mejor estimación.
  4. Una mejora a la estimación propuesta, se puede dar mediante la interacción de variables incluidas en el modelo.
  5. Como pendiente del modelamiento, no se pudo realizar un análisis descriptivo previo a todas las variables explicativas debido al desconocimiento de las categorías base en la data. Esto permitiría tener una explicación más clara de las variables incluidas en el modelo.