library(tidyverse) # manipular datos y graficar
library(sf) # leer y dibujar mapas
library(scales) # formatear números (puntos de miles, %)
library(patchwork) # poner dos mapas lado a lado
library(kableExtra) # tablas con estiloazul <- "#2F6DB5" # hurto (delito patrimonial)
vino <- "#A6243D" # violencia contra las personas
gris <- "#CDD0D5" # contexto
noche <- "#1F2430" # títulos
tema_clase <- theme_minimal(base_size = 12) +
theme(
plot.title.position = "plot",
plot.title = element_text(face = "bold", size = 15, color = noche),
plot.subtitle = element_text(size = 10.5, color = "grey35"),
plot.caption = element_text(hjust = 0, color = "grey45", size = 8.5),
panel.grid.minor = element_blank()
)
fuente <- "Fuente: SDSCJ (delitos ene–jul 2023), DANE (población 2023) y Encuesta Multipropósito 2021."
tabla_bonita <- function(df, resaltar = NULL) {
k <- df %>%
kbl() %>%
kable_styling(bootstrap_options = c("hover", "condensed"), full_width = TRUE) %>%
row_spec(0, bold = TRUE, color = "white", background = vino)
if (!is.null(resaltar)) k <- k %>% row_spec(resaltar, bold = TRUE, background = "#F8E9EC")
k
}# Tabla de variables y mapa de las UPZ (rutas relativas)
upz <- read_csv("input/upz_variables.csv", show_col_types = FALSE)
upz_shp <- st_read("input/shp/upz_bogota.shp", quiet = TRUE)
loc_shp <- st_read("input/shp/localidades_bogota.shp", quiet = TRUE)
# Nos quedamos solo con las variables de las 8 preguntas
datos <- upz %>%
select(upz_cod, upz_nombre, localidad, # identificación
poblacion, area_km2, # demografía y territorio
casos_violencia_intrafamiliar, casos_hurto_personas, # delitos: casos
tasa_violencia_intrafamiliar, tasa_hurto_personas, # delitos: tasas
tasa_homicidios,
em_agrupada, # encuesta
pct_estrato_1_2, pct_estrato_3_4, pct_estrato_5_6,
pct_percibe_inseguridad, pct_cerca_ollas,
pct_cerca_lotes_oscuros, min_cai_policia)
dim(datos) # verificar: 112 filas y 18 columnas## [1] 112 18
En Bogotá, la inseguridad suele resumirse en un número: cuántos delitos se denuncian. Pero detrás de ese número hay fenómenos muy distintos: no es lo mismo un robo en una calle comercial que una agresión dentro de un hogar.
Este informe explora las 112 UPZ de Bogotá para responder una pregunta de fondo: ¿qué nos dicen los datos sobre la inseguridad en la ciudad y su relación con el territorio y las condiciones de vida? Comparamos dos tipos de inseguridad —el hurto y la violencia contra las personas— y cómo la percibe la ciudadanía.
Código de color: azul = hurto · vino = violencia · gris = contexto.
Para responder las ocho preguntas elegimos 12 variables de tres bloques de la base: demografía, delitos y la Encuesta Multipropósito. La tabla muestra cada variable y la pregunta que ayuda a responder.
tibble(
Bloque = c("Demografía", "Demografía", "Delitos", "Delitos", "Delitos",
"Encuesta", "Encuesta", "Encuesta", "Encuesta", "Encuesta"),
Variable = c("poblacion", "area_km2",
"tasa_violencia_intrafamiliar", "tasa_hurto_personas", "tasa_homicidios",
"pct_estrato_1_2 / 3_4 / 5_6", "pct_percibe_inseguridad",
"pct_cerca_ollas", "pct_cerca_lotes_oscuros", "min_cai_policia"),
`Para qué la usamos` = c(
"Filtrar UPZ con poca población",
"Medir el hurto por km² (P2)",
"Violencia intrafamiliar (P1, P3)",
"Hurto a personas (P2, P3, P5, P6)",
"Homicidios (P4)",
"Estrato de cada UPZ (P1, P2)",
"Percepción de inseguridad (P5, P7, P8)",
"Microtráfico (P4, P5)",
"Lotes baldíos u oscuros (P5, P7)",
"Cercanía al CAI (P8)")
) %>%
tabla_bonita()| Bloque | Variable | Para qué la usamos |
|---|---|---|
| Demografía | poblacion | Filtrar UPZ con poca población |
| Demografía | area_km2 | Medir el hurto por km² (P2) |
| Delitos | tasa_violencia_intrafamiliar | Violencia intrafamiliar (P1, P3) |
| Delitos | tasa_hurto_personas | Hurto a personas (P2, P3, P5, P6) |
| Delitos | tasa_homicidios | Homicidios (P4) |
| Encuesta | pct_estrato_1_2 / 3_4 / 5_6 | Estrato de cada UPZ (P1, P2) |
| Encuesta | pct_percibe_inseguridad | Percepción de inseguridad (P5, P7, P8) |
| Encuesta | pct_cerca_ollas | Microtráfico (P4, P5) |
| Encuesta | pct_cerca_lotes_oscuros | Lotes baldíos u oscuros (P5, P7) |
| Encuesta | min_cai_policia | Cercanía al CAI (P8) |
Antes de analizar, revisamos que los datos estén completos y bien construidos: cuántas UPZ y columnas hay, si faltan valores y si cada UPZ aparece una sola vez.
tibble(
Revisión = c("UPZ (filas) en la base original",
"Columnas en la base original",
"Datos faltantes en nuestras variables",
"UPZ distintas (llave única)",
"UPZ con valores de encuesta agrupados"),
Resultado = c(nrow(upz), ncol(upz), sum(is.na(datos)),
n_distinct(datos$upz_cod), sum(datos$em_agrupada))
) %>%
tabla_bonita()| Revisión | Resultado |
|---|---|
| UPZ (filas) en la base original | 112 |
| Columnas en la base original | 67 |
| Datos faltantes en nuestras variables | 0 |
| UPZ distintas (llave única) | 112 |
| UPZ con valores de encuesta agrupados | 32 |
La base tiene una fila por UPZ, sin datos faltantes y con una llave única. Una advertencia: en 32 UPZ
Antes de confiar en una tasa revisamos su denominador: la población. Una tasa divide los casos entre los habitantes, así que en una UPZ con muy pocos habitantes un solo caso puede dispararla. La tabla muestra las UPZ con menos de 10.000 habitantes.
datos %>%
filter(poblacion < 10000) %>%
arrange(poblacion) %>%
select(UPZ = upz_nombre, Localidad = localidad, `Población` = poblacion,
`Tasa de hurto` = tasa_hurto_personas,
`Tasa de VIF` = tasa_violencia_intrafamiliar) %>%
mutate(across(where(is.numeric), ~ round(.x, 1))) %>%
tabla_bonita()| UPZ | Localidad | Población | Tasa de hurto | Tasa de VIF |
|---|---|---|---|---|
| El Mochuelo | Ciudad Bolívar | 30 | 6333.3 | 0.0 |
| Aeropuerto El Dorado | Fontibón | 883 | 4507.4 | 11.3 |
| Parque Entrenubes | Usme | 1169 | 42.8 | 17.1 |
| Parque Salitre | Barrios Unidos | 1442 | 943.1 | 27.7 |
| Paseo De Los Libertadores | Usaquén | 2690 | 163.6 | 0.0 |
| Guaymaral | Suba | 2692 | 107.7 | 7.4 |
| Jardin Botanico | Engativá | 2900 | 520.7 | 31.0 |
| Parque Simon Bolivar - Can | Teusaquillo | 3323 | 1700.3 | 81.2 |
| La Academia | Suba | 5260 | 142.6 | 9.5 |
| Monte Blanco | Ciudad Bolívar | 6575 | 30.4 | 50.2 |
| Zona Industrial | Puente Aranda | 6666 | 1296.1 | 229.5 |
peso <- datos %>%
summarise(upz = sum(poblacion < 10000),
pct_pob = 100 * sum(poblacion[poblacion < 10000]) / sum(poblacion))Encontramos 11 UPZ con menos de 10.000 habitantes. Casi todas son zonas de paso, como el Aeropuerto El Dorado o los parques Simón Bolívar y Salitre: muchos visitantes y pocos residentes, lo que dispara la tasa (en el aeropuerto supera las 4.500 denuncias por 10.000 habitantes).
Decisión: las excluimos del análisis y las mostramos en gris en el mapa. Son solo el 0,4 % de la población, así que no cambian el panorama de la ciudad.
Este efecto también infla el hurto en el centro y las zonas comerciales, pero casi no afecta a la violencia intrafamiliar, que ocurre dentro del hogar. Por eso, el hurto lo verificamos también por km².
El histograma muestra cuántas UPZ hay según su número de habitantes. En vino, las que excluimos.
mediana_pob <- median(datos$poblacion)
ggplot(datos, aes(x = poblacion, fill = pob_baja)) +
geom_histogram(bins = 30, color = "white") +
# Mediana: línea suave
geom_vline(xintercept = mediana_pob, color = "grey40", linetype = "dotted", linewidth = 0.6) +
annotate("text", x = mediana_pob + 4000, y = 16, hjust = 0,
label = "Mediana: 54.000", color = "grey30", size = 3.5) +
# Cola hacia la derecha
annotate("text", x = 250000, y = 6, hjust = 0.5,
label = "Cola hacia la derecha:\nTibabuyes, El Rincón\ny Bosa Central",
color = "grey35", size = 3.2) +
annotate("segment", x = 220000, xend = 300000, y = 3.8, yend = 3.8,
arrow = arrow(length = unit(0.2, "cm")), color = "grey50") +
scale_fill_manual(values = c(`TRUE` = vino, `FALSE` = gris),
labels = c(`TRUE` = "Excluidas (11)", `FALSE` = "Analizadas (101)"),
name = NULL) +
scale_x_continuous(labels = label_comma(big.mark = ".")) +
labs(title = "La mayoría de UPZ son medianas; unas pocas son muy pequeñas o muy grandes",
subtitle = "Número de UPZ según su población · en vino, las 11 UPZ con menos de 10.000 habitantes · línea punteada: mediana",
x = "Población de la UPZ (2023)", y = "Número de UPZ", caption = fuente) +
tema_clase +
theme(legend.position = "top")La mitad de las UPZ tiene entre 30.000 y 101.000 habitantes, con una mediana de 54.000. La distribución tiene una cola hacia la derecha: unas pocas UPZ residenciales de la periferia, como Tibabuyes y El Rincón en Suba o Bosa Central, superan los 200.000 habitantes. Por eso comparamos las UPZ con tasas por habitante y no con el número de casos, que crecería solo por el tamaño.
Excluimos las UPZ más pequeñas, pero no las más grandes, porque el criterio no es la forma de la distribución sino qué tan confiable es la tasa. En una UPZ con pocos habitantes, un solo caso la mueve bruscamente; en una con cientos de miles, apenas la altera. Las UPZ grandes son, de hecho, las que tienen las tasas más estables.
Revisamos las tres tasas que usan nuestras preguntas en las 101 UPZ.
datos_f %>%
select(`Hurto a personas` = tasa_hurto_personas,
`Violencia intrafamiliar` = tasa_violencia_intrafamiliar,
`Homicidios` = tasa_homicidios) %>%
pivot_longer(everything(), names_to = "Delito", values_to = "tasa") %>%
group_by(Delito) %>%
summarise(
`Mínimo` = min(tasa),
Q1 = quantile(tasa, 0.25),
Mediana = median(tasa),
Media = mean(tasa),
Q3 = quantile(tasa, 0.75),
`Máximo` = max(tasa),
`Desv. est.` = sd(tasa)
) %>%
mutate(across(where(is.numeric), ~ round(.x, 1))) %>%
tabla_bonita()| Delito | Mínimo | Q1 | Mediana | Media | Q3 | Máximo | Desv. est. |
|---|---|---|---|---|---|---|---|
| Homicidios | 0.0 | 0.2 | 0.6 | 0.9 | 1.1 | 6.2 | 1.1 |
| Hurto a personas | 15.7 | 54.3 | 96.0 | 167.7 | 159.7 | 1487.5 | 223.9 |
| Violencia intrafamiliar | 5.4 | 12.5 | 17.6 | 21.7 | 23.3 | 232.1 | 24.1 |
La UPZ típica (mediana) registra 96 denuncias de hurto, 18 de violencia intrafamiliar y 0,6 homicidios por cada 10.000 habitantes. El hurto es 5 veces la VIF y más de 150 veces los homicidios.
En las tres, la media es mayor que la mediana: la mayoría de las UPZ tiene valores bajos y unas pocas se disparan.
Las tres tasas varían mucho entre UPZ: su desviación estándar es incluso mayor que su media. Pero esa variación no viene de la mayoría, sino de unas pocas UPZ con valores muy altos. En el hurto el efecto es tan fuerte que el promedio (167,7) supera al 75 % de las UPZ: no representa a la UPZ típica, sino que lo arrastran los extremos. Por eso describimos cada tasa con la mediana y medimos las relaciones con la correlación de Spearman, que no se dejan influir por esos valores.
Para comparar la inseguridad por estrato necesitábamos clasificar cada UPZ, pero la base no asigna un estrato único: reporta qué porcentaje de las viviendas pertenece a los estratos 1–2, 3–4 y 5–6. Por eso construimos una variable nueva, el estrato predominante, que asigna a cada UPZ el rango con la mayor proporción de viviendas.
datos_f <- datos_f %>%
mutate(
estrato_dom = case_when(
pct_estrato_1_2 >= pmax(pct_estrato_3_4, pct_estrato_5_6) ~ "Estrato 1–2",
pct_estrato_3_4 >= pct_estrato_5_6 ~ "Estrato 3–4",
TRUE ~ "Estrato 5–6"
),
estrato_dom = factor(estrato_dom, levels = c("Estrato 1–2", "Estrato 3–4", "Estrato 5–6"))
)
datos_f %>%
count(`Estrato predominante` = estrato_dom, name = "UPZ") %>%
mutate(`% de las UPZ` = round(100 * UPZ / sum(UPZ), 1)) %>%
tabla_bonita()| Estrato predominante | UPZ | % de las UPZ |
|---|---|---|
| Estrato 1–2 | 41 | 40.6 |
| Estrato 3–4 | 53 | 52.5 |
| Estrato 5–6 | 7 | 6.9 |
De las 101 UPZ, el 41 % es predominantemente de estrato 1–2, el 52 % de estrato 3–4 y solo el 7 % de estrato 5–6. Esta clasificación simplifica la realidad, porque una UPZ puede mezclar viviendas de varios estratos, pero permite comparar grupos de forma clara. Hay que tener en cuenta que el grupo de estrato 5–6 tiene apenas 7 UPZ
Antes de responder cada pregunta, revisamos de forma general cómo se relacionan las variables. Usamos la correlación de Spearman, que va de −1 a 1: en vino, las variables que aumentan juntas; en azul, las que se mueven en sentido contrario.
nombres <- c(
tasa_hurto_personas = "Hurto a personas",
tasa_violencia_intrafamiliar = "Violencia intrafamiliar",
tasa_homicidios = "Homicidios",
pct_estrato_1_2 = "% estrato 1–2",
pct_percibe_inseguridad = "% percibe inseguridad",
pct_cerca_ollas = "% cerca de ollas",
pct_cerca_lotes_oscuros = "% cerca de lotes oscuros",
min_cai_policia = "Minutos al CAI"
)
datos_f %>%
select(all_of(names(nombres))) %>%
cor(method = "spearman") %>%
as.data.frame() %>%
rownames_to_column("var1") %>%
pivot_longer(-var1, names_to = "var2", values_to = "rho") %>%
mutate(var1 = factor(nombres[var1], levels = nombres),
var2 = factor(nombres[var2], levels = nombres)) %>%
filter(as.integer(var1) > as.integer(var2)) %>% # solo el triángulo inferior
ggplot(aes(x = var2, y = fct_rev(var1), fill = rho)) +
geom_tile(color = "white", linewidth = 0.8) +
geom_text(aes(label = format(round(rho, 2), nsmall = 2, decimal.mark = ","),
color = abs(rho) > 0.5), size = 3.2) +
scale_fill_gradient2(low = azul, mid = "white", high = vino,
midpoint = 0, limits = c(-1, 1), name = "Spearman") +
scale_color_manual(values = c(`TRUE` = "white", `FALSE` = noche), guide = "none") +
labs(title = "El hurto y la violencia se relacionan con variables opuestas",
subtitle = "Correlación de Spearman entre las variables del análisis · 101 UPZ",
x = NULL, y = NULL, caption = fuente) +
tema_clase +
theme(axis.text.x = element_text(angle = 45, hjust = 1), panel.grid = element_blank())La matriz anticipa la historia del informe. La violencia intrafamiliar, los homicidios, las ollas y la percepción de inseguridad aumentan juntos en las UPZ con más estrato 1–2. El hurto hace lo contrario: es menor donde predominan esos estratos (−0,71) y casi no se relaciona con la violencia intrafamiliar (−0,22). Llama la atención que la percepción de inseguridad crece con las ollas (0,67), pero no con el hurto (−0,39), y que los minutos al CAI prácticamente no se relacionan con nada. Estas son asociaciones, no causas: las responderemos con más detalle en cada pregunta.
Hasta ahora exploramos los delitos. Las preguntas también usan cuatro variables de la Encuesta Multipropósito, que describen lo que la gente percibe de su entorno.
datos_f %>%
select(`% que percibe inseguridad` = pct_percibe_inseguridad,
`% de viviendas cerca de ollas` = pct_cerca_ollas,
`% de viviendas cerca de lotes oscuros` = pct_cerca_lotes_oscuros,
`Minutos caminando al CAI` = min_cai_policia) %>%
pivot_longer(everything(), names_to = "Variable", values_to = "valor") %>%
group_by(Variable) %>%
summarise(`Mínimo` = min(valor),
Q1 = quantile(valor, 0.25),
Mediana = median(valor),
Q3 = quantile(valor, 0.75),
`Máximo` = max(valor)) %>%
mutate(across(where(is.numeric), ~ round(.x, 1))) %>%
tabla_bonita()| Variable | Mínimo | Q1 | Mediana | Q3 | Máximo |
|---|---|---|---|---|---|
| % de viviendas cerca de lotes oscuros | 0.6 | 11.3 | 17.9 | 24.9 | 59.8 |
| % de viviendas cerca de ollas | 0.3 | 10.1 | 20.9 | 30.5 | 75.6 |
| % que percibe inseguridad | 17.4 | 48.5 | 66.0 | 74.3 | 92.1 |
| Minutos caminando al CAI | 10.1 | 15.1 | 17.5 | 20.5 | 35.1 |
La percepción de inseguridad es alta en buena parte de la ciudad: en 72 de las 101 UPZ, más de la mitad de las personas reporta problemas de inseguridad en su entorno. En la UPZ típica, una de cada cinco viviendas tiene cerca una olla de microtráfico. En cambio, la distancia al CAI varía poco: la mitad de las UPZ está entre 15 y 20 minutos caminando, lo que podría limitar su capacidad para explicar diferencias entre zonas.
tasa_bogota_vif <- sum(datos$casos_violencia_intrafamiliar) / sum(datos$poblacion) * 10000
datos_f %>%
group_by(`Estrato predominante` = estrato_dom) %>%
summarise(
UPZ = n(),
`Mediana de VIF` = median(tasa_violencia_intrafamiliar),
`UPZ sobre Bogotá` = sum(tasa_violencia_intrafamiliar > tasa_bogota_vif),
casos = sum(casos_violencia_intrafamiliar),
pob = sum(poblacion)
) %>%
mutate(`% de los casos` = 100 * casos / sum(casos),
`% de la población` = 100 * pob / sum(pob)) %>%
select(-casos, -pob) %>%
mutate(across(where(is.double), ~ round(.x, 1))) %>%
tabla_bonita(resaltar = 1)| Estrato predominante | UPZ | Mediana de VIF | UPZ sobre Bogotá | % de los casos | % de la población |
|---|---|---|---|---|---|
| Estrato 1–2 | 41 | 22.6 | 28 | 60.3 | 50.1 |
| Estrato 3–4 | 53 | 15.5 | 11 | 37.3 | 45.4 |
| Estrato 5–6 | 7 | 9.4 | 0 | 2.4 | 4.5 |
set.seed(3) # para que la dispersión horizontal de los puntos sea siempre igual
puntos <- datos_f %>%
mutate(x = as.numeric(estrato_dom) + runif(n(), -0.22, 0.22),
y = pmin(tasa_violencia_intrafamiliar, 95), # recorta el valor extremo
sobre = tasa_violencia_intrafamiliar > tasa_bogota_vif)
medianas <- puntos %>%
group_by(estrato_dom) %>%
summarise(mediana = median(tasa_violencia_intrafamiliar)) %>%
mutate(x = as.numeric(estrato_dom))
ggplot(puntos, aes(x = x, y = y)) +
geom_hline(yintercept = tasa_bogota_vif, color = azul, linetype = "dashed") +
geom_point(aes(color = sobre), size = 2.5) +
geom_segment(data = medianas,
aes(x = x - 0.32, xend = x + 0.32, y = mediana, yend = mediana),
color = noche, linewidth = 1.3) +
geom_text(data = medianas,
aes(x = x + 0.36, y = mediana, label = format(round(mediana, 1), decimal.mark = ",")),
hjust = 0, fontface = "bold", color = noche, size = 3.6) +
annotate("text", x = 3.45, y = tasa_bogota_vif + 2.5, label = "Bogotá: 20,2",
color = azul, hjust = 1, size = 3.2) +
scale_color_manual(values = c(`TRUE` = vino, `FALSE` = gris), guide = "none") +
scale_x_continuous(breaks = 1:3, labels = levels(datos_f$estrato_dom)) +
coord_cartesian(ylim = c(0, 100)) +
labs(title = "La violencia intrafamiliar se concentra en los estratos bajos, pero no es exclusiva de ellos",
subtitle = "Tasa de VIF por UPZ · línea negra: mediana · en vino, UPZ por encima de Bogotá · eje recortado en 100",
x = NULL, y = "Denuncias de VIF por 10.000 hab", caption = fuente) +
tema_clase +
theme(panel.grid.major.x = element_blank())##
## Kruskal-Wallis rank sum test
##
## data: tasa_violencia_intrafamiliar by estrato_dom
## Kruskal-Wallis chi-squared = 28.884, df = 2, p-value = 5.344e-07
La violencia intrafamiliar se concentra en las UPZ de estratos bajos: la mediana pasa de 22,6 denuncias por 10.000 habitantes en el estrato 1–2 a 9,4 en el 5–6, es decir, 2,4 veces más. La diferencia es estadísticamente significativa (Kruskal-Wallis, p < 0,001). Sin embargo, no es exclusiva de estos estratos: una de cada cinco UPZ de estrato 3–4 también supera la tasa de Bogotá.
datos_f %>%
mutate(hurto_km2 = casos_hurto_personas / area_km2) %>%
select(estrato_dom,
`Por cada 10.000 habitantes` = tasa_hurto_personas,
`Por km²` = hurto_km2) %>%
pivot_longer(-estrato_dom, names_to = "medida", values_to = "valor") %>%
ggplot(aes(x = estrato_dom, y = valor)) +
geom_boxplot(fill = azul, alpha = 0.7, width = 0.55, outlier.color = azul) +
facet_wrap(~ medida, ncol = 1, scales = "free_y") +
scale_y_continuous(labels = label_comma(big.mark = ".")) +
labs(title = "Las UPZ de estratos bajos tienen menos hurto, con cualquiera de las dos medidas",
subtitle = "Denuncias de hurto a personas por UPZ según estrato predominante, ene–jul 2023 · 101 UPZ",
x = NULL, y = NULL, caption = fuente) +
tema_clase +
theme(strip.text = element_text(face = "bold", hjust = 0, size = 11),
panel.grid.major.x = element_blank())El hurto sigue el patrón contrario: la mediana es de 52 denuncias por 10.000 habitantes en el estrato 1–2, frente a 147 en el 3–4 y 154 en el 5–6. Al medirlo por km², que no depende de cuántas personas viven en la zona, el estrato 1–2 sigue teniendo menos hurto (126 frente a 271 en el 3–4), pero la ventaja del estrato 5–6 desaparece (160). La conclusión sólida es que en los estratos bajos hay menos hurto; no que en los altos haya más.
# Unimos los datos al mapa. Las UPZ con menos de 10.000 hab quedan en NA (gris).
mapa <- upz_shp %>%
left_join(datos %>% select(upz_cod, pob_baja, tasa_hurto_personas,
tasa_violencia_intrafamiliar),
by = "upz_cod") %>%
mutate(hurto_mapa = if_else(pob_baja, NA_real_, tasa_hurto_personas),
vif_mapa = if_else(pob_baja, NA_real_, tasa_violencia_intrafamiliar))
m_hurto <- ggplot(mapa) +
geom_sf(aes(fill = hurto_mapa), color = "white", linewidth = 0.1) +
geom_sf(data = loc_shp, fill = NA, color = "grey40", linewidth = 0.25) +
scale_fill_gradient(low = "#EAF1FA", high = "#173A66", trans = "log10",
na.value = "grey90", name = "Tasa de\nhurto",
labels = label_number(accuracy = 1)) +
labs(title = "Hurto a personas") +
theme_void() +
theme(plot.title = element_text(face = "bold", color = azul, hjust = 0.5))
m_vif <- ggplot(mapa) +
geom_sf(aes(fill = vif_mapa), color = "white", linewidth = 0.1) +
geom_sf(data = loc_shp, fill = NA, color = "grey40", linewidth = 0.25) +
scale_fill_gradient(low = "#FBEAEC", high = "#5C0F20", trans = "log10",
na.value = "grey90", name = "Tasa de\nVIF",
labels = label_number(accuracy = 1)) +
labs(title = "Violencia intrafamiliar") +
theme_void() +
theme(plot.title = element_text(face = "bold", color = vino, hjust = 0.5))
m_hurto + m_vif +
plot_annotation(
title = "El hurto y la violencia intrafamiliar dibujan dos mapas distintos de Bogotá",
subtitle = "Denuncias por cada 10.000 habitantes, ene–jul 2023 · escala logarítmica · en gris, UPZ con menos de 10.000 habitantes",
caption = fuente,
theme = theme(plot.title = element_text(face = "bold", size = 15, color = noche),
plot.subtitle = element_text(color = "grey35"),
plot.caption = element_text(hjust = 0, color = "grey45"))
)## [1] -0.2238769
Los dos mapas muestran patrones distintos: el hurto se concentra en el centro y el norte, y la violencia intrafamiliar en el sur y el centro. La correlación entre ambas tasas es baja y negativa (−0,22): las UPZ con más hurto no son las de más violencia. Son dos fenómenos con territorios diferentes.
ggplot(datos_f, aes(x = pct_cerca_ollas, y = tasa_homicidios, color = estrato_dom)) +
geom_point(size = 2.5, alpha = 0.8) +
geom_smooth(method = "lm", se = FALSE, linewidth = 0.9) +
scale_color_manual(values = c("Estrato 1–2" = vino, "Estrato 3–4" = "grey55",
"Estrato 5–6" = noche), name = NULL) +
labs(title = "Más ollas, más homicidios, incluso entre UPZ del mismo estrato",
subtitle = "Cada punto es una UPZ · líneas: tendencia dentro de cada estrato predominante · 101 UPZ",
x = "% de viviendas con ollas de microtráfico cerca",
y = "Homicidios por 10.000 hab", caption = fuente) +
tema_clase +
theme(legend.position = "top")# Como los homicidios son pocos, comparamos grupos de UPZ (tercios según ollas)
datos_f %>%
mutate(nivel_ollas = cut(pct_cerca_ollas,
breaks = quantile(pct_cerca_ollas, c(0, 1/3, 2/3, 1)),
labels = c("Bajo", "Medio", "Alto"), include.lowest = TRUE)) %>%
mutate(homicidios = round(tasa_homicidios * poblacion / 10000)) %>% # casos = tasa × población
group_by(`Presencia de ollas` = nivel_ollas) %>%
summarise(UPZ = n(),
Homicidios = sum(homicidios),
pob = sum(poblacion)) %>%
mutate(`Tasa del grupo (por 10.000 hab)` = round(10000 * Homicidios / pob, 2),
`% de los homicidios` = round(100 * Homicidios / sum(Homicidios), 1)) %>%
select(-pob) %>%
tabla_bonita(resaltar = 3)| Presencia de ollas | UPZ | Homicidios | Tasa del grupo (por 10.000 hab) | % de los homicidios |
|---|---|---|---|---|
| Bajo | 34 | 55 | 0.29 | 9.3 |
| Medio | 33 | 175 | 0.61 | 29.5 |
| Alto | 34 | 364 | 1.17 | 61.3 |
En el tercio de UPZ con más viviendas cerca de ollas, la tasa de homicidios es cuatro veces la del tercio con menos ollas (1,17 frente a 0,29 por 10.000 habitantes), y allí ocurre el 61 % de los homicidios. La relación se mantiene, aunque más débil, al comparar UPZ del mismo estrato. Aun así, es una asociación: los datos no permiten saber si las ollas generan la violencia.
top_hurto <- datos_f %>%
slice_min(tasa_hurto_personas, n = 10) %>%
mutate(etiqueta = fct_rev(fct_reorder(paste0(upz_nombre, " (", localidad, ")"),
tasa_hurto_personas)))
med_hurto <- median(datos_f$tasa_hurto_personas)
med_perc <- median(datos_f$pct_percibe_inseguridad)
# Panel izquierdo: hurto
g_hurto <- ggplot(top_hurto, aes(x = tasa_hurto_personas, y = etiqueta)) +
geom_col(fill = azul, width = 0.65) +
geom_text(aes(label = format(round(tasa_hurto_personas, 1), decimal.mark = ",")),
hjust = -0.2, size = 3.2, color = noche) +
geom_vline(xintercept = med_hurto, color = noche, linetype = "dashed") +
annotate("text", x = med_hurto, y = 10.4, label = "UPZ típica: 96",
hjust = 1.05, vjust = 0, size = 3.1, color = noche) +
scale_x_continuous(limits = c(0, 105)) +
labs(title = "Tasa de hurto (por 10.000 hab)", x = NULL, y = NULL) +
tema_clase +
theme(panel.grid.major.y = element_blank(),
plot.title = element_text(size = 12, color = azul))
# Panel derecho: percepción de inseguridad
g_perc <- ggplot(top_hurto, aes(x = pct_percibe_inseguridad, y = etiqueta)) +
geom_col(fill = vino, width = 0.65) +
geom_text(aes(label = paste0(round(pct_percibe_inseguridad), " %")),
hjust = -0.2, size = 3.2, color = noche) +
geom_vline(xintercept = med_perc, color = noche, linetype = "dashed") +
annotate("text", x = med_perc, y = 10.4, label = "UPZ típica: 66 %",
hjust = 1.05, vjust = 0, size = 3.1, color = noche) +
scale_x_continuous(limits = c(0, 100)) +
labs(title = "% que percibe inseguridad", x = NULL, y = NULL) +
tema_clase +
theme(panel.grid.major.y = element_blank(),
axis.text.y = element_blank(),
plot.title = element_text(size = 12, color = vino))
g_hurto + g_perc +
plot_annotation(
title = "Las 10 UPZ con menos hurto no son las que se sienten más seguras",
subtitle = "Todas están muy por debajo del hurto de la UPZ típica, pero 7 de 10 superan su percepción de inseguridad",
caption = fuente,
theme = theme(plot.title = element_text(face = "bold", size = 15, color = noche),
plot.subtitle = element_text(color = "grey35"),
plot.caption = element_text(hjust = 0, color = "grey45"))
)No. Las diez UPZ con menor tasa de hurto —nueve de ellas de estrato 1–2, como San Isidro–Patios, Tintal Sur y Alfonso López— no se sienten más seguras que el resto de la ciudad. En siete de ellas, la percepción de inseguridad supera la de la UPZ típica de Bogotá (66 %). En El Tesoro, por ejemplo, la tasa de hurto es baja (36), pero el 87 % de las personas percibe inseguridad en su entorno. Tener poco hurto no significa sentirse seguro, lo que anticipa la siguiente pregunta: si no es el hurto, ¿qué genera el miedo? ## 3.6 ¿Qué genera más miedo: el hurto o el deterioro del entorno?
factores <- c(
pct_cerca_ollas = "% cerca de ollas",
tasa_violencia_intrafamiliar = "Violencia intrafamiliar",
tasa_homicidios = "Homicidios",
pct_cerca_lotes_oscuros = "% cerca de lotes oscuros",
min_cai_policia = "Minutos al CAI",
tasa_hurto_personas = "Hurto a personas"
)
tibble(variable = names(factores)) %>%
mutate(rho = map_dbl(variable, ~ cor(datos_f[[.x]], datos_f$pct_percibe_inseguridad,
method = "spearman")),
etiqueta = factores[variable]) %>%
ggplot(aes(x = rho, y = fct_reorder(etiqueta, rho), fill = rho > 0)) +
geom_col(width = 0.6) +
geom_vline(xintercept = 0, color = noche) +
geom_text(aes(label = format(round(rho, 2), decimal.mark = ","),
hjust = if_else(rho >= 0, -0.2, 1.2)), size = 3.4, color = noche) +
scale_fill_manual(values = c(`TRUE` = vino, `FALSE` = azul), guide = "none") +
scale_x_continuous(limits = c(-1, 1)) +
labs(title = "El miedo no sigue al hurto: sigue a las ollas y a la violencia",
subtitle = "Correlación de Spearman de cada factor con el % que percibe inseguridad · 101 UPZ",
x = "Correlación con la percepción de inseguridad", y = NULL, caption = fuente) +
tema_clase +
theme(panel.grid.major.y = element_blank())La percepción de inseguridad aumenta con la presencia de ollas (0,67) y de lotes oscuros (0,35), pero disminuye donde hay más hurto (−0,39). La gente percibe más inseguridad por el deterioro de su entorno que por el delito más frecuente de la ciudad. Esto explica el contraste de la pregunta anterior: las UPZ con poco hurto pueden sentirse inseguras porque allí se concentran las ollas, los lotes oscuros y la violencia.
top_lotes <- datos_f %>%
slice_max(pct_cerca_lotes_oscuros, n = 10) %>%
mutate(upz = fct_reorder(upz_nombre, pct_cerca_lotes_oscuros),
critica = pct_percibe_inseguridad > 90)
ggplot(top_lotes, aes(y = upz)) +
geom_segment(aes(x = pct_cerca_lotes_oscuros, xend = pct_percibe_inseguridad,
yend = upz, color = critica), linewidth = 1.2) +
geom_point(aes(x = pct_cerca_lotes_oscuros), color = "grey55", size = 3) +
geom_point(aes(x = pct_percibe_inseguridad, color = critica), size = 3.5) +
geom_text(aes(x = pct_percibe_inseguridad, label = paste0(round(pct_percibe_inseguridad), " %"),
color = critica), hjust = -0.4, size = 3.2, fontface = "bold") +
geom_vline(xintercept = 90, color = vino, linetype = "dashed") +
annotate("text", x = 90, y = 10.6, label = "90 %", color = vino, size = 3.2, hjust = 1.1) +
scale_color_manual(values = c(`TRUE` = vino, `FALSE` = "grey75"), guide = "none") +
scale_x_continuous(limits = c(0, 105), labels = function(x) paste0(x, " %")) +
labs(title = "Corabastos es la única UPZ con muchos lotes oscuros\ny más del 90 % de percepción de inseguridad",
subtitle = "10 UPZ con más viviendas cerca de lotes oscuros · punto gris: % de viviendas expuestas · punto final: % que percibe inseguridad",
x = NULL, y = NULL, caption = fuente) +
tema_clase +
theme(panel.grid.major.y = element_blank(),
axis.text.y = element_text(color = ifelse(levels(top_lotes$upz) == "Corabastos", vino, "grey30"),
face = ifelse(levels(top_lotes$upz) == "Corabastos", "bold", "plain")))top_lotes %>%
arrange(desc(pct_cerca_lotes_oscuros)) %>%
transmute(UPZ = upz_nombre, Localidad = localidad,
`% viviendas cerca de lotes oscuros` = round(pct_cerca_lotes_oscuros, 1),
`% percibe inseguridad` = round(pct_percibe_inseguridad, 1)) %>%
tabla_bonita(resaltar = 3) # Corabastos| UPZ | Localidad | % viviendas cerca de lotes oscuros | % percibe inseguridad |
|---|---|---|---|
| Zona Franca | Fontibón | 59.8 | 44.9 |
| Tintal Sur | Bosa | 49.0 | 74.4 |
| Corabastos | Kennedy | 48.9 | 92.1 |
| Tintal Norte | Kennedy | 46.4 | 54.0 |
| Puente Aranda | Puente Aranda | 45.3 | 66.3 |
| El Tesoro | Ciudad Bolívar | 45.0 | 86.8 |
| Granjas De Techo | Fontibón | 41.4 | 40.6 |
| Capellania | Fontibón | 40.1 | 32.6 |
| La Sabana | Los Mártires | 38.7 | 83.4 |
| Danubio | Usme | 37.0 | 58.3 |
Las UPZ con más viviendas cerca de lotes baldíos u oscuros están en Fontibón, Bosa y Kennedy. Solo Corabastos combina alta exposición (49 %) con una percepción de inseguridad superior al 90 %, aunque El Tesoro (87 %) y La Sabana (83 %) también registran una percepción muy alta. En cambio, Zona Franca tiene la mayor exposición (60 %) y solo 45 % de percepción: los lotes oscuros se asocian con el miedo, pero no lo explican por sí solos.
datos_f %>%
mutate(distancia = cut(min_cai_policia,
breaks = quantile(min_cai_policia, c(0, 1/3, 2/3, 1)),
labels = c("Cerca", "Media", "Lejos"), include.lowest = TRUE)) %>%
group_by(distancia) %>%
summarise(minutos = median(min_cai_policia),
percepcion = median(pct_percibe_inseguridad)) %>%
ggplot(aes(x = distancia, y = percepcion)) +
geom_col(fill = gris, width = 0.6) +
geom_text(aes(label = paste0(round(percepcion), " %")),
vjust = -0.5, size = 4, fontface = "bold", color = noche) +
geom_text(aes(y = 3, label = paste0(round(minutos), " min al CAI")),
vjust = 0, size = 3.2, color = "grey30") +
scale_y_continuous(limits = c(0, 100), labels = function(x) paste0(x, " %")) +
labs(title = "Tener un CAI más cerca no cambia la percepción de inseguridad",
subtitle = "Mediana del % que percibe inseguridad según la distancia caminando al CAI (tercios de UPZ) · 101 UPZ",
x = "Distancia al CAI", y = "% que percibe inseguridad", caption = fuente) +
tema_clase +
theme(panel.grid.major.x = element_blank())## [1] 0.01459595
La cercanía al CAI no se relaciona con la percepción de inseguridad (correlación de 0,01): es casi igual cerca (63 %), a distancia media (71 %) o lejos (61 %). Además, la distancia al CAI varía poco entre UPZ (la mitad está entre 15 y 20 minutos), lo que limita su capacidad para explicar diferencias. Tener la policía cerca no se asocia con sentirse más seguro.