# Instalación de paquete pacman
# Función p_load permite evaluar si instalar y/o cargar paquetes
# install.packages("pacman") # ejecutar sólo si no está instalado
pacman::p_load(tidyverse, # funciones generales
haven, # manipulación archivos spss
srvyr, # para implementar ponderadores
gtsummary, # herramientas para diseñar tablas de resultados
kableExtra, # para formato de tablas
modelsummary, # diseño tablas de regresión
summarytools) # herramientas para estadísticos de resumen
options(OutDec = ",") # Separador decimalTrabajo Seminario Doctorado
Anexo de análisis de datos con R
1 Presentación
El presente documento busca funcionar como respaldo para el trabajo del seminario Herramientas metodológicas cuantitativas para el estudio de la desigualdad, la estructura social y la pobreza dictado por la docente Jésica Pla y el docente Santiago Poy durante 2024. A continuación se detalla el procesamiento de la fuente de datos consignada en el informe, dejando a la vista un código reproducible como respaldo del trabajo de análisis de datos.
2 Procesamiento inicial de los datos
2.1 Entorno de trabajo
Se utiliza un proyecto de R (.Rproj) con las siguientes carpetas:
codigo
datos
resultados
Se prepara el entorno de trabajo instalando los paquetes necesarios para preparación y análisis de datos.
2.2 Lectura de base de datos original
La base de datos de CASEN 2022 -y toda la documentación asociada- se encuentra para descarga en el repositorio oficial de la encuesta. La descarga se realizó de manera manual y se descomprimió en la carpeta datos ya indicada. Luego, para facilitar su procesamiento se cargó en R y se guardo en formato .rds. Se indica el código de este último paso a continuación.
casen <- haven::read_sav("datos/Base de datos Casen 2022 SPSS_18 marzo 2024.sav")
saveRDS(casen, file = "datos/casen22.rds")
remove(casen) # eliminar del entorno base de origen SAVPosteriormente leemos la base de datos de CASEN 2022 en formato .rds.
casen22 <- readRDS("datos/casen22.rds")2.3 Preparación de variables para análisis
A continuación se seleccionan las variables consideradas para el análisis.
# Seleccionar variables de interés desde bbdd completa
casen_vars <- casen22 %>%
select(expr, varstrat, varunit, # diseño muestral complejo
folio, pco1, # identificación hogar y jefatura
pobreza, # pobreza
sexo, edad, area) # variables de segmentación
# Eliminar base completa para maximizar ram
remove(casen22)Luego se preparan para el análisis. Se eliminan los atributos del objeto que vienen desde el formato SPSS; se editan y colapsan etiquetas cuando es necesario; se filtran los casos de interés para el análisis.
# configurar variables (eliminar configuraciones específicas de SPSS)
casen_vars <- casen_vars %>%
mutate_at(vars(1:5,8), ~as.numeric(.)) %>% # diseño muestral y edad como numeric
mutate_if(
is.labelled,
funs(as_factor(.))) %>%
mutate(across(everything(), ~ {
attr(.x, "label") <- NULL
.x
}))
# Colapsar codificación de pobreza
casen_vars$pobreza <- fct_collapse(casen_vars$pobreza,
Pobre = c("Pobreza extrema", "Pobreza no extrema"),
`No pobre` = "No pobreza")
# Editar etiquetas de respuesta de sexo
levels(casen_vars$sexo) <- sub("^\\d+\\.\\s*", "", levels(casen_vars$sexo))
# Crear edad en tramos
casen_vars <- casen_vars |>
mutate(
edad_tramo = case_when(
edad < 18 ~ "NNA",
edad >= 18 & edad <= 29 ~ "Joven",
edad >= 30 & edad <= 60 ~ "Adulto",
edad > 60 ~ "Tercera edad"),
edad_tramo = factor(
edad_tramo,
levels = c("NNA", "Joven", "Adulto", "Tercera edad")
)
)
# Identificador de personas en hogares de jefatura femenina
casen_vars <- casen_vars |>
group_by(folio) |>
mutate(
jefatura = if (any(pco1 == 1 & sexo == "Mujer")) {
"Femenina"
} else {
"Masculina"
}
) |>
ungroup()
# Variable jefatura: definir como factor
casen_vars$jefatura <- as.factor(casen_vars$jefatura)
# Seleccionar casos completos en variable de analisis
casen_vars <- casen_vars |>
filter(!is.na(pobreza))3 Resultados bivariados
3.1 Tabla de asociación entre variables
# Lista de variables categóricas
data <- select(casen_vars, pobreza, sexo, jefatura, area, edad_tramo)
vars <- c("pobreza", "sexo", "jefatura", "area", "edad_tramo")
# Obtener todas las combinaciones posibles de 2 variables
pares <- combn(vars, 2, simplify = FALSE)
# Función para calcular chi-cuadrado y extraer estadísticas clave
chi_results <- map_dfr(pares, function(pair) {
tab <- table(data[[pair[1]]], data[[pair[2]]])
test <- suppressWarnings(chisq.test(tab)) # evita warnings si hay valores esperados bajos
tibble(
var1 = pair[1],
var2 = pair[2],
chi_squared = round(test$statistic, 3),
df = test$parameter,
p_value = signif(test$p.value, 3)
)
})
# Desactivar notación científica
chi_results$p_value <- round(as.numeric(gsub(",", ".", format(chi_results$p_value, scientific = FALSE))
), 2)
# Agregar columna evaluación lógica
chi_results <- chi_results %>% mutate(significativo = case_when(
p_value < 0.05 ~ "Sí",
p_value > 0.05 ~ "No"
))
# Ver resultado
kable(chi_results[1:4,], col.names = c("Var1", "Var2", "Chi-squared", "DF", "p_redondeado", "p<0,05"))| Var1 | Var2 | Chi-squared | DF | p_redondeado | p<0,05 |
|---|---|---|---|---|---|
| pobreza | sexo | 37,118 | 1 | 0 | Sí |
| pobreza | jefatura | 677,701 | 1 | 0 | Sí |
| pobreza | area | 610,214 | 1 | 0 | Sí |
| pobreza | edad_tramo | 2759,867 | 3 | 0 | Sí |
3.2 Visualización descriptiva
3.2.1 Incidencia de pobreza según sexo
ctable(casen_vars$sexo, casen_vars$pobreza, weights = casen_vars$expr,
headings = FALSE) %>% print(method = "render")| sexo | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| sexo | Pobre | No pobre | Total | |||||||||
| Hombre | 596221,0 | ( | 6,1% | ) | 9210061,0 | ( | 93,9% | ) | 9806282,0 | ( | 100,0% | ) |
| Mujer | 695603,0 | ( | 6,9% | ) | 9362773,0 | ( | 93,1% | ) | 10058376,0 | ( | 100,0% | ) |
| Total | 1291824,0 | ( | 6,5% | ) | 18572834,0 | ( | 93,5% | ) | 19864658,0 | ( | 100,0% | ) |
Generated by summarytools 1.1.3 (R version 4.4.3)
2025-04-15
casen_vars %>% as_survey(weights = expr) %>%
group_by(sexo, pobreza) %>%
summarize(n = survey_total()) %>%
select(-n_se) %>%
mutate(freq = n / sum(n)) %>%
## GRÁFICO
ggplot(aes(x= sexo, y = freq, fill = pobreza ,label = scales::percent(freq))) +
geom_bar(stat = 'identity') +
geom_text(position = position_stack(vjust = .5, reverse = F), colour = "white", size = 3) +
scale_y_continuous(labels = scales::percent_format(accuracy = 1)) +
scale_fill_discrete("Situación de pobreza")+
labs(x = 'Sexo', y = '%',
caption = "Elaboración propia con base en CASEN 2022") +
theme_linedraw()3.2.2 Incidencia de pobreza según área
ctable(casen_vars$area, casen_vars$pobreza, weights = casen_vars$expr,
headings = FALSE) %>% print(method = "render")| area | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| area | Pobre | No pobre | Total | |||||||||
| Urbano | 1067809,0 | ( | 6,1% | ) | 16543793,0 | ( | 93,9% | ) | 17611602,0 | ( | 100,0% | ) |
| Rural | 224015,0 | ( | 9,9% | ) | 2029041,0 | ( | 90,1% | ) | 2253056,0 | ( | 100,0% | ) |
| Total | 1291824,0 | ( | 6,5% | ) | 18572834,0 | ( | 93,5% | ) | 19864658,0 | ( | 100,0% | ) |
Generated by summarytools 1.1.3 (R version 4.4.3)
2025-04-15
casen_vars %>% as_survey(weights = expr) %>%
group_by(area, pobreza) %>%
summarize(n = survey_total()) %>%
select(-n_se) %>%
mutate(freq = n / sum(n)) %>%
## GRÁFICO
ggplot(aes(x= area, y = freq, fill = pobreza ,label = scales::percent(freq))) +
geom_bar(stat = 'identity') +
geom_text(position = position_stack(vjust = .5, reverse = F), colour = "white", size = 3) +
scale_y_continuous(labels = scales::percent_format(accuracy = 1)) +
scale_fill_discrete("Situación de pobreza")+
labs(x = 'Área de residencia', y = '%',
caption = "Elaboración propia con base en CASEN 2022") +
theme_linedraw()3.2.3 Incidencia de pobreza según tramo de edad
ctable(casen_vars$edad_tramo, casen_vars$pobreza, weights = casen_vars$expr,
headings = FALSE) %>% print(method = "render")| edad_tramo | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| edad_tramo | Pobre | No pobre | Total | |||||||||
| NNA | 467914,0 | ( | 10,5% | ) | 3983135,0 | ( | 89,5% | ) | 4451049,0 | ( | 100,0% | ) |
| Joven | 233156,0 | ( | 6,8% | ) | 3219797,0 | ( | 93,2% | ) | 3452953,0 | ( | 100,0% | ) |
| Adulto | 490630,0 | ( | 5,7% | ) | 8071178,0 | ( | 94,3% | ) | 8561808,0 | ( | 100,0% | ) |
| Tercera edad | 100124,0 | ( | 2,9% | ) | 3298724,0 | ( | 97,1% | ) | 3398848,0 | ( | 100,0% | ) |
| Total | 1291824,0 | ( | 6,5% | ) | 18572834,0 | ( | 93,5% | ) | 19864658,0 | ( | 100,0% | ) |
Generated by summarytools 1.1.3 (R version 4.4.3)
2025-04-15
casen_vars %>% as_survey(weights = expr) %>%
group_by(edad_tramo, pobreza) %>%
summarize(n = survey_total()) %>%
select(-n_se) %>%
mutate(freq = n / sum(n)) %>%
## GRÁFICO
ggplot(aes(x= edad_tramo, y = freq, fill = pobreza ,label = scales::percent(freq))) +
geom_bar(stat = 'identity') +
geom_text(position = position_stack(vjust = .5, reverse = F), colour = "white", size = 3) +
scale_y_continuous(labels = scales::percent_format(accuracy = 1)) +
scale_fill_discrete("Situación de pobreza")+
labs(x = 'Tramo de edad', y = '%',
caption = "Elaboración propia con base en CASEN 2022") +
theme_linedraw()3.2.4 Incidencia de pobreza según tipo de jefatura del hogar
ctable(casen_vars$jefatura, casen_vars$pobreza, weights = casen_vars$expr,
headings = FALSE) %>% print(method = "render")| jefatura | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| jefatura | Pobre | No pobre | Total | |||||||||
| Femenina | 770535,0 | ( | 7,9% | ) | 8955141,0 | ( | 92,1% | ) | 9725676,0 | ( | 100,0% | ) |
| Masculina | 521289,0 | ( | 5,1% | ) | 9617693,0 | ( | 94,9% | ) | 10138982,0 | ( | 100,0% | ) |
| Total | 1291824,0 | ( | 6,5% | ) | 18572834,0 | ( | 93,5% | ) | 19864658,0 | ( | 100,0% | ) |
Generated by summarytools 1.1.3 (R version 4.4.3)
2025-04-15
casen_vars %>% as_survey(weights = expr) %>%
group_by(jefatura, pobreza) %>%
summarize(n = survey_total()) %>%
select(-n_se) %>%
mutate(freq = n / sum(n)) %>%
## GRÁFICO
ggplot(aes(x= jefatura, y = freq, fill = pobreza ,label = scales::percent(freq))) +
geom_bar(stat = 'identity') +
geom_text(position = position_stack(vjust = .5, reverse = F), colour = "white", size = 3) +
scale_y_continuous(labels = scales::percent_format(accuracy = 1)) +
scale_fill_discrete("Situación de pobreza")+
labs(x = 'Jefatura del hogar', y = '%',
caption = "Elaboración propia con base en CASEN 2022") +
theme_linedraw()4 Resultado multivariable
4.1 Regresión logística múltiple
Para modelar los datos primero se definieron todas las variables como factor en el apartado de procesamiento de la información. Se definen las categorías de referencia para el análisis y en el caso de edad se simplifican las categorías de respuesta, agrupando a niñas, niños, adolescentes y jóvenes (sub 30 años) en una misma categoría, y al resto (adultos y tercera edad, de 30 años hacia arriba) en otra categoría.
# Niveles de variable pobreza: categoría referencia = "Pobre"
casen_vars$pobreza <- relevel(casen_vars$pobreza,
ref = "No pobre")
# Variable jefatura: categoría referencia = "Masculina"
casen_vars$jefatura <- relevel(casen_vars$jefatura,
ref = "Masculina")
# Variable edad: agrupar categorías y definir referencia = "NNA-joven"
casen_vars$edad_tramo2 <- fct_collapse(casen_vars$edad_tramo,
"NNA - Joven" = c("NNA", "Joven"),
"Adulto - 3a edad" = c("Adulto", "Tercera edad"))
casen_vars$edad_tramo2 <- relevel(casen_vars$edad_tramo2,
ref = "Adulto - 3a edad")
# Variable área: definir categoría referencia = "Urbano"
casen_vars$area <- relevel(casen_vars$area,
ref = "Urbano")Con tal procesamiento de datos definimos el modelo de regresión logística y construimos resultados con formato para interpretación.
# Modelamiento
rlogit <- glm(pobreza ~ edad_tramo2 + jefatura + area, # variables modeladas
data = casen_vars, # base de datos
family = "binomial")
# Tabla resumen del modelo
summary(rlogit)
Call:
glm(formula = pobreza ~ edad_tramo2 + jefatura + area, family = "binomial",
data = casen_vars)
Coefficients:
Estimate Std. Error z value Pr(>|z|)
(Intercept) -3,18745 0,01720 -185,34 <2e-16 ***
edad_tramo2NNA - Joven 0,66557 0,01706 39,02 <2e-16 ***
jefaturaFemenina 0,44466 0,01749 25,43 <2e-16 ***
areaRural 0,56530 0,01928 29,32 <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: 108254 on 202110 degrees of freedom
Residual deviance: 105348 on 202107 degrees of freedom
AIC: 105356
Number of Fisher Scoring iterations: 5
# Diseño resultados para informe
tabla_rlogit <- modelsummary(
list("Log-odds" = rlogit, "Odds Ratio" = rlogit),
exponentiate = c(FALSE, TRUE),
statistic = "conf.int",
output = "markdown"
)
tabla_rlogit| Log-odds | Odds Ratio | |
|---|---|---|
| (Intercept) | -3,187 | 0,041 |
| [-3,221, -3,154] | [0,040, 0,043] | |
| edad_tramo2NNA - Joven | 0,666 | 1,946 |
| [0,632, 0,699] | [1,882, 2,012] | |
| jefaturaFemenina | 0,445 | 1,560 |
| [0,410, 0,479] | [1,507, 1,614] | |
| areaRural | 0,565 | 1,760 |
| [0,527, 0,603] | [1,695, 1,828] | |
| Num.Obs. | 202111 | 202111 |
| AIC | 105356,0 | 105356,0 |
| BIC | 105396,9 | 105396,9 |
| Log.Lik. | -52674,022 | -52674,022 |
| RMSE | 0,26 | 0,26 |