Un paquete es un conjunto de funciones extra que le
“enseñan” nuevas habilidades a R. Si es la primera vez que los usas,
instálalos una sola vez desde la consola de RStudio
con:
install.packages(c("readxl", "dplyr", "tidyr", "ggplot2", "knitr", "rmarkdown"))
library(readxl) # leer archivos de Excel
library(dplyr) # manipular datos (filtrar, agrupar, resumir)
library(tidyr) # reorganizar tablas (pivot_longer)
library(ggplot2) # hacer gráficos
library(knitr) # mostrar tablas bonitas con kable()
Los archivos BD1.xlsx y BD2.xlsx deben
estar en la misma carpeta que este archivo .Rmd (así R
los encuentra sin que tengamos que escribir rutas largas).
bd1 <- read_excel("BD1.xlsx") # datos sociodemográficos (14 variables)
bd2 <- read_excel("BD2.xlsx") # respuestas de la encuesta (409 variables)
dim(bd1) # filas y columnas de BD1
## [1] 4673 14
dim(bd2) # filas y columnas de BD2
## [1] 4673 409
Ambas bases tienen 4.673 encuestas (jefes de hogar).
Cada encuesta se identifica con la variable REGISTRO, que
según el diccionario sirve como llave para pegar las bases.
De BD2 solo necesitamos unas pocas variables: percepción
de seguridad en el barrio (P1), la comuna (P3)
y la ciudad (P5), el delito sufrido (P20A),
nivel educativo (P110) y el factor de expansión
(FACTOR). Las pegamos a BD1 usando
REGISTRO como llave.
bd2_sel <- bd2 %>% select(REGISTRO, P1, P3, P5, P20A, P110, FACTOR)
datos <- bd1 %>% left_join(bd2_sel, by = "REGISTRO")
nrow(datos) # debe seguir siendo 4673
## [1] 4673
sum(is.na(datos$FACTOR)) # debe ser 0 (todas las encuestas pegaron bien)
## [1] 0
# Cuántos datos vacíos (NA) tiene cada variable que vamos a usar
colSums(is.na(datos[, c("COMUNA", "GENERO", "ESTRATO_DEC", "ESTRATO", "PC_EDAD", "PD",
"P1", "P3", "P5", "P20A", "FACTOR")]))
## COMUNA GENERO ESTRATO_DEC ESTRATO PC_EDAD PD
## 0 0 0 4673 8 0
## P1 P3 P5 P20A FACTOR
## 0 0 0 0 0
Hallazgos importantes: la variable ESTRATO está
completamente vacía, por lo que usamos
ESTRATO_DEC, que tiene la misma pregunta (D0A) y sí trae
datos. La edad (PC_EDAD) solo tiene unos pocos vacíos, que
R ignora al calcular promedios con na.rm = TRUE.
En la base los datos vienen como números (por ejemplo,
GENERO = 1). Con ayuda del diccionario de
datos convertimos esos códigos en etiquetas legibles. Una
variable con etiquetas se llama factor en R.
datos <- datos %>%
mutate(
Genero = factor(GENERO, levels = c(1, 2), labels = c("Masculino", "Femenino")),
Estrato = factor(ESTRATO_DEC, levels = 1:7,
labels = c("Estrato 1", "Estrato 2", "Estrato 3", "Estrato 4",
"Estrato 5", "Estrato 6", "Sin estrato")),
Rango_edad = factor(EDAD_RANGO, levels = 1:10,
labels = c("16-17", "18-24", "25-28", "29-34", "35-38",
"39-44", "45-54", "55-59", "60-66", "67 o más")),
# case_when funciona como una cadena de "si... entonces...". Agrupamos las
# ocupaciones con muy pocos casos en una sola categoría.
Ocupacion = case_when(
PD == 1 ~ "Empleado/asalariado",
PD == 2 ~ "Independiente/propietario",
PD == 3 ~ "Retirado/jubilado",
PD == 4 ~ "Desempleado",
PD == 5 ~ "Ama de casa",
PD == 6 ~ "Estudiante",
TRUE ~ "Otra / sin información"),
Educacion = factor(P110, levels = c(1, 2, 3, 4, 5, 6, 990),
labels = c("Preescolar", "Primaria", "Secundaria", "Técnico",
"Universitario", "Postgrado", "Ninguno")),
# La comuna es un código (1, 2, 3...). La convertimos en factor ordenado.
Comuna = factor(COMUNA, levels = sort(unique(COMUNA))),
# Percepción de seguridad (P1 = barrio, P3 = comuna, P5 = ciudad)
Seg_barrio = factor(P1, levels = 1:4, labels = c("Muy seguro", "Seguro", "Inseguro", "Muy inseguro")),
Seg_comuna = factor(P3, levels = 1:4, labels = c("Muy seguro", "Seguro", "Inseguro", "Muy inseguro")),
Seg_ciudad = factor(P5, levels = 1:4, labels = c("Muy seguro", "Seguro", "Inseguro", "Muy inseguro")),
# Variable "víctima": vale 1 si el hogar sufrió al menos uno de los 5 delitos del
# índice (1 Hurto a personas, 2 Hurto a residencias, 3 Hurto a establecimientos,
# 4 Hurto de vehículos, 6 Extorsión/vacunas) y 0 en los demás casos.
victima = ifelse(P20A %in% c(1, 2, 3, 4, 6), 1, 0)
)
# Texto de la fuente que repetiremos debajo de cada tabla y gráfico
fuente <- "Fuente: elaboración propia con base en la encuesta de seguridad, convivencia ciudadana y confianza institucional (BD1 y BD2), ciudad Castellana. Cifras ponderadas con el factor de expansión."
# Versión de la fuente partida en varias líneas, para que quepa al pie de los gráficos
fuente_graf <- paste(strwrap(fuente, width = 95), collapse = "\n")
# Pequeña función para dar formato a los porcentajes en el texto
pct <- function(x) paste0(format(round(x, 1), trim = TRUE), "%")
# Igual, pero para las etiquetas de los gráficos (varios valores a la vez)
lab <- function(x) paste0(format(x, nsmall = 1, trim = TRUE), "%")
Nota sobre las cifras ponderadas. Cada encuesta “representa” a un número distinto de hogares, y ese número es el
FACTOR(factor de expansión). Por eso, para describir a la población usamos porcentajes ponderados: en vez de contar 1 por cada encuesta, sumamos suFACTOR.
Función auxiliar para armar tablas de frecuencias ponderadas (la usaremos varias veces):
# Recibe la base y el nombre de una variable, y devuelve una tabla con:
# número de encuestas, población expandida y porcentaje ponderado.
tabla_pond <- function(base, variable) {
base %>%
group_by(Categoria = .data[[variable]]) %>%
summarise(Encuestas = n(),
Poblacion = round(sum(FACTOR)),
.groups = "drop") %>%
mutate(Porcentaje = round(100 * Poblacion / sum(Poblacion), 1))
}
Las preguntas P1, P3 y P5 piden al encuestado calificar qué tan seguro se siente en su barrio, su comuna y la ciudad (Muy seguro, Seguro, Inseguro, Muy inseguro).
# Calculamos el % ponderado de cada respuesta para cada ámbito
t_barrio <- tabla_pond(datos, "Seg_barrio") %>% mutate(Ambito = "Barrio")
t_comuna <- tabla_pond(datos, "Seg_comuna") %>% mutate(Ambito = "Comuna")
t_ciudad <- tabla_pond(datos, "Seg_ciudad") %>% mutate(Ambito = "Ciudad")
# bind_rows apila las tres tablas una debajo de otra
t_perc <- bind_rows(t_barrio, t_comuna, t_ciudad) %>%
mutate(Ambito = factor(Ambito, levels = c("Barrio", "Comuna", "Ciudad")))
# Tabla "ancha": una fila por respuesta y una columna por ámbito
t_perc_ancha <- t_perc %>%
select(Categoria, Ambito, Porcentaje) %>%
pivot_wider(names_from = Ambito, values_from = Porcentaje)
kable(t_perc_ancha, col.names = c("Percepción", "Barrio (%)", "Comuna (%)", "Ciudad (%)"),
caption = "Tabla 7. Percepción de seguridad en el barrio, la comuna y la ciudad (porcentaje ponderado)")
| Percepción | Barrio (%) | Comuna (%) | Ciudad (%) |
|---|---|---|---|
| Muy seguro | 10,8 | 8,2 | 4,3 |
| Seguro | 72,2 | 70,4 | 44,9 |
| Inseguro | 13,6 | 16,9 | 40,2 |
| Muy inseguro | 3,4 | 4,5 | 10,6 |
Fuente: elaboración propia con base en la encuesta de seguridad, convivencia ciudadana y confianza institucional (BD1 y BD2), ciudad Castellana. Cifras ponderadas con el factor de expansión.
ggplot(t_perc, aes(x = Ambito, y = Porcentaje, fill = Categoria)) +
geom_col(position = "stack") +
geom_text(aes(label = lab(Porcentaje)), position = position_stack(vjust = 0.5),
size = 3.2, colour = "white") +
scale_fill_manual(values = c("Muy seguro" = "#1a9850", "Seguro" = "#91cf60",
"Inseguro" = "#fc8d59", "Muy inseguro" = "#d73027")) +
labs(title = "Figura 6. Percepción de seguridad según ámbito",
x = NULL, y = "Porcentaje (%)", fill = "Percepción", caption = fuente_graf) +
theme_minimal() +
theme(plot.caption = element_text(hjust = 0))
# Resumen: % que se siente "seguro" (Seguro + Muy seguro) en cada ámbito
seg_barrio <- sum(t_barrio$Porcentaje[t_barrio$Categoria %in% c("Muy seguro", "Seguro")])
seg_comuna <- sum(t_comuna$Porcentaje[t_comuna$Categoria %in% c("Muy seguro", "Seguro")])
seg_ciudad <- sum(t_ciudad$Porcentaje[t_ciudad$Categoria %in% c("Muy seguro", "Seguro")])
Interpretación. La Tabla 7 y la Figura 6 muestran que la percepción de seguridad disminuye a medida que el ámbito se hace más grande: el 83% de los encuestados se siente seguro o muy seguro en su barrio, el 78,6% en su comuna y solo el 49,2% en la ciudad. A la inversa, se siente inseguro o muy inseguro el 17% en el barrio, el 21,4% en la comuna y el 50,8% en la ciudad. Es decir, las personas se sienten más tranquilas en su entorno cercano que en la ciudad en su conjunto.
Para comparar grupos usamos una medida sencilla: el porcentaje de personas que se sienten inseguras (respuestas “Inseguro” + “Muy inseguro”) en el barrio, la comuna y la ciudad.
# Función que calcula el % ponderado de personas inseguras para cada grupo
inseguridad_por <- function(base, grupo) {
base %>%
group_by(Grupo = .data[[grupo]]) %>%
summarise(
Encuestas = n(),
Barrio = round(100 * sum(FACTOR * (P1 %in% c(3, 4))) / sum(FACTOR), 1),
Comuna = round(100 * sum(FACTOR * (P3 %in% c(3, 4))) / sum(FACTOR), 1),
Ciudad = round(100 * sum(FACTOR * (P5 %in% c(3, 4))) / sum(FACTOR), 1),
.groups = "drop")
}
i_gen <- inseguridad_por(datos, "Genero")
kable(i_gen, col.names = c("Género", "Encuestas", "Inseguros en el barrio (%)",
"Inseguros en la comuna (%)", "Inseguros en la ciudad (%)"),
format.args = list(big.mark = "."),
caption = "Tabla 8. Porcentaje de personas que se sienten inseguras, según género")
| Género | Encuestas | Inseguros en el barrio (%) | Inseguros en la comuna (%) | Inseguros en la ciudad (%) |
|---|---|---|---|---|
| Masculino | 2.290 | 13,1 | 18,0 | 43,4 |
| Femenino | 2.383 | 20,4 | 24,3 | 57,1 |
Fuente: elaboración propia con base en la encuesta de seguridad, convivencia ciudadana y confianza institucional (BD1 y BD2), ciudad Castellana. Cifras ponderadas con el factor de expansión.
i_gen_largo <- i_gen %>% pivot_longer(cols = c(Barrio, Comuna, Ciudad),
names_to = "Ambito", values_to = "Porcentaje") %>%
mutate(Ambito = factor(Ambito, levels = c("Barrio", "Comuna", "Ciudad")))
ggplot(i_gen_largo, aes(x = Ambito, y = Porcentaje, fill = Grupo)) +
geom_col(position = "dodge") +
geom_text(aes(label = lab(Porcentaje)), position = position_dodge(width = 0.9),
vjust = -0.4, size = 3.2) +
labs(title = "Figura 7. Personas que se sienten inseguras, según género",
x = NULL, y = "Porcentaje (%)", fill = "Género", caption = fuente_graf) +
theme_minimal() +
theme(plot.caption = element_text(hjust = 0))
# Diferencia (mujeres - hombres) en puntos porcentuales
dif_b <- i_gen$Barrio[i_gen$Grupo == "Femenino"] - i_gen$Barrio[i_gen$Grupo == "Masculino"]
dif_c <- i_gen$Comuna[i_gen$Grupo == "Femenino"] - i_gen$Comuna[i_gen$Grupo == "Masculino"]
dif_u <- i_gen$Ciudad[i_gen$Grupo == "Femenino"] - i_gen$Ciudad[i_gen$Grupo == "Masculino"]
Interpretación. Según la Tabla 8 y la Figura 7, sí cambia la percepción según el género: las mujeres se sienten más inseguras que los hombres en los tres ámbitos. En el barrio, el 20,4% de las mujeres se siente inseguro frente al 13,1% de los hombres (una brecha de 7,3 puntos porcentuales); en la comuna la brecha es de 6,3 puntos y en la ciudad llega a 13,7 puntos (57,1% de las mujeres frente a 43,4% de los hombres). La diferencia es mayor cuando se evalúa la ciudad en su conjunto.
i_est <- inseguridad_por(datos, "Estrato")
kable(i_est, col.names = c("Estrato", "Encuestas", "Inseguros en el barrio (%)",
"Inseguros en la comuna (%)", "Inseguros en la ciudad (%)"),
format.args = list(big.mark = "."),
caption = "Tabla 9. Porcentaje de personas que se sienten inseguras, según estrato")
| Estrato | Encuestas | Inseguros en el barrio (%) | Inseguros en la comuna (%) | Inseguros en la ciudad (%) |
|---|---|---|---|---|
| Estrato 1 | 753 | 16,7 | 19,3 | 45,8 |
| Estrato 2 | 2.026 | 14,1 | 18,9 | 48,8 |
| Estrato 3 | 1.282 | 19,7 | 23,8 | 55,5 |
| Estrato 4 | 141 | 29,1 | 35,5 | 64,2 |
| Estrato 5 | 82 | 40,0 | 44,5 | 58,9 |
| Estrato 6 | 3 | 0,0 | 31,9 | 42,1 |
| Sin estrato | 386 | 12,2 | 16,8 | 43,8 |
Fuente: elaboración propia con base en la encuesta de seguridad, convivencia ciudadana y confianza institucional (BD1 y BD2), ciudad Castellana. Cifras ponderadas con el factor de expansión.
i_est_largo <- i_est %>% pivot_longer(cols = c(Barrio, Comuna, Ciudad),
names_to = "Ambito", values_to = "Porcentaje") %>%
mutate(Ambito = factor(Ambito, levels = c("Barrio", "Comuna", "Ciudad")))
ggplot(i_est_largo, aes(x = Grupo, y = Porcentaje, fill = Ambito)) +
geom_col(position = "dodge") +
labs(title = "Figura 8. Personas que se sienten inseguras, según estrato",
x = NULL, y = "Porcentaje (%)", fill = "Ámbito", caption = fuente_graf) +
theme_minimal() +
theme(plot.caption = element_text(hjust = 0))
# Estrato con mayor y menor inseguridad en el barrio (solo estratos con 30 o más encuestas,
# porque con muy pocos casos el resultado no es confiable)
i_est_ok <- i_est %>% filter(Encuestas >= 30)
mayor_b <- i_est_ok[which.max(i_est_ok$Barrio), ]
menor_b <- i_est_ok[which.min(i_est_ok$Barrio), ]
mayor_u <- i_est_ok[which.max(i_est_ok$Ciudad), ]
menor_u <- i_est_ok[which.min(i_est_ok$Ciudad), ]
Interpretación. La percepción también cambia según el estrato (Tabla 9 y Figura 8), y la tendencia general es que la inseguridad percibida aumenta a medida que sube el estrato. En el barrio, la mayor inseguridad se da en Estrato 5 (40%) y la menor en Sin estrato (12,2%); en la ciudad, la mayor se registra en Estrato 4 (64,2%) y la menor en Sin estrato (43,8%). Por ejemplo, en el barrio se sienten inseguros el 14,1% de los hogares del estrato 2, frente al 29,1% del estrato 4. Precaución: los estratos 4 y 5 tienen pocas encuestas (141 y 82) y el estrato 6 solo 3, por lo que el estrato 6 no se interpreta y los otros dos se leen con cautela.
El índice de victimización mide la proporción de hogares que fue víctima de por lo menos uno de estos delitos: hurto a personas, hurto a residencias, hurto a establecimientos comerciales, hurto de vehículos o extorsiones/vacunas (pregunta P20A):
\[ \text{Índice de victimización}=\frac{\sum_{i=1}^{4.673}\left(P20A_i=1\right)\times \text{factor de ponderación}_i}{\sum_{i=1}^{4.673}\text{factor de ponderación}_i} \]
En R esto es: suma del factor de ponderación de los hogares
víctima ÷ suma del factor de ponderación de todos los hogares.
Como la variable victima vale 1 o 0, basta con
sum(victima * FACTOR) / sum(FACTOR).
indice_ciudad <- sum(datos$victima * datos$FACTOR) / sum(datos$FACTOR)
indice_ciudad # como proporción (entre 0 y 1)
## [1] 0,1995605
indice_ciudad * 100 # como porcentaje
## [1] 19,95605
Respuesta. El índice de victimización de la ciudad Castellana es de 0,1996, es decir, 20%: aproximadamente 20 de cada 100 hogares fue víctima de por lo menos uno de los delitos considerados. (Sin ponderar, la proporción de encuestas con víctima sería 18,2%.)
indice_comuna <- datos %>%
group_by(Comuna) %>%
summarise(Encuestas = n(),
Hogares_victima = sum(victima),
Indice = sum(victima * FACTOR) / sum(FACTOR),
.groups = "drop") %>%
mutate(Indice_pct = round(100 * Indice, 1),
Indice = round(Indice, 4))
kable(indice_comuna,
col.names = c("Comuna (código)", "Encuestas", "Encuestas con víctima", "Índice (proporción)", "Índice (%)"),
caption = "Tabla 10. Índice de victimización por comuna")
| Comuna (código) | Encuestas | Encuestas con víctima | Índice (proporción) | Índice (%) |
|---|---|---|---|---|
| 1 | 282 | 40 | 0,1818 | 18,2 |
| 2 | 405 | 79 | 0,1968 | 19,7 |
| 3 | 373 | 76 | 0,2052 | 20,5 |
| 4 | 404 | 76 | 0,2252 | 22,5 |
| 5 | 219 | 51 | 0,2757 | 27,6 |
| 6 | 394 | 56 | 0,1376 | 13,8 |
| 7 | 293 | 63 | 0,2344 | 23,4 |
| 8 | 375 | 82 | 0,2157 | 21,6 |
| 9 | 389 | 71 | 0,1890 | 18,9 |
| 10 | 109 | 24 | 0,1800 | 18,0 |
| 11 | 62 | 13 | 0,1314 | 13,1 |
| 12 | 44 | 7 | 0,1512 | 15,1 |
| 13 | 393 | 57 | 0,2079 | 20,8 |
| 15 | 94 | 13 | 0,1128 | 11,3 |
| 16 | 268 | 48 | 0,2078 | 20,8 |
| 50 | 3 | 0 | 0,0000 | 0,0 |
| 60 | 156 | 35 | 0,2295 | 22,9 |
| 70 | 129 | 13 | 0,1271 | 12,7 |
| 80 | 250 | 43 | 0,1698 | 17,0 |
| 90 | 31 | 3 | 0,1428 | 14,3 |
Fuente: elaboración propia con base en la encuesta de seguridad, convivencia ciudadana y confianza institucional (BD1 y BD2), ciudad Castellana. Cifras ponderadas con el factor de expansión.
ggplot(indice_comuna, aes(x = Comuna, y = Indice_pct)) +
geom_col(fill = "firebrick") +
geom_hline(yintercept = 100 * indice_ciudad, linetype = "dashed") +
annotate("text", x = 1, y = 100 * indice_ciudad, label = "Total ciudad", vjust = -0.6, hjust = 0, size = 3.2) +
labs(title = "Figura 9. Índice de victimización por comuna",
x = "Comuna (código)", y = "Índice de victimización (%)", caption = fuente_graf) +
theme_minimal() +
theme(plot.caption = element_text(hjust = 0))
comuna_mayor <- indice_comuna[which.max(indice_comuna$Indice), ]
comuna_menor <- indice_comuna[which.min(indice_comuna$Indice), ]
# Algunas comunas tienen muy pocas encuestas y su índice no es confiable.
# Por eso miramos también el menor índice entre las comunas con 30 o más encuestas.
menor_confiable <- indice_comuna %>% filter(Encuestas >= 30) %>% slice(which.min(Indice))
comuna_mayor
comuna_menor
menor_confiable
Respuesta. Según la Tabla 10 y la Figura 9, el índice es mayor en la comuna 5 (27,6%, con 219 encuestas). El valor menor corresponde a la comuna 50 (0%), pero ese resultado se basa en solo 3 encuestas, por lo que es poco confiable. Si se consideran únicamente las comunas con 30 o más encuestas, el índice más bajo es el de la comuna 15 (11,3%). Entre la comuna con mayor índice y esta última hay una diferencia de 16,3 puntos porcentuales.
Quiénes son los encuestados. La encuesta recoge la voz de jefes de hogar de la ciudad Castellana: un poco más de la mitad son mujeres (54,1%), la edad promedio es de unos 42 años y la gran mayoría vive en estratos 1, 2 y 3 (85,3%). Las ocupaciones más comunes son ama de casa, empleado e independiente, y el nivel educativo más frecuente es la secundaria. Es decir, hablamos principalmente de hogares de ingresos bajos y medios.
Cómo se sienten con la seguridad. Las personas se sienten más tranquilas cuanto más cerca está el lugar: la mayoría se siente segura en su barrio (83%) y en su comuna (78,6%), pero en la ciudad en general la opinión se divide casi por la mitad (49,2% se siente seguro y 50,8% inseguro). Dicho de otra forma, lo que está cerca se percibe como más seguro y la ciudad en conjunto, como más riesgosa.
Diferencias entre grupos. La percepción no es igual para todos. Las mujeres se sienten más inseguras que los hombres en los tres ámbitos, y la brecha es más grande al hablar de la ciudad (13,7 puntos porcentuales). Por estrato, la inseguridad percibida tiende a ser mayor en los estratos más altos (sobre todo el 4 y el 5), aunque esos grupos tienen pocas encuestas y sus cifras deben leerse con cuidado.
Victimización. Cerca de 20 de cada 100 hogares de la ciudad fue víctima de por lo menos uno de los delitos considerados (hurto a personas, residencias, comercios o vehículos, o extorsión). El problema no se reparte igual: la comuna 5 es la más afectada (27,6%), mientras que entre las comunas con datos suficientes la menos afectada es la comuna 15 (11,3%). La comuna 50 aparece con 0 %, pero solo tiene 3 encuestas, por lo que no se puede concluir nada de ella.
Idea final. La ciudad Castellana tiene un problema de seguridad que se siente más en la ciudad como un todo que en el barrio de cada persona, afecta más la sensación de las mujeres y golpea de forma desigual a las comunas. Esto sugiere que las acciones públicas deberían enfocarse en las comunas con mayor victimización y prestar atención especial a la seguridad de las mujeres.