Regresión lineal en R

Limpiamos la memoria con rm() y gc(), cargamos los directorios y cargamos las librerías y la base que vamos a utilizar.

rm(list=ls())
gc()
          used (Mb) gc trigger   (Mb)   max used   (Mb)
Ncells 2132921  114    3205452  171.2    3205452  171.2
Vcells 3526159   27  263950304 2013.8 1006890509 7682.0
dir <- paste0(dirname(rstudioapi::getActiveDocumentContext()$path),"/")
bases.dir      <-  paste0(dirname(dir),"/Fuentes/")
resultados.dir <- paste0(dirname(dir),"/Resultados/")
library(tidyverse, warn.conflicts = FALSE)
individual.416 <- read.table(paste0(bases.dir, "usu_individual_t416.txt"), sep=";", dec=",", header = TRUE, fill = TRUE)

El objetivo será hacer inferencia respecto del ingreso de la ocupación principal P21, para ello selecionamos las columnas con las que trabajaremos: variable dependiente y algunas posibles covariables:

Variables a utilizar:

  • P21: MONTO DE INGRESO DE LA OCUPACIÓN PRINCIPAL
  • NIVEL_ED
  • ESTADO
  • CAT_OCUP
  • CH04: Sexo
  • CH06: Edad
  • PP04C99: Tamaño del establecimiento, reducido
  • PP07H: ¿Por ese trabajo tiene descuento jubilatorio?

creamos un vector para seleccionar estas varibales, y un vectr que especifique qué variables son categóricas, para convertirlas en factores. Es necesario convertir las variables categóricas a la clase factor, para que el algorítmo de regresión lineal las reconozca como lo que son

La función lapply() aplica la función factor() a toda la base[factores]

var <- c('P21','NIVEL_ED','ESTADO','CAT_OCUP', 'CH04','CH06','PP04C99','PP07H')
base <- individual.416 %>% 
  select(var)
factores <- c('NIVEL_ED','ESTADO','CAT_OCUP', 'CH04','PP04C99','PP07H')
base[factores] <- lapply(base[factores], factor)
# Nos quedamos sólo con los valores positivos de la variable explicada
base <- base %>% filter(P21 >0)

Correlación y test de correlación

  • Para calcular un test de correlacón de Pearson utilizamos el comando cor().
  • Si queremos calcular un test de hipótesis sobre la correlación, o un interavalo de confianza, utilizamos cor.test()
  • Si no se cumplen los supestos de Pearson (Normalidad, independencia, linealidad en la relación), podemos utilizar el test de correlación no paramétrico de Spearman o kendall con el parámetro method =
  • si queremos que el test sea a una cola, lo podemos especificar con el parámetro alternative =
  • La significativiadd por default es 0.95, pero se puede modificar con el parámetro conf.level =
cor(base$P21, base$CH06)
[1] 0.1460676
cor.test(base$P21, base$CH06)

    Pearson's product-moment correlation

data:  base$P21 and base$CH06
t = 20.09, df = 18514, p-value < 2.2e-16
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
 0.1319413 0.1601345
sample estimates:
      cor 
0.1460676 
cor.test(base$P21, base$CH06,method = "spearman")
Cannot compute exact p-value with ties

    Spearman's rank correlation rho

data:  base$P21 and base$CH06
S = 8.9399e+11, p-value < 2.2e-16
alternative hypothesis: true rho is not equal to 0
sample estimates:
      rho 
0.1550252 

Regresión lineal

con el comando lm() podemos ajustar el modelo. Algunos parametros importantes de esta función son:

  • formula: definimos el modelo como _ Y ~ X _.
    • regresion multiple: y ~ \(X_1 + X_2 + ... X_n\).
    • regresión polinómica: y ~ poly(x = X, degree = k)
    • interacción de variables: y ~ \(X_1*X_2\). Si sólo queremos el término de interacción: \(X_1:X_2\)
  • data : especificamos el dataset a utilizar
  • subset : si dividimos la muestra en training y testing, podemos indicar el subconjunto de entrenamiento con un vector que indique sus números de fila

Regresión lineal simple

Comenzamos regresando a P21 contra la única variable continua que seleccionamos, la edad.

El modelo propuesto resulta

\[ E(P_{21}/ch_{06})= \beta_0 + \beta_1 ch_{06} \]

modelo.ajustado <- lm(formula = P21 ~ CH06, data = base)

La función lm() genera un objeto que contiene varias propiedades de la regresión que ajustamos.

con summary() podemos acceder los principales resultados

summary(modelo.ajustado)

Call:
lm(formula = P21 ~ CH06, data = base)

Residuals:
   Min     1Q Median     3Q    Max 
-15780  -5630  -1599   3351 386290 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept) 6744.583    222.854   30.27   <2e-16 ***
CH06         105.533      5.253   20.09   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 9105 on 18514 degrees of freedom
Multiple R-squared:  0.02134,   Adjusted R-squared:  0.02128 
F-statistic: 403.6 on 1 and 18514 DF,  p-value: < 2.2e-16

Para revisar los supuestos del modelo, así como la posible presencia de outliers, podemos revisar unos gráficos que se generan vía el comando plot().

plot(modelo.ajustado)

  • Residuals ~ Fitted values: Aquí buscamos que no exista ningúna estructura en los datos. Si la presentan, según la forma que tome, podría ser un indicador de heterocedasticidad o no linealidad en la relación
  • QQ plot: Muestra si los datos se ajustan al supuesto de normalidad. Si los puntos se ubican sobre la linea puntada, esto indica que tienen una distribución normal. En nuestro caso, podemos ver que se ve que se alejan en el extremo derecho de la distribución.
  • \(\sqrt{residuos \space estandarizados}\) ~ Fitted Values: Es similar al primer gráfico, con otra escala.
  • Leverage ~ residuos estandarizados: Nos permite encontrar observaciones influyentes. En particular, aquellas que queden fuera de los márgenes definidos por la distancia de cook deberían ser revisadas.

Regresión lineal múltiple

\[ E(P_{21}/X)= \beta_0 + \beta_1 ch_{06} + \beta_2 ch_{06}^2 \]

modelo.ajustado <- lm(formula = P21 ~ poly(x = CH06,degree = 2) , data = base)
summary(modelo.ajustado)

Call:
lm(formula = P21 ~ poly(x = CH06, degree = 2), data = base)

Residuals:
   Min     1Q Median     3Q    Max 
-12489  -5442  -1673   3145 388558 

Coefficients:
                              Estimate Std. Error t value Pr(>|t|)    
(Intercept)                   11015.19      66.44  165.79   <2e-16 ***
poly(x = CH06, degree = 2)1  182928.34    9040.73   20.23   <2e-16 ***
poly(x = CH06, degree = 2)2 -147552.65    9040.73  -16.32   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 9041 on 18513 degrees of freedom
Multiple R-squared:  0.03522,   Adjusted R-squared:  0.03511 
F-statistic: 337.9 on 2 and 18513 DF,  p-value: < 2.2e-16

Si queremos elegir el mejor modelo polinomico entre los de la forma

\[ E(P_{21}/X)= \beta_0 + \beta_1 ch_{06} + \beta_2 ch_{06}^2 + ... + \beta_n ch_{06}^n \]

podemos hacer uso de los loops, para ajustar varios modelos polinómicos de distinto grado, y luego comparar sus r cuadrados ajustados.

r.ajustado <- c()
for (i in 1:10) {
  modelo.ajustado <- lm(formula = P21 ~ poly(x = CH06,degree = i) , data = base)
  r.ajustado[i] <- summary(modelo.ajustado)$adj.r.squared  
}
plot(r.ajustado, type = "b")

Regresión lineal con variables categóricas

\[ E(P_{21}/X)= \beta_0 + \beta_1 ch_{06} + \beta_2 cat.ocup \]

CAT_OCUP: 1 = Patrón 2 = Cuenta propia 3 = Obrero o empleado

table(base$CAT_OCUP)

    0     1     2     3     4     9 
    0   548  3510 14458     0     0 

Para utilizar dummies, no es necesario que las creemos, simplemente agregamos la variable categórica, y la función se encarga de crear las variables.

modelo.ajustado <- lm(formula = P21 ~ CH06 + CAT_OCUP, data = base)
summary(modelo.ajustado)

Call:
lm(formula = P21 ~ CH06 + CAT_OCUP, data = base)

Residuals:
   Min     1Q Median     3Q    Max 
-19731  -5185  -1593   3060 380342 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept) 11791.53     454.04   25.97   <2e-16 ***
CH06          119.20       5.21   22.88   <2e-16 ***
CAT_OCUP2   -9464.41     408.12  -23.19   <2e-16 ***
CAT_OCUP3   -4873.89     388.90  -12.53   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 8875 on 18512 degrees of freedom
Multiple R-squared:  0.07022,   Adjusted R-squared:  0.07007 
F-statistic:   466 on 3 and 18512 DF,  p-value: < 2.2e-16

Best subset selection

Si queremos hacer Best subset selection, podemos utilizar el paquete leaps, aunque no es el único. El comando regsubsets() nos permite hacer selección de modelos exahustiva, así como forward o backward stepwise, entre otros métodos.

library(leaps)
names(base)
[1] "P21"      "NIVEL_ED" "ESTADO"   "CAT_OCUP" "CH04"     "CH06"     "PP04C99"  "PP07H"   
regsubsets.out <-
    regsubsets(P21 ~ NIVEL_ED + ESTADO + CAT_OCUP + CH04 + CH06 + PP04C99 + PP07H,
               data = base,
               nbest = 1,       # 1 best model for each number of predictors
               nvmax = NULL,    # NULL for no limit on number of variables
               force.in = NULL, force.out = NULL,
               method = "exhaustive")
7  linear dependencies found
Reordering variables and trying again:
summary(regsubsets.out)
Subset selection object
Call: regsubsets.formula(P21 ~ NIVEL_ED + ESTADO + CAT_OCUP + CH04 + 
    CH06 + PP04C99 + PP07H, data = base, nbest = 1, nvmax = NULL, 
    force.in = NULL, force.out = NULL, method = "exhaustive")
23 Variables  (and intercept)
          Forced in Forced out
NIVEL_ED2     FALSE      FALSE
NIVEL_ED3     FALSE      FALSE
NIVEL_ED4     FALSE      FALSE
NIVEL_ED5     FALSE      FALSE
NIVEL_ED6     FALSE      FALSE
NIVEL_ED7     FALSE      FALSE
CAT_OCUP1     FALSE      FALSE
CAT_OCUP2     FALSE      FALSE
CH042         FALSE      FALSE
CH06          FALSE      FALSE
PP04C991      FALSE      FALSE
PP04C992      FALSE      FALSE
PP04C993      FALSE      FALSE
PP04C999      FALSE      FALSE
PP07H1        FALSE      FALSE
PP07H2        FALSE      FALSE
ESTADO1       FALSE      FALSE
ESTADO2       FALSE      FALSE
ESTADO3       FALSE      FALSE
ESTADO4       FALSE      FALSE
CAT_OCUP3     FALSE      FALSE
CAT_OCUP4     FALSE      FALSE
CAT_OCUP9     FALSE      FALSE
1 subsets of each size up to 16
Selection Algorithm: exhaustive
          NIVEL_ED2 NIVEL_ED3 NIVEL_ED4 NIVEL_ED5 NIVEL_ED6 NIVEL_ED7 ESTADO1 ESTADO2 ESTADO3 ESTADO4 CAT_OCUP1
1  ( 1 )  " "       " "       " "       " "       " "       " "       " "     " "     " "     " "     " "      
2  ( 1 )  " "       " "       " "       " "       " "       " "       " "     " "     " "     " "     " "      
3  ( 1 )  " "       " "       " "       " "       "*"       " "       " "     " "     " "     " "     " "      
4  ( 1 )  " "       " "       " "       " "       "*"       " "       " "     " "     " "     " "     "*"      
5  ( 1 )  " "       " "       " "       " "       "*"       " "       " "     " "     " "     " "     "*"      
6  ( 1 )  "*"       " "       " "       " "       "*"       " "       " "     " "     " "     " "     "*"      
7  ( 1 )  " "       " "       "*"       "*"       "*"       " "       " "     " "     " "     " "     "*"      
8  ( 1 )  " "       "*"       "*"       "*"       "*"       " "       " "     " "     " "     " "     "*"      
9  ( 1 )  "*"       "*"       "*"       "*"       "*"       " "       " "     " "     " "     " "     "*"      
10  ( 1 ) "*"       "*"       "*"       "*"       "*"       " "       " "     " "     " "     " "     "*"      
11  ( 1 ) "*"       "*"       "*"       "*"       "*"       " "       " "     " "     " "     " "     "*"      
12  ( 1 ) "*"       "*"       "*"       "*"       "*"       " "       " "     " "     " "     " "     "*"      
13  ( 1 ) "*"       "*"       "*"       "*"       "*"       " "       " "     " "     " "     " "     "*"      
14  ( 1 ) "*"       "*"       "*"       "*"       "*"       " "       " "     " "     " "     " "     "*"      
15  ( 1 ) "*"       "*"       "*"       "*"       "*"       " "       " "     " "     " "     " "     "*"      
16  ( 1 ) "*"       "*"       "*"       "*"       "*"       "*"       " "     " "     " "     " "     "*"      
          CAT_OCUP2 CAT_OCUP3 CAT_OCUP4 CAT_OCUP9 CH042 CH06 PP04C991 PP04C992 PP04C993 PP04C999 PP07H1 PP07H2
1  ( 1 )  " "       " "       " "       " "       " "   " "  " "      " "      " "      " "      "*"    " "   
2  ( 1 )  "*"       " "       " "       " "       " "   " "  " "      " "      " "      " "      " "    "*"   
3  ( 1 )  " "       " "       " "       " "       "*"   " "  " "      " "      " "      " "      "*"    " "   
4  ( 1 )  " "       " "       " "       " "       "*"   " "  " "      " "      " "      " "      "*"    " "   
5  ( 1 )  " "       " "       " "       " "       "*"   "*"  " "      " "      " "      " "      "*"    " "   
6  ( 1 )  " "       " "       " "       " "       "*"   "*"  " "      " "      " "      " "      "*"    " "   
7  ( 1 )  " "       " "       " "       " "       "*"   "*"  " "      " "      " "      " "      "*"    " "   
8  ( 1 )  " "       " "       " "       " "       "*"   "*"  " "      " "      " "      " "      "*"    " "   
9  ( 1 )  " "       " "       " "       " "       "*"   "*"  " "      " "      " "      " "      "*"    " "   
10  ( 1 ) " "       " "       " "       " "       "*"   "*"  " "      "*"      " "      " "      "*"    " "   
11  ( 1 ) " "       " "       " "       " "       "*"   "*"  "*"      "*"      " "      " "      "*"    " "   
12  ( 1 ) " "       " "       " "       " "       "*"   "*"  "*"      "*"      " "      "*"      "*"    " "   
13  ( 1 ) " "       " "       " "       " "       "*"   "*"  "*"      "*"      "*"      "*"      "*"    " "   
14  ( 1 ) " "       " "       " "       " "       "*"   "*"  "*"      "*"      "*"      "*"      "*"    "*"   
15  ( 1 ) " "       "*"       " "       " "       "*"   "*"  "*"      "*"      "*"      "*"      "*"    "*"   
16  ( 1 ) "*"       " "       " "       " "       "*"   "*"  "*"      "*"      "*"      "*"      "*"    "*"   
## Adjusted R2
plot(regsubsets.out, scale = "adjr2", main = "Adjusted R^2")

con which.max() podemos ubicar el modelo con el mejor ajuste. En nuestro caso elegimos comparar por \(R^2\).

which.max(summary(regsubsets.out)$adjr2)
[1] 13

Sabiendo que el modelo con 13 covariables es el que mejor ajusta, podemos observar con más detalle el mejor de los modelos con 13 covariables

summary(regsubsets.out)$which[13,]
(Intercept)   NIVEL_ED2   NIVEL_ED3   NIVEL_ED4   NIVEL_ED5   NIVEL_ED6   NIVEL_ED7     ESTADO1     ESTADO2 
       TRUE        TRUE        TRUE        TRUE        TRUE        TRUE       FALSE       FALSE       FALSE 
    ESTADO3     ESTADO4   CAT_OCUP1   CAT_OCUP2   CAT_OCUP3   CAT_OCUP4   CAT_OCUP9       CH042        CH06 
      FALSE       FALSE        TRUE       FALSE       FALSE       FALSE       FALSE        TRUE        TRUE 
   PP04C991    PP04C992    PP04C993    PP04C999      PP07H1      PP07H2 
       TRUE        TRUE        TRUE        TRUE        TRUE       FALSE 

Como las dummies de la misma categorica se deben incluir todas, sólo puedo concluir que la variable ESTADO no es significativa para el modelo, pero todas las demás sí. Como se vé, este método no es muy útil si pensamos trabajar con muchas variables categóricas, ya que no podemos indicarle que todas las dummies pertenecientes a una misma covariable deben ser consideradas en conjunto (por lo menos para esta librería).

modelo.ajustado <- lm(P21 ~ NIVEL_ED + CAT_OCUP + CH04 + CH06 + PP04C99 + PP07H,
               data = base)
summary(modelo.ajustado)

Call:
lm(formula = P21 ~ NIVEL_ED + CAT_OCUP + CH04 + CH06 + PP04C99 + 
    PP07H, data = base)

Residuals:
   Min     1Q Median     3Q    Max 
-19890  -4015  -1105   2313 376024 

Coefficients:
              Estimate Std. Error t value Pr(>|t|)    
(Intercept)   9740.395    521.493  18.678  < 2e-16 ***
NIVEL_ED2     1157.565    337.677   3.428 0.000609 ***
NIVEL_ED3     2204.099    337.717   6.526 6.91e-11 ***
NIVEL_ED4     3732.148    328.143  11.374  < 2e-16 ***
NIVEL_ED5     4671.176    351.836  13.277  < 2e-16 ***
NIVEL_ED6     7922.073    338.660  23.392  < 2e-16 ***
NIVEL_ED7      -74.977   1016.887  -0.074 0.941224    
CAT_OCUP2    -8336.445    360.867 -23.101  < 2e-16 ***
CAT_OCUP3   -15104.260   7829.490  -1.929 0.053728 .  
CH042        -3946.775    121.013 -32.614  < 2e-16 ***
CH06            95.655      4.853  19.709  < 2e-16 ***
PP04C991     -1671.932    877.720  -1.905 0.056814 .  
PP04C992     -1194.144    377.407  -3.164 0.001558 ** 
PP04C993      -434.592    327.381  -1.327 0.184366    
PP04C999      -537.287    305.261  -1.760 0.078408 .  
PP07H1       12970.539   7822.940   1.658 0.097332 .  
PP07H2        6810.680   7821.678   0.871 0.383905    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 7819 on 18499 degrees of freedom
Multiple R-squared:  0.279, Adjusted R-squared:  0.2783 
F-statistic: 447.3 on 16 and 18499 DF,  p-value: < 2.2e-16

Ejemplo trivial

Por útlimo, utilizamos un dataset de datos de manual, para hacer algunos ejercicios más. Los datos son tomados de Heinz, Peterson, Johnson, y Kerk {2003}, y se encuentran en la base de datos bdims del paquete openintro.

library(openintro,warn.conflicts = FALSE)

Primero realizamos un diagrama de dispersión que muestre la relación entre el peso medido en kilogramos (wgt)y la circunferencia de la cadera medida en centímetros (hip.gi), diferenciando por sexo (sex = 1 para los hombres y sex = 0 para las mujeres)

Primero calculamos el modelo sin diferenciar por sexo

lm.ajustado <- lm(wgt~hip.gi,data = bdims)
summary(lm.ajustado)

Call:
lm(formula = wgt ~ hip.gi, data = bdims)

Residuals:
    Min      1Q  Median      3Q     Max 
-19.449  -7.111  -0.367   7.264  22.353 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)    
(Intercept) -78.21054    5.56902  -14.04   <2e-16 ***
hip.gi        1.52417    0.05747   26.52   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 8.636 on 505 degrees of freedom
Multiple R-squared:  0.5821,    Adjusted R-squared:  0.5813 
F-statistic: 703.5 on 1 and 505 DF,  p-value: < 2.2e-16

Lo graficamos

plot(bdims$hip.gi,bdims$wgt)
abline(lm.ajustado, col = "red")

Una alternativa en ggplot (no utilizamos el modelo construido, sino que lo volvemos a generar)

ggplot(bdims, aes(hip.gi, wgt)) + 
  geom_point()+ 
  geom_smooth(method = "lm")

Prediccion

Para predecir una nueva observación, podemos calular el intervalo de confianza o el intervalo de predicción con el comando predict.lm()
Por ejemplo, si elegimos una persona con contorno de cadera mide 100 cm.

new <- data.frame(hip.gi = 100)
#intervalo de confianza
predict.lm(lm.ajustado,newdata = new,interval="confidence",level = 0.95)
       fit      lwr    upr
1 74.20646 73.36492 75.048
#intervalo de predicción
predict.lm(lm.ajustado,newdata = new,interval="prediction",level = 0.95)
       fit      lwr      upr
1 74.20646 57.21927 91.19365

anova

So queremos los datos de la tabla anova, lo hacemos con el comando anova()

anova(lm.ajustado)
Analysis of Variance Table

Response: wgt
           Df Sum Sq Mean Sq F value    Pr(>F)    
hip.gi      1  52463   52463  703.49 < 2.2e-16 ***
Residuals 505  37661      75                      
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Si queremos calcular el modelo con la interacción por sexo.

lm.ajustado <- lm(wgt ~ hip.gi*sex ,data = bdims)
summary(lm.ajustado)

Call:
lm(formula = wgt ~ hip.gi * sex, data = bdims)

Residuals:
     Min       1Q   Median       3Q      Max 
-15.9539  -2.6721  -0.2353   2.6641  21.6628 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)    
(Intercept) -58.97920    3.96073 -14.891  < 2e-16 ***
hip.gi        1.25014    0.04130  30.270  < 2e-16 ***
sex          -7.67232    6.09012  -1.260 0.208326    
hip.gi:sex    0.23095    0.06274   3.681 0.000257 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 4.613 on 503 degrees of freedom
Multiple R-squared:  0.8812,    Adjusted R-squared:  0.8805 
F-statistic:  1244 on 3 and 503 DF,  p-value: < 2.2e-16

Para graficar el resultado, recupero los valores predichos, que estan guardados en el objeto generado por lm(), y se los agrego a la tabla original.

bdims$yhat <- lm.ajustado$fitted.values
ggplot(bdims, aes(group = sex, color = factor(sex))) + 
  geom_point(aes(hip.gi, wgt))+
  geom_line(aes(hip.gi, yhat))+
  theme_minimal()

La interacción resulta significativa, pero no la dummy. Además, parece que el término de interacción no es realmente necesario, sino más bien que es preferible el supuesto de que ambas poblaciones comparten la misma pendiente, con una diferente ordenada al origen.

Podemos probar qué sucede cuando en lugar de utilizar la interacción, simplemente agregamos la dummy de sexo

lm.ajustado <- lm(wgt ~ hip.gi + sex ,data = bdims)
lm.ajustado <- lm(wgt ~ hip.gi + sex ,data = bdims)
summary(lm.ajustado)

Call:
lm(formula = wgt ~ hip.gi + sex, data = bdims)

Residuals:
     Min       1Q   Median       3Q      Max 
-13.8293  -2.9544  -0.1366   2.4290  19.8266 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)    
(Intercept) -68.55225    3.02439  -22.67   <2e-16 ***
hip.gi        1.35022    0.03147   42.90   <2e-16 ***
sex          14.69455    0.42024   34.97   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 4.67 on 504 degrees of freedom
Multiple R-squared:  0.878, Adjusted R-squared:  0.8775 
F-statistic:  1814 on 2 and 504 DF,  p-value: < 2.2e-16

La diferencia en el R cuadrado ajustado es menor, por lo que por simplicidad eligiríamos este modelo.

Nuevamente, si queremos graficar ambas rectas, podemos recuperar los valores predichos

Logit

Por útlimo, hacemos un ejercicio simple de una regresión logística, que contrasta el deseo de trabajar más horas respecto a la cantidad de hroas trabajadas.

variables <- c('CH04',        # Sexo
               'PP3E_TOT',    # Horas trabajadas
               'PP03G')       # La semana pasada, ¿quería trabajar más horas? 1-Si 2-No
# Me quedo con los asalariados que respondieron sobre su ingreso
datos <- individual.416 %>% 
  select(variables) %>% 
   filter(!is.na(PP3E_TOT),
          !is.na(PP03G),
          !PP3E_TOT %in% c(0,999),
          PP03G    !=9) %>%
  mutate(PP03G= case_when(PP03G==1 ~ 1,
                          PP03G==2 ~ 0),
         Sexo = case_when(CH04==1 ~'Varon',
                          CH04==2 ~'Mujer')) %>% 
  select(-CH04)
datos
model <- glm(PP03G ~.,family=binomial(link='logit'),data=datos)
summary(model)

Call:
glm(formula = PP03G ~ ., family = binomial(link = "logit"), data = datos)

Deviance Residuals: 
    Min       1Q   Median       3Q      Max  
-1.4542  -0.5422  -0.4012  -0.2565   3.6664  

Coefficients:
             Estimate Std. Error z value Pr(>|z|)    
(Intercept)  0.089322   0.047374   1.885   0.0594 .  
PP3E_TOT    -0.070682   0.001607 -43.993   <2e-16 ***
SexoVaron    0.612064   0.044361  13.797   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

(Dispersion parameter for binomial family taken to be 1)

    Null deviance: 18255  on 22989  degrees of freedom
Residual deviance: 15865  on 22987  degrees of freedom
AIC: 15871

Number of Fisher Scoring iterations: 5

Si queremos graficarlo. Podemos utilizar lo valores estimados del modelo.

Otra opción es calcular dos modelos logit por separado, según sexo. Esto tiene la ventaja de que incluye los intervalos de confianza del modelo, y la desventaja de que no se trata de un mismo modelo con un control por sexo, sino de dos modelos calculados por separado.

 ggplot(datos, aes(x=PP3E_TOT, y=PP03G, color= Sexo, group=Sexo))+
  geom_jitter(alpha=0.03,width = 0,height = 0.01)+ 
  stat_smooth(method="glm", method.args=list(family="binomial"), se=T)+
  geom_vline(xintercept = 35, linetype= 'dashed')+
  labs(x = "Total de Horas trabajadas en la semana en la ocupación principal",
       y ="¿Quería trabajar más horas?",
       title= "Probabilidad de querer trabajar más horas según género")+
  theme_minimal()+
  theme(legend.position = "bottom",
        text = element_text(size=15))+
  scale_y_continuous(breaks = c(0,.5,1),labels = c("No","50%","Si"))+
  scale_x_continuous(limits = c(0,100))

LS0tDQp0aXRsZTogIlJlZ3Jlc2nDs24gbGluZWFsIg0KYXV0aG9yOiBEaWVnbyBLb3psb3dza2kNCmRhdGU6ICIzIGRlIG5vdmllbWJyZSBkZSAyMDE3Ig0Kb3V0cHV0OiANCiAgaHRtbF9ub3RlYm9vazoNCiAgICB0b2M6IHRydWUNCiAgICB0b2NfZmxvYXQ6IHRydWUgDQoNCi0tLQ0KDQojIFJlZ3Jlc2nDs24gbGluZWFsIGVuIFINCg0KTGltcGlhbW9zIGxhIG1lbW9yaWEgY29uIGBgYHJtKClgYGAgeSBgYGBnYygpYGBgLCBjYXJnYW1vcyBsb3MgZGlyZWN0b3Jpb3MgeSBjYXJnYW1vcyBsYXMgbGlicmVyw61hcyB5IGxhIGJhc2UgcXVlIHZhbW9zIGEgdXRpbGl6YXIuDQoNCmBgYHtyLCB3YXJuaW5nPUZBTFNFfQ0Kcm0obGlzdD1scygpKQ0KZ2MoKQ0KZGlyIDwtIHBhc3RlMChkaXJuYW1lKHJzdHVkaW9hcGk6OmdldEFjdGl2ZURvY3VtZW50Q29udGV4dCgpJHBhdGgpLCIvIikNCmJhc2VzLmRpciAgICAgIDwtICBwYXN0ZTAoZGlybmFtZShkaXIpLCIvRnVlbnRlcy8iKQ0KcmVzdWx0YWRvcy5kaXIgPC0gcGFzdGUwKGRpcm5hbWUoZGlyKSwiL1Jlc3VsdGFkb3MvIikNCg0KbGlicmFyeSh0aWR5dmVyc2UsIHdhcm4uY29uZmxpY3RzID0gRkFMU0UpDQoNCmluZGl2aWR1YWwuNDE2IDwtIHJlYWQudGFibGUocGFzdGUwKGJhc2VzLmRpciwgInVzdV9pbmRpdmlkdWFsX3Q0MTYudHh0IiksIHNlcD0iOyIsIGRlYz0iLCIsIGhlYWRlciA9IFRSVUUsIGZpbGwgPSBUUlVFKQ0KYGBgDQoNCkVsIG9iamV0aXZvIHNlcsOhIGhhY2VyIGluZmVyZW5jaWEgcmVzcGVjdG8gZGVsIGluZ3Jlc28gZGUgbGEgb2N1cGFjacOzbiBwcmluY2lwYWwgX19QMjFfXywgcGFyYSBlbGxvIHNlbGVjaW9uYW1vcyBsYXMgY29sdW1uYXMgY29uIGxhcyBxdWUgdHJhYmFqYXJlbW9zOiB2YXJpYWJsZSBkZXBlbmRpZW50ZSB5IGFsZ3VuYXMgcG9zaWJsZXMgY292YXJpYWJsZXM6DQoNCg0KVmFyaWFibGVzIGEgdXRpbGl6YXI6IA0KDQoqIFAyMTogTU9OVE8gREUgSU5HUkVTTyBERSBMQSBPQ1VQQUNJw5NOIFBSSU5DSVBBTA0KKiBOSVZFTF9FRA0KKiBFU1RBRE8NCiogQ0FUX09DVVANCiogQ0gwNDogU2V4bw0KKiBDSDA2OiBFZGFkDQoqIFBQMDRDOTk6IFRhbWHDsW8gZGVsIGVzdGFibGVjaW1pZW50bywgcmVkdWNpZG8NCiogUFAwN0g6IMK/UG9yIGVzZSB0cmFiYWpvIHRpZW5lIGRlc2N1ZW50byBqdWJpbGF0b3Jpbz8NCg0KDQpjcmVhbW9zIHVuIHZlY3RvciBwYXJhIHNlbGVjY2lvbmFyIGVzdGFzIHZhcmliYWxlcywgeSB1biB2ZWN0ciBxdWUgZXNwZWNpZmlxdWUgcXXDqSB2YXJpYWJsZXMgc29uIGNhdGVnw7NyaWNhcywgcGFyYSBjb252ZXJ0aXJsYXMgZW4gZmFjdG9yZXMuIF9fRXMgbmVjZXNhcmlvIGNvbnZlcnRpciBsYXMgdmFyaWFibGVzIGNhdGVnw7NyaWNhcyBhIGxhIGNsYXNlIGZhY3RvciwgcGFyYSBxdWUgZWwgYWxnb3LDrXRtbyBkZSByZWdyZXNpw7NuIGxpbmVhbCBsYXMgcmVjb25vemNhIGNvbW8gbG8gcXVlIHNvbl9fDQoNCkxhIGZ1bmNpw7NuIGBgYGxhcHBseSgpYGBgIGFwbGljYSBsYSBmdW5jacOzbiBgYGBmYWN0b3IoKWBgYCBhIHRvZGEgbGEgYGBgYmFzZVtmYWN0b3Jlc11gYGANCg0KYGBge3J9DQp2YXIgPC0gYygnUDIxJywnTklWRUxfRUQnLCdFU1RBRE8nLCdDQVRfT0NVUCcsICdDSDA0JywnQ0gwNicsJ1BQMDRDOTknLCdQUDA3SCcpDQoNCmJhc2UgPC0gaW5kaXZpZHVhbC40MTYgJT4lIA0KICBzZWxlY3QodmFyKQ0KDQpmYWN0b3JlcyA8LSBjKCdOSVZFTF9FRCcsJ0VTVEFETycsJ0NBVF9PQ1VQJywgJ0NIMDQnLCdQUDA0Qzk5JywnUFAwN0gnKQ0KDQpiYXNlW2ZhY3RvcmVzXSA8LSBsYXBwbHkoYmFzZVtmYWN0b3Jlc10sIGZhY3RvcikNCg0KIyBOb3MgcXVlZGFtb3Mgc8OzbG8gY29uIGxvcyB2YWxvcmVzIHBvc2l0aXZvcyBkZSBsYSB2YXJpYWJsZSBleHBsaWNhZGENCmJhc2UgPC0gYmFzZSAlPiUgZmlsdGVyKFAyMSA+MCkNCg0KYGBgDQoNCiMjIyBDb3JyZWxhY2nDs24geSB0ZXN0IGRlIGNvcnJlbGFjacOzbg0KDQorIFBhcmEgY2FsY3VsYXIgdW4gdGVzdCBkZSBjb3JyZWxhY8OzbiBkZSBQZWFyc29uIHV0aWxpemFtb3MgZWwgY29tYW5kbyBgYGBjb3IoKWBgYC4NCisgU2kgcXVlcmVtb3MgY2FsY3VsYXIgdW4gdGVzdCBkZSBoaXDDs3Rlc2lzIHNvYnJlIGxhIGNvcnJlbGFjacOzbiwgbyB1biBpbnRlcmF2YWxvIGRlIGNvbmZpYW56YSwgdXRpbGl6YW1vcyBgYGBjb3IudGVzdCgpYGBgDQorIFNpIG5vIHNlIGN1bXBsZW4gbG9zIHN1cGVzdG9zIGRlIFBlYXJzb24gKE5vcm1hbGlkYWQsIGluZGVwZW5kZW5jaWEsIGxpbmVhbGlkYWQgZW4gbGEgcmVsYWNpw7NuKSwgcG9kZW1vcyB1dGlsaXphciBlbCB0ZXN0IGRlIGNvcnJlbGFjacOzbiBubyBwYXJhbcOpdHJpY28gZGUgU3BlYXJtYW4gbyBrZW5kYWxsIGNvbiBlbCBwYXLDoW1ldHJvIGBgYG1ldGhvZCA9YGBgDQorIHNpIHF1ZXJlbW9zIHF1ZSBlbCB0ZXN0IHNlYSBhIHVuYSBjb2xhLCBsbyBwb2RlbW9zIGVzcGVjaWZpY2FyIGNvbiBlbCBwYXLDoW1ldHJvIGBgYGFsdGVybmF0aXZlID0gYGBgDQorIExhIHNpZ25pZmljYXRpdmlhZGQgcG9yIGRlZmF1bHQgZXMgMC45NSwgcGVybyBzZSBwdWVkZSBtb2RpZmljYXIgY29uIGVsIHBhcsOhbWV0cm8gYGBgY29uZi5sZXZlbCA9IGBgYA0KDQpgYGB7cn0NCmNvcihiYXNlJFAyMSwgYmFzZSRDSDA2KQ0KDQoNCmNvci50ZXN0KGJhc2UkUDIxLCBiYXNlJENIMDYpDQoNCg0KY29yLnRlc3QoYmFzZSRQMjEsIGJhc2UkQ0gwNixtZXRob2QgPSAic3BlYXJtYW4iKQ0KDQpgYGANCg0KIyMgUmVncmVzacOzbiBsaW5lYWwgDQoNCmNvbiBlbCBjb21hbmRvIGBgYGxtKClgYGAgcG9kZW1vcyBhanVzdGFyIGVsIG1vZGVsby4gQWxndW5vcyBwYXJhbWV0cm9zIGltcG9ydGFudGVzIGRlIGVzdGEgZnVuY2nDs24gc29uOg0KDQorIF9mb3JtdWxhXzogZGVmaW5pbW9zIGVsIG1vZGVsbyBjb21vIF8gWSB+IFggXy4NCiAgICAgICsgcmVncmVzaW9uIG11bHRpcGxlOiAgeSB+ICRYXzEgKyBYXzIgKyAuLi4gWF9uJC4NCiAgICAgICsgcmVncmVzacOzbiBwb2xpbsOzbWljYTogeSB+IGBgYHBvbHkoeCA9IFgsIGRlZ3JlZSA9IGspYGBgDQogICAgICArIGludGVyYWNjacOzbiBkZSB2YXJpYWJsZXM6IHkgfiAkWF8xKlhfMiQuIFNpIHPDs2xvIHF1ZXJlbW9zIGVsIHTDqXJtaW5vIGRlIGludGVyYWNjacOzbjogJFhfMTpYXzIkDQorIF9kYXRhXyA6IGVzcGVjaWZpY2Ftb3MgZWwgZGF0YXNldCBhIHV0aWxpemFyDQorIF9zdWJzZXRfIDogc2kgZGl2aWRpbW9zIGxhIG11ZXN0cmEgZW4gdHJhaW5pbmcgeSB0ZXN0aW5nLCBwb2RlbW9zIGluZGljYXIgZWwgc3ViY29uanVudG8gZGUgZW50cmVuYW1pZW50byBjb24gdW4gdmVjdG9yIHF1ZSBpbmRpcXVlIHN1cyBuw7ptZXJvcyBkZSBmaWxhDQoNCg0KDQojIyMgUmVncmVzacOzbiBsaW5lYWwgc2ltcGxlDQoNCkNvbWVuemFtb3MgcmVncmVzYW5kbyBhIFAyMSBjb250cmEgbGEgw7puaWNhIHZhcmlhYmxlIGNvbnRpbnVhIHF1ZSBzZWxlY2Npb25hbW9zLCBsYSBlZGFkLiAgICAgDQoNCkVsIG1vZGVsbyBwcm9wdWVzdG8gcmVzdWx0YQ0KDQokJA0KRShQX3syMX0vY2hfezA2fSk9IFxiZXRhXzAgKyBcYmV0YV8xIGNoX3swNn0NCiQkDQoNCg0KYGBge3J9DQptb2RlbG8uYWp1c3RhZG8gPC0gbG0oZm9ybXVsYSA9IFAyMSB+IENIMDYsIGRhdGEgPSBiYXNlKQ0KYGBgDQoNCkxhIGZ1bmNpw7NuIGBgYGxtKClgYGAgZ2VuZXJhIHVuIF9vYmpldG9fIHF1ZSBjb250aWVuZSB2YXJpYXMgcHJvcGllZGFkZXMgZGUgbGEgcmVncmVzacOzbiBxdWUgYWp1c3RhbW9zLg0KDQpjb24gYGBgc3VtbWFyeSgpYGBgIHBvZGVtb3MgYWNjZWRlciBsb3MgcHJpbmNpcGFsZXMgcmVzdWx0YWRvcw0KDQpgYGB7cn0NCnN1bW1hcnkobW9kZWxvLmFqdXN0YWRvKQ0KYGBgDQoNClBhcmEgcmV2aXNhciBsb3Mgc3VwdWVzdG9zIGRlbCBtb2RlbG8sIGFzw60gY29tbyBsYSBwb3NpYmxlIHByZXNlbmNpYSBkZSBvdXRsaWVycywgcG9kZW1vcyByZXZpc2FyIHVub3MgZ3LDoWZpY29zIHF1ZSBzZSBnZW5lcmFuIHbDrWEgZWwgY29tYW5kbyBgYGBwbG90KClgYGAuIA0KDQpgYGB7cn0NCnBsb3QobW9kZWxvLmFqdXN0YWRvKQ0KYGBgDQoNCisgUmVzaWR1YWxzIH4gRml0dGVkIHZhbHVlczogQXF1w60gYnVzY2Ftb3MgcXVlIG5vIGV4aXN0YSBuaW5nw7puYSBlc3RydWN0dXJhIGVuIGxvcyBkYXRvcy4gU2kgbGEgcHJlc2VudGFuLCBzZWfDum4gbGEgZm9ybWEgcXVlIHRvbWUsIHBvZHLDrWEgc2VyIHVuIGluZGljYWRvciBkZSBoZXRlcm9jZWRhc3RpY2lkYWQgbyBubyBsaW5lYWxpZGFkIGVuIGxhIHJlbGFjacOzbg0KKyBRUSBwbG90OiBNdWVzdHJhIHNpIGxvcyBkYXRvcyBzZSBhanVzdGFuIGFsIHN1cHVlc3RvIGRlIG5vcm1hbGlkYWQuIFNpIGxvcyBwdW50b3Mgc2UgdWJpY2FuIHNvYnJlIGxhIGxpbmVhIHB1bnRhZGEsIGVzdG8gaW5kaWNhIHF1ZSB0aWVuZW4gdW5hIGRpc3RyaWJ1Y2nDs24gbm9ybWFsLiBFbiBudWVzdHJvIGNhc28sIHBvZGVtb3MgdmVyIHF1ZSBzZSB2ZSBxdWUgc2UgYWxlamFuIGVuIGVsIGV4dHJlbW8gZGVyZWNobyBkZSBsYSBkaXN0cmlidWNpw7NuLg0KKyAkXHNxcnR7cmVzaWR1b3MgXHNwYWNlIGVzdGFuZGFyaXphZG9zfSQgfiBGaXR0ZWQgVmFsdWVzOiBFcyBzaW1pbGFyIGFsIHByaW1lciBncsOhZmljbywgY29uIG90cmEgZXNjYWxhLg0KKyBMZXZlcmFnZSB+IHJlc2lkdW9zIGVzdGFuZGFyaXphZG9zOiBOb3MgcGVybWl0ZSBlbmNvbnRyYXIgb2JzZXJ2YWNpb25lcyBpbmZsdXllbnRlcy4gRW4gcGFydGljdWxhciwgYXF1ZWxsYXMgcXVlIHF1ZWRlbiBmdWVyYSBkZSBsb3MgbcOhcmdlbmVzIGRlZmluaWRvcyBwb3IgbGEgZGlzdGFuY2lhIGRlIGNvb2sgZGViZXLDrWFuIHNlciByZXZpc2FkYXMuDQoNCiMjIyBSZWdyZXNpw7NuIGxpbmVhbCBtw7psdGlwbGUgDQoNCg0KJCQNCkUoUF97MjF9L1gpPSBcYmV0YV8wICsgXGJldGFfMSBjaF97MDZ9ICsgXGJldGFfMiBjaF97MDZ9XjINCiQkDQoNCmBgYHtyfQ0KbW9kZWxvLmFqdXN0YWRvIDwtIGxtKGZvcm11bGEgPSBQMjEgfiBwb2x5KHggPSBDSDA2LGRlZ3JlZSA9IDIpICwgZGF0YSA9IGJhc2UpDQoNCnN1bW1hcnkobW9kZWxvLmFqdXN0YWRvKQ0KYGBgDQoNCg0KU2kgcXVlcmVtb3MgZWxlZ2lyIGVsIG1lam9yIG1vZGVsbyBwb2xpbm9taWNvIGVudHJlIGxvcyBkZSBsYSBmb3JtYQ0KDQoNCiQkDQpFKFBfezIxfS9YKT0gXGJldGFfMCArIFxiZXRhXzEgY2hfezA2fSArIFxiZXRhXzIgY2hfezA2fV4yICsgLi4uICsgXGJldGFfbiBjaF97MDZ9Xm4gDQokJA0KDQoNCnBvZGVtb3MgaGFjZXIgdXNvIGRlIGxvcyBsb29wcywgcGFyYSBhanVzdGFyIHZhcmlvcyBtb2RlbG9zIHBvbGluw7NtaWNvcyBkZSBkaXN0aW50byBncmFkbywgeSBsdWVnbyBjb21wYXJhciBzdXMgciBjdWFkcmFkb3MgYWp1c3RhZG9zLg0KDQpgYGB7cn0NCnIuYWp1c3RhZG8gPC0gYygpDQpmb3IgKGkgaW4gMToxMCkgew0KDQogIG1vZGVsby5hanVzdGFkbyA8LSBsbShmb3JtdWxhID0gUDIxIH4gcG9seSh4ID0gQ0gwNixkZWdyZWUgPSBpKSAsIGRhdGEgPSBiYXNlKQ0KICByLmFqdXN0YWRvW2ldIDwtIHN1bW1hcnkobW9kZWxvLmFqdXN0YWRvKSRhZGouci5zcXVhcmVkICANCn0NCg0KcGxvdChyLmFqdXN0YWRvLCB0eXBlID0gImIiKQ0KDQpgYGANCg0KDQoNCiMjIyBSZWdyZXNpw7NuIGxpbmVhbCBjb24gdmFyaWFibGVzIGNhdGVnw7NyaWNhcw0KDQokJA0KRShQX3syMX0vWCk9IFxiZXRhXzAgKyBcYmV0YV8xIGNoX3swNn0gKyBcYmV0YV8yIGNhdC5vY3VwDQokJA0KDQpDQVRfT0NVUDoNCjEgPSBQYXRyw7NuDQoyID0gQ3VlbnRhIHByb3BpYQ0KMyA9IE9icmVybyBvIGVtcGxlYWRvDQoNCmBgYHtyfQ0KdGFibGUoYmFzZSRDQVRfT0NVUCkNCmBgYA0KDQpQYXJhIHV0aWxpemFyIGR1bW1pZXMsIG5vIGVzIG5lY2VzYXJpbyBxdWUgbGFzIGNyZWVtb3MsIHNpbXBsZW1lbnRlIGFncmVnYW1vcyBsYSB2YXJpYWJsZSBjYXRlZ8OzcmljYSwgeSBsYSBmdW5jacOzbiBzZSBlbmNhcmdhIGRlIGNyZWFyIGxhcyB2YXJpYWJsZXMuIA0KDQpgYGB7cn0NCm1vZGVsby5hanVzdGFkbyA8LSBsbShmb3JtdWxhID0gUDIxIH4gQ0gwNiArIENBVF9PQ1VQLCBkYXRhID0gYmFzZSkNCnN1bW1hcnkobW9kZWxvLmFqdXN0YWRvKQ0KDQpgYGANCg0KDQojIyMgQmVzdCBzdWJzZXQgc2VsZWN0aW9uDQoNClNpIHF1ZXJlbW9zIGhhY2VyIEJlc3Qgc3Vic2V0IHNlbGVjdGlvbiwgcG9kZW1vcyB1dGlsaXphciBlbCBwYXF1ZXRlIF9sZWFwc18sIGF1bnF1ZSBubyBlcyBlbCDDum5pY28uIEVsIGNvbWFuZG8gYGBgcmVnc3Vic2V0cygpYGBgIG5vcyBwZXJtaXRlIGhhY2VyIHNlbGVjY2nDs24gZGUgbW9kZWxvcyBleGFodXN0aXZhLCBhc8OtIGNvbW8gZm9yd2FyZCBvIGJhY2t3YXJkIHN0ZXB3aXNlLCBlbnRyZSBvdHJvcyBtw6l0b2Rvcy4gDQoNCg0KYGBge3J9DQpsaWJyYXJ5KGxlYXBzKQ0KbmFtZXMoYmFzZSkNCnJlZ3N1YnNldHMub3V0IDwtDQogICAgcmVnc3Vic2V0cyhQMjEgfiBOSVZFTF9FRCArIEVTVEFETyArIENBVF9PQ1VQICsgQ0gwNCArIENIMDYgKyBQUDA0Qzk5ICsgUFAwN0gsDQogICAgICAgICAgICAgICBkYXRhID0gYmFzZSwNCiAgICAgICAgICAgICAgIG5iZXN0ID0gMSwgICAgICAgIyAxIGJlc3QgbW9kZWwgZm9yIGVhY2ggbnVtYmVyIG9mIHByZWRpY3RvcnMNCiAgICAgICAgICAgICAgIG52bWF4ID0gTlVMTCwgICAgIyBOVUxMIGZvciBubyBsaW1pdCBvbiBudW1iZXIgb2YgdmFyaWFibGVzDQogICAgICAgICAgICAgICBmb3JjZS5pbiA9IE5VTEwsIGZvcmNlLm91dCA9IE5VTEwsDQogICAgICAgICAgICAgICBtZXRob2QgPSAiZXhoYXVzdGl2ZSIpDQpzdW1tYXJ5KHJlZ3N1YnNldHMub3V0KQ0KDQoNCg0KYGBgDQoNCg0KYGBge3J9DQojIyBBZGp1c3RlZCBSMg0KcGxvdChyZWdzdWJzZXRzLm91dCwgc2NhbGUgPSAiYWRqcjIiLCBtYWluID0gIkFkanVzdGVkIFJeMiIpDQoNCmBgYA0KDQpjb24gYGBgd2hpY2gubWF4KClgYGAgcG9kZW1vcyB1YmljYXIgZWwgbW9kZWxvIGNvbiBlbCBtZWpvciBhanVzdGUuIEVuIG51ZXN0cm8gY2FzbyBlbGVnaW1vcyBjb21wYXJhciBwb3IgJFJeMiQuDQoNCg0KYGBge3J9DQp3aGljaC5tYXgoc3VtbWFyeShyZWdzdWJzZXRzLm91dCkkYWRqcjIpDQpgYGANCg0KU2FiaWVuZG8gcXVlIGVsIG1vZGVsbyBjb24gMTMgY292YXJpYWJsZXMgZXMgZWwgcXVlIG1lam9yIGFqdXN0YSwgcG9kZW1vcyBvYnNlcnZhciBjb24gbcOhcyBkZXRhbGxlIGVsIG1lam9yIGRlIGxvcyBtb2RlbG9zIGNvbiAxMyBjb3ZhcmlhYmxlcw0KDQpgYGB7cn0NCnN1bW1hcnkocmVnc3Vic2V0cy5vdXQpJHdoaWNoWzEzLF0NCg0KYGBgDQoNCg0KQ29tbyBsYXMgZHVtbWllcyBkZSBsYSBtaXNtYSBjYXRlZ29yaWNhIHNlIGRlYmVuIGluY2x1aXIgdG9kYXMsIHPDs2xvIHB1ZWRvIGNvbmNsdWlyIHF1ZSBsYSB2YXJpYWJsZSBFU1RBRE8gbm8gZXMgc2lnbmlmaWNhdGl2YSBwYXJhIGVsIG1vZGVsbywgcGVybyB0b2RhcyBsYXMgZGVtw6FzIHPDrS4gQ29tbyBzZSB2w6ksIGVzdGUgbcOpdG9kbyBubyBlcyBtdXkgw7p0aWwgc2kgcGVuc2Ftb3MgdHJhYmFqYXIgY29uIG11Y2hhcyB2YXJpYWJsZXMgY2F0ZWfDs3JpY2FzLCB5YSBxdWUgbm8gcG9kZW1vcyBpbmRpY2FybGUgcXVlIHRvZGFzIGxhcyBkdW1taWVzIHBlcnRlbmVjaWVudGVzIGEgdW5hIG1pc21hIGNvdmFyaWFibGUgZGViZW4gc2VyIGNvbnNpZGVyYWRhcyBlbiBjb25qdW50byAocG9yIGxvIG1lbm9zIHBhcmEgZXN0YSBsaWJyZXLDrWEpLg0KDQoNCmBgYHtyfQ0KbW9kZWxvLmFqdXN0YWRvIDwtIGxtKFAyMSB+IE5JVkVMX0VEICsgQ0FUX09DVVAgKyBDSDA0ICsgQ0gwNiArIFBQMDRDOTkgKyBQUDA3SCwNCiAgICAgICAgICAgICAgIGRhdGEgPSBiYXNlKQ0Kc3VtbWFyeShtb2RlbG8uYWp1c3RhZG8pDQoNCmBgYA0KDQoNCg0KIyMgRWplbXBsbyB0cml2aWFsDQoNClBvciDDunRsaW1vLCB1dGlsaXphbW9zIHVuIGRhdGFzZXQgZGUgZGF0b3MgZGUgbWFudWFsLCBwYXJhIGhhY2VyIGFsZ3Vub3MgZWplcmNpY2lvcyBtw6FzLiBMb3MgZGF0b3Mgc29uIHRvbWFkb3MgZGUgSGVpbnosIFBldGVyc29uLCBKb2huc29uLCB5IEtlcmsgezIwMDN9LCB5IHNlIGVuY3VlbnRyYW4gZW4gbGEgYmFzZSBkZSBkYXRvcyBiZGltcyBkZWwgcGFxdWV0ZSBvcGVuaW50cm8uDQoNCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgcGFnZWQucHJpbnQ9RkFMU0V9DQpsaWJyYXJ5KG9wZW5pbnRybyx3YXJuLmNvbmZsaWN0cyA9IEZBTFNFKQ0KDQpgYGANCg0KDQpQcmltZXJvIHJlYWxpemFtb3MgdW4gZGlhZ3JhbWEgZGUgZGlzcGVyc2nDs24gcXVlIG11ZXN0cmUgbGEgcmVsYWNpw7NuIGVudHJlIGVsIHBlc28gbWVkaWRvIGVuIGtpbG9ncmFtb3MgKHdndCl5IGxhIGNpcmN1bmZlcmVuY2lhIGRlIGxhIGNhZGVyYSBtZWRpZGEgZW4gY2VudMOtbWV0cm9zIChoaXAuZ2kpLCBkaWZlcmVuY2lhbmRvIHBvciBzZXhvIChzZXggPSAxIHBhcmEgbG9zIGhvbWJyZXMgeSBzZXggPSAwIHBhcmEgbGFzIG11amVyZXMpDQoNCmBgYHtyfQ0KZ2dwbG90KGJkaW1zLCBhZXMoaGlwLmdpLCB3Z3QsIGNvbG9yID0gZmFjdG9yKHNleCkpKSArIGdlb21fcG9pbnQoKQ0KDQpgYGANCg0KUHJpbWVybyBjYWxjdWxhbW9zIGVsIG1vZGVsbyBzaW4gZGlmZXJlbmNpYXIgcG9yIHNleG8NCg0KYGBge3J9DQpsbS5hanVzdGFkbyA8LSBsbSh3Z3R+aGlwLmdpLGRhdGEgPSBiZGltcykNCnN1bW1hcnkobG0uYWp1c3RhZG8pDQpgYGANCg0KTG8gZ3JhZmljYW1vcw0KDQpgYGB7cn0NCnBsb3QoYmRpbXMkaGlwLmdpLGJkaW1zJHdndCkNCmFibGluZShsbS5hanVzdGFkbywgY29sID0gInJlZCIpDQpgYGANCg0KVW5hIGFsdGVybmF0aXZhIGVuIGdncGxvdCAobm8gdXRpbGl6YW1vcyBlbCBtb2RlbG8gY29uc3RydWlkbywgc2lubyBxdWUgbG8gdm9sdmVtb3MgYSBnZW5lcmFyKQ0KDQpgYGB7cn0NCg0KZ2dwbG90KGJkaW1zLCBhZXMoaGlwLmdpLCB3Z3QpKSArIA0KICBnZW9tX3BvaW50KCkrIA0KICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iKQ0KDQpgYGANCg0KIyMjIFByZWRpY2Npb24NCg0KUGFyYSBwcmVkZWNpciB1bmEgbnVldmEgb2JzZXJ2YWNpw7NuLCBwb2RlbW9zIGNhbHVsYXIgZWwgaW50ZXJ2YWxvIGRlIGNvbmZpYW56YSBvIGVsIGludGVydmFsbyBkZSBwcmVkaWNjacOzbiBjb24gZWwgY29tYW5kbyBgYGBwcmVkaWN0LmxtKClgYGAgICAgIA0KUG9yIGVqZW1wbG8sIHNpIGVsZWdpbW9zIHVuYSBwZXJzb25hIGNvbiBjb250b3JubyBkZSBjYWRlcmEgbWlkZSAxMDAgY20uDQoNCg0KYGBge3J9DQpuZXcgPC0gZGF0YS5mcmFtZShoaXAuZ2kgPSAxMDApDQojaW50ZXJ2YWxvIGRlIGNvbmZpYW56YQ0KcHJlZGljdC5sbShsbS5hanVzdGFkbyxuZXdkYXRhID0gbmV3LGludGVydmFsPSJjb25maWRlbmNlIixsZXZlbCA9IDAuOTUpDQojaW50ZXJ2YWxvIGRlIHByZWRpY2Npw7NuDQpwcmVkaWN0LmxtKGxtLmFqdXN0YWRvLG5ld2RhdGEgPSBuZXcsaW50ZXJ2YWw9InByZWRpY3Rpb24iLGxldmVsID0gMC45NSkNCmBgYA0KDQojIyMjIGFub3ZhDQoNClNvIHF1ZXJlbW9zIGxvcyBkYXRvcyBkZSBsYSB0YWJsYSBhbm92YSwgbG8gaGFjZW1vcyBjb24gZWwgY29tYW5kbyBgYGBhbm92YSgpYGBgIA0KDQpgYGB7cn0NCmFub3ZhKGxtLmFqdXN0YWRvKQ0KDQpgYGANCg0KDQpTaSBxdWVyZW1vcyBjYWxjdWxhciBlbCBtb2RlbG8gY29uIGxhIGludGVyYWNjacOzbiBwb3Igc2V4by4NCg0KYGBge3J9DQpsbS5hanVzdGFkbyA8LSBsbSh3Z3QgfiBoaXAuZ2kqc2V4ICxkYXRhID0gYmRpbXMpDQpzdW1tYXJ5KGxtLmFqdXN0YWRvKQ0KYGBgDQoNClBhcmEgZ3JhZmljYXIgZWwgcmVzdWx0YWRvLCByZWN1cGVybyBsb3MgdmFsb3JlcyBwcmVkaWNob3MsIHF1ZSBlc3RhbiBndWFyZGFkb3MgZW4gZWwgb2JqZXRvIGdlbmVyYWRvIHBvciBgYGBsbSgpYGBgLCB5IHNlIGxvcyBhZ3JlZ28gYSBsYSB0YWJsYSBvcmlnaW5hbC4NCmBgYHtyfQ0KDQpiZGltcyR5aGF0IDwtIGxtLmFqdXN0YWRvJGZpdHRlZC52YWx1ZXMNCg0KZ2dwbG90KGJkaW1zLCBhZXMoZ3JvdXAgPSBzZXgsIGNvbG9yID0gZmFjdG9yKHNleCkpKSArIA0KICBnZW9tX3BvaW50KGFlcyhoaXAuZ2ksIHdndCkpKw0KICBnZW9tX2xpbmUoYWVzKGhpcC5naSwgeWhhdCkpKw0KICB0aGVtZV9taW5pbWFsKCkNCg0KYGBgDQoNCg0KTGEgaW50ZXJhY2Npw7NuIHJlc3VsdGEgc2lnbmlmaWNhdGl2YSwgcGVybyBubyBsYSBkdW1teS4gQWRlbcOhcywgcGFyZWNlIHF1ZSBlbCB0w6lybWlubyBkZSBpbnRlcmFjY2nDs24gbm8gZXMgcmVhbG1lbnRlIG5lY2VzYXJpbywgc2lubyBtw6FzIGJpZW4gcXVlIGVzIHByZWZlcmlibGUgZWwgc3VwdWVzdG8gZGUgcXVlIGFtYmFzIHBvYmxhY2lvbmVzIGNvbXBhcnRlbiBsYSBtaXNtYSBwZW5kaWVudGUsIGNvbiB1bmEgZGlmZXJlbnRlIG9yZGVuYWRhIGFsIG9yaWdlbi4NCg0KUG9kZW1vcyBwcm9iYXIgcXXDqSBzdWNlZGUgY3VhbmRvIGVuIGx1Z2FyIGRlIHV0aWxpemFyIGxhIGludGVyYWNjacOzbiwgc2ltcGxlbWVudGUgYWdyZWdhbW9zIGxhIGR1bW15IGRlIHNleG8NCg0KDQpgYGB7cn0NCmxtLmFqdXN0YWRvIDwtIGxtKHdndCB+IGhpcC5naSArIHNleCAsZGF0YSA9IGJkaW1zKQ0Kc3VtbWFyeShsbS5hanVzdGFkbykNCg0KYGBgDQoNCkxhIGRpZmVyZW5jaWEgZW4gZWwgUiBjdWFkcmFkbyBhanVzdGFkbyBlcyBtZW5vciwgcG9yIGxvIHF1ZSBwb3Igc2ltcGxpY2lkYWQgZWxpZ2lyw61hbW9zIGVzdGUgbW9kZWxvLiAgICANCg0KTnVldmFtZW50ZSwgc2kgcXVlcmVtb3MgZ3JhZmljYXIgYW1iYXMgcmVjdGFzLCBwb2RlbW9zIHJlY3VwZXJhciBsb3MgdmFsb3JlcyBwcmVkaWNob3MNCg0KYGBge3J9DQoNCmJkaW1zJHloYXQgPC0gbG0uYWp1c3RhZG8kZml0dGVkLnZhbHVlcw0KDQpnZ3Bsb3QoYmRpbXMsIGFlcyhncm91cCA9IHNleCwgY29sb3IgPSBmYWN0b3Ioc2V4KSkpICsgDQogIGdlb21fcG9pbnQoYWVzKGhpcC5naSwgd2d0KSkrDQogIGdlb21fbGluZShhZXMoaGlwLmdpLCB5aGF0KSkrDQogIHRoZW1lX21pbmltYWwoKQ0KDQpgYGANCg0KDQoNCiMjIExvZ2l0DQoNClBvciDDunRsaW1vLCBoYWNlbW9zIHVuIGVqZXJjaWNpbyBzaW1wbGUgZGUgdW5hIHJlZ3Jlc2nDs24gbG9nw61zdGljYSwgcXVlIGNvbnRyYXN0YSBlbCBkZXNlbyBkZSB0cmFiYWphciBtw6FzIGhvcmFzIHJlc3BlY3RvIGEgbGEgY2FudGlkYWQgZGUgaHJvYXMgdHJhYmFqYWRhcy4NCg0KDQpgYGB7cn0NCnZhcmlhYmxlcyA8LSBjKCdDSDA0JywgICAgICAgICMgU2V4bw0KICAgICAgICAgICAgICAgJ1BQM0VfVE9UJywgICAgIyBIb3JhcyB0cmFiYWphZGFzDQogICAgICAgICAgICAgICAnUFAwM0cnKSAgICAgICAjIExhIHNlbWFuYSBwYXNhZGEsIMK/cXVlcsOtYSB0cmFiYWphciBtw6FzIGhvcmFzPyAxLVNpIDItTm8NCg0KIyBNZSBxdWVkbyBjb24gbG9zIGFzYWxhcmlhZG9zIHF1ZSByZXNwb25kaWVyb24gc29icmUgc3UgaW5ncmVzbw0KDQpkYXRvcyA8LSBpbmRpdmlkdWFsLjQxNiAlPiUgDQogIHNlbGVjdCh2YXJpYWJsZXMpICU+JSANCiAgIGZpbHRlcighaXMubmEoUFAzRV9UT1QpLA0KICAgICAgICAgICFpcy5uYShQUDAzRyksDQogICAgICAgICAgIVBQM0VfVE9UICVpbiUgYygwLDk5OSksDQogICAgICAgICAgUFAwM0cgICAgIT05KSAlPiUNCiAgbXV0YXRlKFBQMDNHPSBjYXNlX3doZW4oUFAwM0c9PTEgfiAxLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBQUDAzRz09MiB+IDApLA0KICAgICAgICAgU2V4byA9IGNhc2Vfd2hlbihDSDA0PT0xIH4nVmFyb24nLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBDSDA0PT0yIH4nTXVqZXInKSkgJT4lIA0KICBzZWxlY3QoLUNIMDQpDQpkYXRvcw0KDQpgYGANCg0KYGBge3J9DQptb2RlbCA8LSBnbG0oUFAwM0cgfi4sZmFtaWx5PWJpbm9taWFsKGxpbms9J2xvZ2l0JyksZGF0YT1kYXRvcykNCnN1bW1hcnkobW9kZWwpDQoNCmBgYA0KDQoNClNpIHF1ZXJlbW9zIGdyYWZpY2FybG8uIFBvZGVtb3MgdXRpbGl6YXIgbG8gdmFsb3JlcyBlc3RpbWFkb3MgZGVsIG1vZGVsby4NCg0KYGBge3J9DQpkYXRvcyR5aGF0IDwtIG1vZGVsJGZpdHRlZC52YWx1ZXMNCg0KZ2dwbG90KGRhdG9zLCBhZXMoZ3JvdXAgPSBTZXhvLCBjb2xvciA9IGZhY3RvcihTZXhvKSkpICsgDQogIGdlb21fbGluZShhZXMoUFAzRV9UT1QsIHloYXQpKSsNCiAgZ2VvbV9qaXR0ZXIoYWVzKFBQM0VfVE9ULFBQMDNHICksYWxwaGE9MC4wMyx3aWR0aCA9IDAsaGVpZ2h0ID0gMC4wMSkrDQogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDM1LCBsaW5ldHlwZT0gJ2Rhc2hlZCcpKw0KICBsYWJzKHggPSAiVG90YWwgZGUgSG9yYXMgdHJhYmFqYWRhcyBlbiBsYSBzZW1hbmEgZW4gbGEgb2N1cGFjacOzbiBwcmluY2lwYWwiLA0KICAgICAgIHkgPSLCv1F1ZXLDrWEgdHJhYmFqYXIgbcOhcyBob3Jhcz8iLA0KICAgICAgIHRpdGxlPSAiUHJvYmFiaWxpZGFkIGRlIHF1ZXJlciB0cmFiYWphciBtw6FzIGhvcmFzIHNlZ8O6biBnw6luZXJvIikrDQogIHRoZW1lX21pbmltYWwoKSsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsDQogICAgICAgIHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0xNSkpKw0KICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gYygwLC41LDEpLGxhYmVscyA9IGMoIk5vIiwiNTAlIiwiU2kiKSkrDQogIHNjYWxlX3hfY29udGludW91cyhsaW1pdHMgPSBjKDAsMTAwKSkNCmBgYA0KDQoNCk90cmEgb3BjacOzbiBlcyBjYWxjdWxhciBkb3MgbW9kZWxvcyBsb2dpdCBwb3Igc2VwYXJhZG8sIHNlZ8O6biBzZXhvLiBFc3RvIHRpZW5lIGxhIHZlbnRhamEgZGUgcXVlIGluY2x1eWUgbG9zIGludGVydmFsb3MgZGUgY29uZmlhbnphIGRlbCBtb2RlbG8sIHkgbGEgZGVzdmVudGFqYSBkZSBxdWUgbm8gc2UgdHJhdGEgZGUgdW4gbWlzbW8gbW9kZWxvIGNvbiB1biBjb250cm9sIHBvciBzZXhvLCBzaW5vIGRlIGRvcyBtb2RlbG9zIGNhbGN1bGFkb3MgcG9yIHNlcGFyYWRvLg0KDQoNCmBgYHtyfQ0KIGdncGxvdChkYXRvcywgYWVzKHg9UFAzRV9UT1QsIHk9UFAwM0csIGNvbG9yPSBTZXhvLCBncm91cD1TZXhvKSkrDQogIGdlb21faml0dGVyKGFscGhhPTAuMDMsd2lkdGggPSAwLGhlaWdodCA9IDAuMDEpKyANCiAgc3RhdF9zbW9vdGgobWV0aG9kPSJnbG0iLCBtZXRob2QuYXJncz1saXN0KGZhbWlseT0iYmlub21pYWwiKSwgc2U9VCkrDQogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDM1LCBsaW5ldHlwZT0gJ2Rhc2hlZCcpKw0KICBsYWJzKHggPSAiVG90YWwgZGUgSG9yYXMgdHJhYmFqYWRhcyBlbiBsYSBzZW1hbmEgZW4gbGEgb2N1cGFjacOzbiBwcmluY2lwYWwiLA0KICAgICAgIHkgPSLCv1F1ZXLDrWEgdHJhYmFqYXIgbcOhcyBob3Jhcz8iLA0KICAgICAgIHRpdGxlPSAiUHJvYmFiaWxpZGFkIGRlIHF1ZXJlciB0cmFiYWphciBtw6FzIGhvcmFzIHNlZ8O6biBnw6luZXJvIikrDQogIHRoZW1lX21pbmltYWwoKSsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsDQogICAgICAgIHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0xNSkpKw0KICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gYygwLC41LDEpLGxhYmVscyA9IGMoIk5vIiwiNTAlIiwiU2kiKSkrDQogIHNjYWxlX3hfY29udGludW91cyhsaW1pdHMgPSBjKDAsMTAwKSkNCg0KYGBgDQoNCg0KDQo=