En el análisis del mercado laboral es frecuente estudiar fenómenos expresados como conteos. A diferencia de una variable dicotómica, que registra si ocurre o no un evento, una variable de conteo mide cuántas veces ocurre un evento en un periodo determinado.
En esta guía se desarrolla la aplicación del modelo de regresión de Poisson para analizar el número de meses sin cotizar al seguro social. El ejemplo se plantea desde una perspectiva laboral, considerando que el conteo de meses sin cotización puede interpretarse como una medida de discontinuidad contributiva o fragilidad en la trayectoria de formalidad laboral.
La unidad de análisis será el trabajador asalariado observado durante un periodo de referencia. La variable dependiente será el conteo de meses en los que no registra cotización al seguro social. El objetivo será explicar cómo dicho conteo varía en función de características sociodemográficas y laborales.
En términos didácticos, esta guía mantiene una estructura similar a la utilizada para la regresión logística multinomial: primero se presenta el fundamento estadístico del modelo, luego se prepara una base de datos, se ajusta el modelo, se interpretan sus parámetros, se realizan predicciones y se evalúa el ajuste.
Al finalizar la guía, se espera que el estudiante sea capaz de:
glm().newdata.Supóngase que se dispone de información sobre trabajadores asalariados del sector privado y se desea analizar cuántos meses no cotizaron al seguro social durante los últimos 24 meses. La variable dependiente puede tomar valores enteros no negativos:
\[ Y_i = 0, 1, 2, 3, \ldots \]
donde \(Y_i\) representa el número de meses sin cotización del trabajador \(i\).
Desde el punto de vista sustantivo, valores más altos de \(Y_i\) indican mayor discontinuidad contributiva. En cambio, valores cercanos a cero indican mayor estabilidad en la cotización al seguro social.
En este contexto, algunas preguntas de interés son:
Una variable de conteo registra la cantidad de veces que ocurre un evento en una unidad de observación o en un intervalo de tiempo. En esta guía, el evento corresponde a un mes sin cotización al seguro social.
La variable dependiente debe cumplir tres características básicas:
Por ejemplo, para el caso de los meses sin cotizar:
\[ Y_i \in \{0,1,2,3,\ldots,24\} \]
si el periodo de observación corresponde a 24 meses.
La distribución de Poisson se utiliza para modelar conteos. Si la variable aleatoria \(Y_i\) sigue una distribución de Poisson con parámetro \(\lambda_i\), se escribe:
\[ Y_i \sim Poisson(\lambda_i) \]
La función de probabilidad es:
\[ P(Y_i = y_i) = \frac{e^{-\lambda_i}\lambda_i^{y_i}}{y_i!}, \quad y_i = 0,1,2,\ldots \]
El parámetro \(\lambda_i\) representa tanto la media como la varianza de la distribución:
\[ E(Y_i) = \lambda_i \]
\[ Var(Y_i) = \lambda_i \]
Esta igualdad entre media y varianza es conocida como el supuesto de equidispersión. En datos laborales reales, este supuesto puede no cumplirse, por lo que será necesario evaluarlo.
El modelo de regresión de Poisson relaciona la media esperada del conteo con un conjunto de variables explicativas. Debido a que \(\lambda_i\) debe ser positiva, se utiliza una función de enlace logarítmica:
\[ \log(\lambda_i) = \beta_0 + \beta_1X_{1i} + \beta_2X_{2i} + \cdots + \beta_kX_{ki} \]
Por lo tanto:
\[ \lambda_i = E(Y_i|X_i) = exp(\beta_0 + \beta_1X_{1i} + \cdots + \beta_kX_{ki}) \]
La expresión anterior indica que el modelo no estima directamente el conteo observado, sino el valor esperado del conteo para un perfil determinado de trabajador.
Para aplicar el modelo de Poisson deben considerarse los siguientes supuestos:
Cuando la varianza es mayor que la media, se presenta sobredispersión. En ese caso, puede utilizarse un modelo cuasi-Poisson o un modelo binomial negativo.
Para el desarrollo de la guía se utilizarán las siguientes librerías de R.
# Instalar previamente si fuera necesario:
# install.packages(c("dplyr", "ggplot2", "knitr", "broom", "MASS"))
library(dplyr)
library(ggplot2)
library(knitr)
library(broom)
library(MASS)
En ausencia de una base administrativa real, se construye una base de datos ficticia con fines didácticos. La base representa trabajadores asalariados observados durante los últimos 24 meses.
La variable dependiente será meses_sin_cotizar, que
registra el número de meses sin cotización al seguro social.
set.seed(123)
n <- 1200
datos <- data.frame(
sexo = sample(c("Hombre", "Mujer"), n, replace = TRUE, prob = c(0.52, 0.48)),
edad = round(pmin(pmax(rnorm(n, mean = 36, sd = 11), 18), 65)),
nivel_educ = sample(
c("Hasta primaria", "Secundaria", "Terciaria"),
n, replace = TRUE, prob = c(0.25, 0.50, 0.25)
),
tipo_contrato = sample(
c("Permanente", "Temporal", "Sin contrato escrito"),
n, replace = TRUE, prob = c(0.48, 0.30, 0.22)
),
tamano_empresa = sample(
c("Micro", "Pequeña", "Mediana/Grande"),
n, replace = TRUE, prob = c(0.45, 0.35, 0.20)
),
sector = sample(
c("Industria", "Comercio", "Servicios", "Construcción"),
n, replace = TRUE, prob = c(0.18, 0.32, 0.38, 0.12)
),
antiguedad = round(pmax(rnorm(n, mean = 4, sd = 3), 0), 1)
)
# Definir categorías de referencia
datos <- datos %>%
mutate(
sexo = factor(sexo, levels = c("Hombre", "Mujer")),
nivel_educ = factor(nivel_educ, levels = c("Terciaria", "Secundaria", "Hasta primaria")),
tipo_contrato = factor(tipo_contrato, levels = c("Permanente", "Temporal", "Sin contrato escrito")),
tamano_empresa = factor(tamano_empresa, levels = c("Mediana/Grande", "Pequeña", "Micro")),
sector = factor(sector, levels = c("Industria", "Comercio", "Servicios", "Construcción"))
)
# Generación del conteo esperado de meses sin cotizar
eta <- -0.50 +
0.015 * (datos$edad - 35) +
0.15 * (datos$sexo == "Mujer") +
0.18 * (datos$nivel_educ == "Secundaria") +
0.42 * (datos$nivel_educ == "Hasta primaria") +
0.45 * (datos$tipo_contrato == "Temporal") +
0.85 * (datos$tipo_contrato == "Sin contrato escrito") +
0.18 * (datos$tamano_empresa == "Pequeña") +
0.35 * (datos$tamano_empresa == "Micro") +
0.15 * (datos$sector == "Comercio") +
0.05 * (datos$sector == "Servicios") +
0.25 * (datos$sector == "Construcción") -
0.07 * datos$antiguedad
lambda <- exp(eta)
datos$meses_sin_cotizar <- rpois(n, lambda = lambda)
# Como se observa un periodo máximo de 24 meses, se limita el valor máximo.
datos$meses_sin_cotizar <- pmin(datos$meses_sin_cotizar, 24)
head(datos)
## sexo edad nivel_educ tipo_contrato tamano_empresa sector
## 1 Hombre 48 Secundaria Permanente Micro Comercio
## 2 Mujer 36 Terciaria Permanente Micro Servicios
## 3 Hombre 36 Secundaria Permanente Micro Construcción
## 4 Mujer 19 Secundaria Permanente Pequeña Construcción
## 5 Mujer 45 Secundaria Permanente Micro Comercio
## 6 Hombre 34 Hasta primaria Permanente Pequeña Construcción
## antiguedad meses_sin_cotizar
## 1 6,0 0
## 2 1,3 2
## 3 7,9 2
## 4 0,0 3
## 5 0,7 4
## 6 3,0 0
La base contiene variables que permiten aproximar características laborales asociadas a la continuidad contributiva. En un análisis con datos reales, estas variables deberían provenir de registros administrativos, encuestas laborales o de una integración entre ambas fuentes.
Antes de ajustar el modelo, es necesario analizar el comportamiento de la variable de conteo.
resumen_y <- datos %>%
summarise(
observaciones = n(),
media = mean(meses_sin_cotizar),
varianza = var(meses_sin_cotizar),
minimo = min(meses_sin_cotizar),
maximo = max(meses_sin_cotizar),
proporcion_ceros = mean(meses_sin_cotizar == 0)
)
kable(resumen_y, digits = 3, caption = "Resumen del conteo de meses sin cotizar")
| observaciones | media | varianza | minimo | maximo | proporcion_ceros |
|---|---|---|---|---|---|
| 1200 | 1,304 | 1,693 | 0 | 8 | 0,322 |
La comparación entre media y varianza es importante para evaluar preliminarmente el supuesto de equidispersión. Si la varianza es considerablemente mayor que la media, puede existir sobredispersión.
ggplot(datos, aes(x = meses_sin_cotizar)) +
geom_bar() +
labs(
title = "Distribución del número de meses sin cotizar",
x = "Meses sin cotizar",
y = "Cantidad de trabajadores"
) +
theme_minimal()
Como primera aproximación, se puede comparar el promedio de meses sin cotizar según algunas características laborales.
tabla_contrato <- datos %>%
group_by(tipo_contrato) %>%
summarise(
trabajadores = n(),
promedio_meses_sin_cotizar = mean(meses_sin_cotizar),
mediana = median(meses_sin_cotizar),
proporcion_ceros = mean(meses_sin_cotizar == 0),
.groups = "drop"
)
kable(tabla_contrato, digits = 3, caption = "Meses sin cotizar según tipo de contrato")
| tipo_contrato | trabajadores | promedio_meses_sin_cotizar | mediana | proporcion_ceros |
|---|---|---|---|---|
| Permanente | 594 | 0,973 | 1 | 0,396 |
| Temporal | 343 | 1,376 | 1 | 0,292 |
| Sin contrato escrito | 263 | 1,958 | 2 | 0,198 |
ggplot(tabla_contrato, aes(x = tipo_contrato, y = promedio_meses_sin_cotizar)) +
geom_col() +
labs(
title = "Promedio de meses sin cotizar según tipo de contrato",
x = "Tipo de contrato",
y = "Promedio de meses sin cotizar"
) +
theme_minimal()
Este análisis permite identificar diferencias descriptivas. Sin embargo, no controla simultáneamente por otras características. Para ello se ajusta un modelo de regresión de Poisson.
El modelo a estimar será:
\[ \log(\lambda_i) = \beta_0 + \beta_1 sexo_i + \beta_2 edad_i + \beta_3 nivel\_educ_i + \beta_4 tipo\_contrato_i + \beta_5 tamano\_empresa_i + \beta_6 sector_i + \beta_7 antiguedad_i \]
Donde:
\[ \lambda_i = E(Y_i|X_i) \]
representa la cantidad esperada de meses sin cotizar para el trabajador \(i\), dadas sus características.
El modelo de Poisson se ajusta mediante la función
glm(), especificando la familia poisson y el
enlace logarítmico.
modelo_poisson <- glm(
meses_sin_cotizar ~ sexo + edad + nivel_educ + tipo_contrato +
tamano_empresa + sector + antiguedad,
family = poisson(link = "log"),
data = datos
)
summary(modelo_poisson)
##
## Call:
## glm(formula = meses_sin_cotizar ~ sexo + edad + nivel_educ +
## tipo_contrato + tamano_empresa + sector + antiguedad, family = poisson(link = "log"),
## data = datos)
##
## Coefficients:
## Estimate Std. Error z value
## (Intercept) -0,862963 0,147713 -5,842
## sexoMujer 0,108279 0,050827 2,130
## edad 0,015950 0,002359 6,762
## nivel_educSecundaria 0,140296 0,064876 2,163
## nivel_educHasta primaria 0,307440 0,071760 4,284
## tipo_contratoTemporal 0,384224 0,062271 6,170
## tipo_contratoSin contrato escrito 0,765528 0,060926 12,565
## tamano_empresaPequeña 0,212522 0,078717 2,700
## tamano_empresaMicro 0,348614 0,074682 4,668
## sectorComercio 0,102079 0,075949 1,344
## sectorServicios -0,067898 0,075028 -0,905
## sectorConstrucción 0,277147 0,091112 3,042
## antiguedad -0,072722 0,009737 -7,468
## Pr(>|z|)
## (Intercept) 0,0000000051528454 ***
## sexoMujer 0,03314 *
## edad 0,0000000000135694 ***
## nivel_educSecundaria 0,03058 *
## nivel_educHasta primaria 0,0000183310752937 ***
## tipo_contratoTemporal 0,0000000006821668 ***
## tipo_contratoSin contrato escrito < 0,0000000000000002 ***
## tamano_empresaPequeña 0,00694 **
## tamano_empresaMicro 0,0000030419690403 ***
## sectorComercio 0,17894
## sectorServicios 0,36548
## sectorConstrucción 0,00235 **
## antiguedad 0,0000000000000811 ***
## ---
## Signif. codes: 0 '***' 0,001 '**' 0,01 '*' 0,05 '.' 0,1 ' ' 1
##
## (Dispersion parameter for poisson family taken to be 1)
##
## Null deviance: 1695,3 on 1199 degrees of freedom
## Residual deviance: 1387,5 on 1187 degrees of freedom
## AIC: 3411,1
##
## Number of Fisher Scoring iterations: 5
El resumen del modelo presenta los coeficientes estimados en escala logarítmica. Por lo tanto, la interpretación directa de los parámetros debe realizarse considerando que el modelo fue estimado sobre el logaritmo de la media esperada del conteo.
El signo del coeficiente permite conocer la dirección de la relación entre una variable explicativa y el número esperado de meses sin cotizar.
Esta interpretación permite identificar la orientación de la asociación, aunque no su intensidad.
Para interpretar la magnitud del efecto se utiliza la exponenciación del coeficiente:
\[ IRR_j = exp(\beta_j) \]
El valor \(IRR_j\) se conoce como razón de incidencias o razón de tasas. Su interpretación general es:
La variación porcentual aproximada se calcula como:
\[ (exp(\beta_j)-1) \times 100 \]
tabla_modelo <- tidy(modelo_poisson, conf.int = TRUE, exponentiate = FALSE) %>%
mutate(
IRR = exp(estimate),
variacion_porcentual = (IRR - 1) * 100,
orientacion = case_when(
estimate > 0 ~ "Aumenta el conteo esperado",
estimate < 0 ~ "Disminuye el conteo esperado",
TRUE ~ "Sin variación"
)
) %>%
dplyr::select(term, estimate, std.error, statistic, p.value, IRR, variacion_porcentual, orientacion)
kable(tabla_modelo, digits = 4, caption = "Coeficientes del modelo de Poisson e interpretación mediante IRR")
| term | estimate | std.error | statistic | p.value | IRR | variacion_porcentual | orientacion |
|---|---|---|---|---|---|---|---|
| (Intercept) | -0,8630 | 0,1477 | -5,8422 | 0,0000 | 0,4219 | -57,8090 | Disminuye el conteo esperado |
| sexoMujer | 0,1083 | 0,0508 | 2,1304 | 0,0331 | 1,1144 | 11,4359 | Aumenta el conteo esperado |
| edad | 0,0160 | 0,0024 | 6,7624 | 0,0000 | 1,0161 | 1,6078 | Aumenta el conteo esperado |
| nivel_educSecundaria | 0,1403 | 0,0649 | 2,1625 | 0,0306 | 1,1506 | 15,0614 | Aumenta el conteo esperado |
| nivel_educHasta primaria | 0,3074 | 0,0718 | 4,2843 | 0,0000 | 1,3599 | 35,9939 | Aumenta el conteo esperado |
| tipo_contratoTemporal | 0,3842 | 0,0623 | 6,1702 | 0,0000 | 1,4685 | 46,8474 | Aumenta el conteo esperado |
| tipo_contratoSin contrato escrito | 0,7655 | 0,0609 | 12,5650 | 0,0000 | 2,1501 | 115,0130 | Aumenta el conteo esperado |
| tamano_empresaPequeña | 0,2125 | 0,0787 | 2,6998 | 0,0069 | 1,2368 | 23,6794 | Aumenta el conteo esperado |
| tamano_empresaMicro | 0,3486 | 0,0747 | 4,6680 | 0,0000 | 1,4171 | 41,7102 | Aumenta el conteo esperado |
| sectorComercio | 0,1021 | 0,0759 | 1,3440 | 0,1789 | 1,1075 | 10,7470 | Aumenta el conteo esperado |
| sectorServicios | -0,0679 | 0,0750 | -0,9050 | 0,3655 | 0,9344 | -6,5645 | Disminuye el conteo esperado |
| sectorConstrucción | 0,2771 | 0,0911 | 3,0418 | 0,0024 | 1,3194 | 31,9360 | Aumenta el conteo esperado |
| antiguedad | -0,0727 | 0,0097 | -7,4685 | 0,0000 | 0,9299 | -7,0140 | Disminuye el conteo esperado |
Se considera la variable tipo_contrato. La categoría de
referencia es Permanente. Por lo tanto, los coeficientes de
las categorías Temporal y Sin contrato escrito
se interpretan en comparación con trabajadores con contrato permanente,
manteniendo constantes las demás variables del modelo.
coef_contrato <- tabla_modelo %>%
filter(grepl("tipo_contrato", term)) %>%
dplyr::select(term, estimate, IRR, variacion_porcentual, orientacion, p.value)
kable(coef_contrato, digits = 4, caption = "Interpretación de la variable tipo de contrato")
| term | estimate | IRR | variacion_porcentual | orientacion | p.value |
|---|---|---|---|---|---|
| tipo_contratoTemporal | 0,3842 | 1,4685 | 46,8474 | Aumenta el conteo esperado | 0 |
| tipo_contratoSin contrato escrito | 0,7655 | 2,1501 | 115,0130 | Aumenta el conteo esperado | 0 |
Si el coeficiente asociado a tipo_contratoTemporal es
positivo, esto indica que los trabajadores con contrato temporal
presentan una cantidad esperada de meses sin cotizar mayor que los
trabajadores con contrato permanente, manteniendo constantes las demás
variables.
En términos de razón de incidencias, si el IRR es mayor que 1, la cantidad esperada de meses sin cotizar es proporcionalmente mayor para trabajadores con contrato temporal respecto de la categoría de referencia.
Se considera la variable antiguedad, medida en años. Su
coeficiente indica cómo cambia el número esperado de meses sin cotizar
ante un aumento de un año en la antigüedad laboral, manteniendo
constantes las demás variables.
coef_antiguedad <- tabla_modelo %>%
filter(term == "antiguedad") %>%
dplyr::select(term, estimate, IRR, variacion_porcentual, orientacion, p.value)
kable(coef_antiguedad, digits = 4, caption = "Interpretación de la variable antigüedad")
| term | estimate | IRR | variacion_porcentual | orientacion | p.value |
|---|---|---|---|---|---|
| antiguedad | -0,0727 | 0,9299 | -7,014 | Disminuye el conteo esperado | 0 |
Si el coeficiente de antiguedad es negativo, se
interpreta que una mayor antigüedad laboral se asocia con una menor
cantidad esperada de meses sin cotizar. En términos laborales, esto
puede reflejar que la estabilidad en el empleo está asociada con una
mayor continuidad contributiva.
Para evaluar si el conjunto de variables explicativas mejora el ajuste respecto de un modelo sin covariables, se puede utilizar una prueba de razón de verosimilitud.
El modelo nulo se especifica como:
\[ \log(\lambda_i) = \beta_0 \]
Luego se compara el modelo nulo con el modelo completo.
modelo_nulo <- glm(
meses_sin_cotizar ~ 1,
family = poisson(link = "log"),
data = datos
)
anova(modelo_nulo, modelo_poisson, test = "Chisq")
## Analysis of Deviance Table
##
## Model 1: meses_sin_cotizar ~ 1
## Model 2: meses_sin_cotizar ~ sexo + edad + nivel_educ + tipo_contrato +
## tamano_empresa + sector + antiguedad
## Resid. Df Resid. Dev Df Deviance Pr(>Chi)
## 1 1199 1695,3
## 2 1187 1387,5 12 307,86 < 0,00000000000000022 ***
## ---
## Signif. codes: 0 '***' 0,001 '**' 0,01 '*' 0,05 '.' 0,1 ' ' 1
La hipótesis nula de la prueba global sostiene que los coeficientes de las variables explicativas son conjuntamente iguales a cero. Un valor-p pequeño permite rechazar la hipótesis nula y concluir que el modelo con variables explicativas mejora el ajuste respecto del modelo nulo.
newdataUno de los usos más importantes del modelo ajustado es la predicción
para perfiles laborales específicos. Para ello se utiliza la función
predict() con el argumento newdata.
El argumento newdata debe contener un nuevo
data.frame con las mismas variables explicativas utilizadas
en el modelo. Además, las variables categóricas deben conservar los
mismos niveles que en la base original.
Se construyen tres perfiles de trabajadores:
perfiles <- data.frame(
sexo = factor(c("Hombre", "Mujer", "Mujer"), levels = levels(datos$sexo)),
edad = c(35, 35, 35),
nivel_educ = factor(c("Terciaria", "Secundaria", "Hasta primaria"), levels = levels(datos$nivel_educ)),
tipo_contrato = factor(c("Permanente", "Temporal", "Sin contrato escrito"), levels = levels(datos$tipo_contrato)),
tamano_empresa = factor(c("Mediana/Grande", "Pequeña", "Micro"), levels = levels(datos$tamano_empresa)),
sector = factor(c("Industria", "Comercio", "Construcción"), levels = levels(datos$sector)),
antiguedad = c(6, 3, 1)
)
perfiles
## sexo edad nivel_educ tipo_contrato tamano_empresa sector
## 1 Hombre 35 Terciaria Permanente Mediana/Grande Industria
## 2 Mujer 35 Secundaria Temporal Pequeña Comercio
## 3 Mujer 35 Hasta primaria Sin contrato escrito Micro Construcción
## antiguedad
## 1 6
## 2 3
## 3 1
La predicción se realiza en escala de respuesta, es decir, en cantidad esperada de meses sin cotizar.
perfiles$prediccion_meses <- predict(
modelo_poisson,
newdata = perfiles,
type = "response"
)
kable(perfiles, digits = 3, caption = "Predicción del número esperado de meses sin cotizar")
| sexo | edad | nivel_educ | tipo_contrato | tamano_empresa | sector | antiguedad | prediccion_meses |
|---|---|---|---|---|---|---|---|
| Hombre | 35 | Terciaria | Permanente | Mediana/Grande | Industria | 6 | 0,477 |
| Mujer | 35 | Secundaria | Temporal | Pequeña | Comercio | 3 | 1,529 |
| Mujer | 35 | Hasta primaria | Sin contrato escrito | Micro | Construcción | 1 | 4,177 |
La columna prediccion_meses representa la cantidad
esperada de meses sin cotización para cada perfil laboral. Estos valores
no son categorías, sino promedios esperados condicionales al conjunto de
variables incluidas en el modelo.
El modelo de Poisson supone que la media y la varianza condicional del conteo son iguales. Como aproximación inicial, se compara la media y la varianza observada de la variable dependiente.
media_y <- mean(datos$meses_sin_cotizar)
varianza_y <- var(datos$meses_sin_cotizar)
relacion_var_media <- varianza_y / media_y
data.frame(
media = media_y,
varianza = varianza_y,
razon_varianza_media = relacion_var_media
) %>%
kable(digits = 3, caption = "Relación entre varianza y media observada")
| media | varianza | razon_varianza_media |
|---|---|---|
| 1,304 | 1,693 | 1,298 |
Una razón entre varianza y media considerablemente mayor que 1 puede ser una señal preliminar de sobredispersión.
Una forma más adecuada de evaluar sobredispersión consiste en calcular el estadístico de dispersión basado en los residuos de Pearson:
\[ \hat{\phi} = \frac{\sum r_i^2}{gl} \]
Donde \(r_i\) son los residuos de Pearson y \(gl\) son los grados de libertad residuales.
dispersion_pearson <- sum(residuals(modelo_poisson, type = "pearson")^2) /
modelo_poisson$df.residual
dispersion_pearson
## [1] 1,01874
Como regla práctica, valores cercanos a 1 son compatibles con el supuesto de equidispersión. Valores claramente superiores a 1 sugieren sobredispersión.
datos$residuos_pearson <- residuals(modelo_poisson, type = "pearson")
datos$ajustados <- fitted(modelo_poisson)
ggplot(datos, aes(x = ajustados, y = residuos_pearson)) +
geom_point(alpha = 0.4) +
geom_hline(yintercept = 0, linetype = "dashed") +
labs(
title = "Residuos de Pearson versus valores ajustados",
x = "Valores ajustados",
y = "Residuos de Pearson"
) +
theme_minimal()
El gráfico permite observar si existen patrones sistemáticos en los residuos. Un patrón marcado podría sugerir problemas de especificación del modelo.
Si se detecta sobredispersión, las inferencias del modelo de Poisson pueden ser demasiado optimistas, especialmente porque los errores estándar podrían estar subestimados. En ese caso, pueden considerarse dos alternativas: el modelo cuasi-Poisson y el modelo binomial negativo.
El modelo cuasi-Poisson mantiene la misma media condicional que el modelo de Poisson, pero permite que la varianza sea proporcional a la media.
modelo_quasi <- glm(
meses_sin_cotizar ~ sexo + edad + nivel_educ + tipo_contrato +
tamano_empresa + sector + antiguedad,
family = quasipoisson(link = "log"),
data = datos
)
summary(modelo_quasi)
##
## Call:
## glm(formula = meses_sin_cotizar ~ sexo + edad + nivel_educ +
## tipo_contrato + tamano_empresa + sector + antiguedad, family = quasipoisson(link = "log"),
## data = datos)
##
## Coefficients:
## Estimate Std. Error t value
## (Intercept) -0,862963 0,149091 -5,788
## sexoMujer 0,108279 0,051301 2,111
## edad 0,015950 0,002381 6,700
## nivel_educSecundaria 0,140296 0,065481 2,143
## nivel_educHasta primaria 0,307440 0,072429 4,245
## tipo_contratoTemporal 0,384224 0,062852 6,113
## tipo_contratoSin contrato escrito 0,765528 0,061494 12,449
## tamano_empresaPequeña 0,212522 0,079452 2,675
## tamano_empresaMicro 0,348614 0,075379 4,625
## sectorComercio 0,102079 0,076658 1,332
## sectorServicios -0,067898 0,075727 -0,897
## sectorConstrucción 0,277147 0,091962 3,014
## antiguedad -0,072722 0,009828 -7,399
## Pr(>|t|)
## (Intercept) 0,000000009099072 ***
## sexoMujer 0,03501 *
## edad 0,000000000032132 ***
## nivel_educSecundaria 0,03235 *
## nivel_educHasta primaria 0,000023594732249 ***
## tipo_contratoTemporal 0,000000001323229 ***
## tipo_contratoSin contrato escrito < 0,0000000000000002 ***
## tamano_empresaPequeña 0,00758 **
## tamano_empresaMicro 0,000004160154183 ***
## sectorComercio 0,18324
## sectorServicios 0,37011
## sectorConstrucción 0,00264 **
## antiguedad 0,000000000000258 ***
## ---
## Signif. codes: 0 '***' 0,001 '**' 0,01 '*' 0,05 '.' 0,1 ' ' 1
##
## (Dispersion parameter for quasipoisson family taken to be 1,018746)
##
## Null deviance: 1695,3 on 1199 degrees of freedom
## Residual deviance: 1387,5 on 1187 degrees of freedom
## AIC: NA
##
## Number of Fisher Scoring iterations: 5
Este modelo ajusta los errores estándar para contemplar la sobredispersión, aunque no permite comparar modelos mediante AIC, porque no se basa en una verosimilitud completa.
El modelo binomial negativo es una alternativa cuando la varianza es mayor que la media y se desea modelar explícitamente la sobredispersión.
modelo_nb <- glm.nb(
meses_sin_cotizar ~ sexo + edad + nivel_educ + tipo_contrato +
tamano_empresa + sector + antiguedad,
data = datos
)
summary(modelo_nb)
##
## Call:
## glm.nb(formula = meses_sin_cotizar ~ sexo + edad + nivel_educ +
## tipo_contrato + tamano_empresa + sector + antiguedad, data = datos,
## init.theta = 87.95256438, link = log)
##
## Coefficients:
## Estimate Std. Error z value
## (Intercept) -0,864204 0,148883 -5,805
## sexoMujer 0,109115 0,051280 2,128
## edad 0,015947 0,002381 6,699
## nivel_educSecundaria 0,140246 0,065394 2,145
## nivel_educHasta primaria 0,307012 0,072396 4,241
## tipo_contratoTemporal 0,384648 0,062741 6,131
## tipo_contratoSin contrato escrito 0,765484 0,061511 12,445
## tamano_empresaPequeña 0,214021 0,079330 2,698
## tamano_empresaMicro 0,349678 0,075281 4,645
## sectorComercio 0,101726 0,076593 1,328
## sectorServicios -0,068551 0,075632 -0,906
## sectorConstrucción 0,277327 0,092009 3,014
## antiguedad -0,072650 0,009820 -7,398
## Pr(>|z|)
## (Intercept) 0,000000006452092 ***
## sexoMujer 0,03335 *
## edad 0,000000000020997 ***
## nivel_educSecundaria 0,03198 *
## nivel_educHasta primaria 0,000022281563177 ***
## tipo_contratoTemporal 0,000000000875028 ***
## tipo_contratoSin contrato escrito < 0,0000000000000002 ***
## tamano_empresaPequeña 0,00698 **
## tamano_empresaMicro 0,000003400906816 ***
## sectorComercio 0,18414
## sectorServicios 0,36474
## sectorConstrucción 0,00258 **
## antiguedad 0,000000000000138 ***
## ---
## Signif. codes: 0 '***' 0,001 '**' 0,01 '*' 0,05 '.' 0,1 ' ' 1
##
## (Dispersion parameter for Negative Binomial(87,9526) family taken to be 1)
##
## Null deviance: 1672,7 on 1199 degrees of freedom
## Residual deviance: 1369,8 on 1187 degrees of freedom
## AIC: 3413
##
## Number of Fisher Scoring iterations: 1
##
##
## Theta: 88
## Std. Err.: 234
##
## 2 x log-likelihood: -3384,973
Se puede comparar el AIC del modelo de Poisson y del modelo binomial negativo.
AIC(modelo_poisson, modelo_nb)
## df AIC
## modelo_poisson 13 3411,118
## modelo_nb 14 3412,973
Un menor AIC indica mejor ajuste relativo, aunque la selección del modelo debe considerar también la coherencia teórica y la interpretación sustantiva.
En caso de sobredispersión, puede ser útil comparar las predicciones del modelo de Poisson y del modelo binomial negativo para los mismos perfiles laborales.
perfiles$pred_poisson <- predict(modelo_poisson, newdata = perfiles, type = "response")
perfiles$pred_binomial_negativo <- predict(modelo_nb, newdata = perfiles, type = "response")
kable(perfiles, digits = 3, caption = "Predicción comparada entre Poisson y binomial negativo")
| sexo | edad | nivel_educ | tipo_contrato | tamano_empresa | sector | antiguedad | prediccion_meses | pred_poisson | pred_binomial_negativo |
|---|---|---|---|---|---|---|---|---|---|
| Hombre | 35 | Terciaria | Permanente | Mediana/Grande | Industria | 6 | 0,477 | 0,477 | 0,476 |
| Mujer | 35 | Secundaria | Temporal | Pequeña | Comercio | 3 | 1,529 | 1,529 | 1,531 |
| Mujer | 35 | Hasta primaria | Sin contrato escrito | Micro | Construcción | 1 | 4,177 | 4,177 | 4,178 |
La lectura sustantiva del modelo debe vincular los resultados estadísticos con el fenómeno laboral analizado. En este caso, el conteo de meses sin cotizar al seguro social puede entenderse como un indicador de discontinuidad contributiva.
Desde esta perspectiva:
tipo_contratoTemporal
indicaría que los trabajadores con contrato temporal acumulan más meses
esperados sin cotización que los trabajadores con contrato
permanente;tipo_contratoSin contrato escrito indicaría una mayor
discontinuidad contributiva respecto de trabajadores con contrato
permanente;antiguedad indicaría que la
permanencia en el empleo se asocia con menor cantidad esperada de meses
sin cotización;tamano_empresaMicro
indicaría que los trabajadores de microempresas presentan mayor cantidad
esperada de meses sin cotizar en comparación con trabajadores de
empresas medianas o grandes.La interpretación debe realizarse siempre manteniendo constantes las demás variables incluidas en el modelo.
En una aplicación con registros administrativos o encuestas laborales, es necesario considerar los siguientes aspectos:
Si algunos trabajadores fueron observados durante distintos números
de meses, el modelo debe incorporar un offset. Por ejemplo, si
meses_observados indica la exposición de cada trabajador,
el modelo sería:
modelo_poisson_offset <- glm(
meses_sin_cotizar ~ sexo + edad + nivel_educ + tipo_contrato +
tamano_empresa + sector + antiguedad + offset(log(meses_observados)),
family = poisson(link = "log"),
data = datos_reales
)
En este caso, el modelo estima una tasa de meses sin cotizar por unidad de exposición, en lugar de un conteo bruto.
Utilizando la base datos, realice lo siguiente:
meses_sin_cotizar.nivel_educ.Ajuste un modelo de Poisson considerando como variable dependiente
meses_sin_cotizar y como variables explicativas:
sexoedadnivel_eductipo_contratotamano_empresasectorantiguedadLuego responda:
Construya tres perfiles laborales hipotéticos y estime la cantidad esperada de meses sin cotizar para cada uno. Luego responda:
A partir del modelo ajustado:
El siguiente bloque resume el flujo básico de trabajo para ajustar el modelo de Poisson.
# 1. Cargar librerías
library(dplyr)
library(broom)
library(MASS)
# 2. Ajustar modelo de Poisson
modelo_poisson <- glm(
meses_sin_cotizar ~ sexo + edad + nivel_educ + tipo_contrato +
tamano_empresa + sector + antiguedad,
family = poisson(link = "log"),
data = datos
)
# 3. Revisar resultados
summary(modelo_poisson)
# 4. Calcular razón de incidencias
tidy(modelo_poisson) %>%
mutate(
IRR = exp(estimate),
variacion_porcentual = (IRR - 1) * 100
)
# 5. Evaluar sobredispersión
dispersion_pearson <- sum(residuals(modelo_poisson, type = "pearson")^2) /
modelo_poisson$df.residual
dispersion_pearson
# 6. Modelo alternativo si existe sobredispersión
modelo_nb <- glm.nb(
meses_sin_cotizar ~ sexo + edad + nivel_educ + tipo_contrato +
tamano_empresa + sector + antiguedad,
data = datos
)
summary(modelo_nb)
Agresti, A. (2013). Categorical Data Analysis. Wiley.
Cameron, A. C., & Trivedi, P. K. (2013). Regression Analysis of Count Data. Cambridge University Press.
Hilbe, J. M. (2014). Modeling Count Data. Cambridge University Press.
Long, J. S. (1997). Regression Models for Categorical and Limited Dependent Variables. SAGE Publications.
Venables, W. N., & Ripley, B. D. (2002). Modern Applied Statistics with S. Springer.
R Core Team. R: A Language and Environment for Statistical Computing. R Foundation for Statistical Computing.
Wickham, H., François, R., Henry, L., Müller, K., & Vaughan, D. dplyr: A Grammar of Data Manipulation.
Wickham, H. ggplot2: Elegant Graphics for Data Analysis. Springer.
Robinson, D., Hayes, A., & Couch, S. broom: Convert Statistical Objects into Tidy Tibbles.