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 estilo
library(plotly)      # gráficos interactivos (información al pasar el mouse)
azul  <- "#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
         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)

1. Introducción y preguntas

1.1 Contexto

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 tres tipos de inseguridad —el hurto , la violencia intrafamiliar (VIF) y el homicidio — y cómo la percibe la ciudadanía.No es lo mismo un robo en una calle comercial que una agresión dentro de un hogar. Y no siempre la gente siente más miedo donde más se denuncia.

1.2 Preguntas

  1. ¿La violencia intrafamiliar se concentra predominantemente en las UPZ de estratos bajos, o se presenta de forma heterogénea a través de los estratos medios y altos?

  2. ¿Ocurren más hurtos a personas en UPZ con alta presencia de estratos 5 y 6 o de estratos 1 y 2?

  3. ¿El delito de hurto y la violencia intrafamiliar se concentran en las mismas UPZ?

  4. ¿La presencia de microtráfico tiene alguna relación con la violencia por homicidios en las UPZ de Bogotá?

  5. ¿Cuáles son las 10 UPZ con menor tasa de hurto, y estas se sienten más seguras que el resto de la ciudad?

  6. ¿¿Qué genera más miedo en la ciudadanía: el hurto o el deterioro del entorno por la cercanía a ollas de microtráfico O lotes oscuros?

  7. ¿Cuáles son las UPZ con mayor porcentaje de viviendas cercanas a lotes baldíos u oscuros, y en cuál de ellas la percepción de inseguridad supera el 90 %?

  8. ¿Tener un CAI de policía más cerca se asocia con una mayor percepción de seguridad en la zona?

1.3 Variables elegidas

Para responder las ocho preguntas elegimos 13 variables de cuatro bloques de la base: identificación, demografía, delitos y la Encuesta Multipropósito. La tabla muestra cada variable y la pregunta que ayuda a responder.

Estas 13 variables se consideraron por la mayor relevancia al enfoque de estudio

tibble(
  Bloque = c("Identificación", "Identificación", "Identificación",
             "Demografía", "Demografía",
             "Delitos", "Delitos", "Delitos",
             "Encuesta", "Encuesta", "Encuesta", "Encuesta", "Encuesta"),
  Variable = c("upz_cod", "upz_nombre", "localidad",
               "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(
    "Llave para unir la tabla con el mapa (P3)",
    "Nombrar las UPZ en tablas, rankings y gráficos",
    "Ubicar cada UPZ en la ciudad",
    "Filtrar UPZ con poca población y calcular tasas de Bogotá",
    "Medir el hurto por km² (P2)",
    "Violencia intrafamiliar (P1, P3, P6)",
    "Hurto a personas (P2, P3, P5, P6)",
    "Homicidios (P4, P6)",
    "Estrato predominante de cada UPZ (P1, P2)",
    "Percepción de inseguridad (P5, P6, P7, P8)",
    "Microtráfico (P4, P6)",
    "Lotes baldíos u oscuros (P6, P7)",
    "Cercanía al CAI (P8)")
) %>%
  tabla_bonita()
Bloque Variable Para qué la usamos
Identificación upz_cod Llave para unir la tabla con el mapa (P3)
Identificación upz_nombre Nombrar las UPZ en tablas, rankings y gráficos
Identificación localidad Ubicar cada UPZ en la ciudad
Demografía poblacion Filtrar UPZ con poca población y calcular tasas de Bogotá
Demografía area_km2 Medir el hurto por km² (P2)
Delitos tasa_violencia_intrafamiliar Violencia intrafamiliar (P1, P3, P6)
Delitos tasa_hurto_personas Hurto a personas (P2, P3, P5, P6)
Delitos tasa_homicidios Homicidios (P4, P6)
Encuesta pct_estrato_1_2 / 3_4 / 5_6 Estrato predominante de cada UPZ (P1, P2)
Encuesta pct_percibe_inseguridad Percepción de inseguridad (P5, P6, P7, P8)
Encuesta pct_cerca_ollas Microtráfico (P4, P6)
Encuesta pct_cerca_lotes_oscuros Lotes baldíos u oscuros (P6, P7)
Encuesta min_cai_policia Cercanía al CAI (P8)

2. Los datos y su exploración

2.1 Estructura y faltantes

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)"),
  Resultado = c(nrow(upz), ncol(upz), sum(is.na(datos)),
                n_distinct(datos$upz_cod))
) %>%
  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

La base se encuentra en condiciones para iniciar un análisis, dado que esta sin datos faltantes y con una llave única.

2.2 UPZ con muy poca población

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.

datos   <- datos %>% mutate(pob_baja = poblacion < 10000)
datos_f <- datos %>% filter(!pob_baja)   # tabla de análisis: 101 UPZ

2.3 ¿Cómo se reparte la población?

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 con pocos habitantes debido a que , un solo caso la mueve bruscamente; en cambio una con cientos de miles, apenas la altera.

2.4 ¿Cómo se reparten las tasas?

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.

2.5 El estrato predominante de cada UPZ

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 % corresponden al 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.

2.6 ¿Cómo se relacionan las variables entre sí?

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_estrato_3_4              = "% estrato 3–4",
  pct_estrato_5_6              = "% estrato 5–6",
  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())

Esta matriz nos permite tener un panorama general de como se relacionan las variables elegidas entre si, dandonos un panorama hacia donde llevar la historia, puesto que se abordaran más adetalle en los hallazgos por cada pregunta. Por el momento se puede destacar que la presencia de ollas es alta en estratos bajos y si nos vamos al otro extremo vemos que la percepción de seguridad es mayor en estratos 5-6.

2.7 ¿Cómo se reparten las variables de la encuesta?

Hasta ahora exploramos las denuncias por 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 la UPZ típica, el 66 % de las personas reporta problemas de inseguridad en su entorno, y en tres de cada cuatro UPZ supera el 48 %.

En la UPZ típica, una de cada cinco viviendas tiene cerca una olla de microtráfico. En cambio, el tiempo caminando al CAI varía poco: la mitad de las UPZ está entre 15 y 20 minutos.

3. Análisis

En este apartado le daremos respuesta a las preguntas plantedas por medio de visualización grafica e informaremos los hallazgos evidenciados en cada una de ellas.

3.1 ¿La violencia intrafamiliar se concentra predominantemente en las UPZ de estratos bajos, o se presenta de forma heterogénea a través de los estratos medios y altos?

tasa_bogota_vif <- sum(datos$tasa_violencia_intrafamiliar * datos$poblacion) / sum(datos$poblacion)

datos_f %>%
  mutate(y = pmin(tasa_violencia_intrafamiliar, 99)) %>%      # recorta el valor extremo
  ggplot(aes(x = estrato_dom, y = y)) +
  geom_boxplot(fill = "#F3D9DE", color = "grey55", width = 0.5,
               outlier.color = vino, outlier.size = 2.5) +
  geom_hline(yintercept = tasa_bogota_vif, color = azul, linetype = "dashed") +
  annotate("text", x = 3.45, y = tasa_bogota_vif + 2.5, label = "Bogotá: 20,2",
           color = azul, hjust = 1, size = 3.2) +
  coord_cartesian(ylim = c(0, 100)) +
  labs(title = "La violencia intrafamiliar se denuncia más en los estratos bajos,\npero también hay UPZ críticas en los estratos medios",
       subtitle = "Tasa de VIF por UPZ según estrato predominante · eje recortado: una UPZ de estrato 3–4 llega a 232",
       x = NULL, y = "Denuncias de VIF por 10.000 hab", caption = fuente) +
  tema_clase +
  theme(panel.grid.major.x = element_blank())

Se evidencia que la violencia intrafamiliar en Bogotá no se concentra exclusivamente en los estratos bajos, pero tampoco se distribuye de forma pareja: los estratos 1-2 son los que, en conjunto, cargan con la mayor tasa de denuncias, mientras que los estratos 5-6 registran los niveles más bajos y homogéneos (alrededor de 9,4). Sin embargo, no se debe pasar por alto el comportamiento de denuncias en estratos medios: aunque su mediana es más baja (15,5), allí aparecen las UPZ más críticas de toda la ciudad, con tasas superiores a 80 denuncias por 10.000 habitantes, por encima del caso más extremo de los estratos bajos y más de cuatro veces el promedio de Bogotá.

En resumen, podemos decir que el problema es predominante en los estratos bajos, pero heterogéneo en la población. Además, estas cifras miden lo que se denuncia y no necesariamente todo lo que ocurre, por lo que las tasas bajas de los estratos altos podrían esconder subregistros.

3.2 ¿Ocurren más hurtos a personas en UPZ con alta presencia de estratos 5 y 6 o en zonas de estratos 1 y 2?

datos_f %>%
  group_by(estrato_dom) %>%
  summarise(hurto = median(tasa_hurto_personas)) %>%
  mutate(destacar = estrato_dom == "Estrato 5–6") %>%
  ggplot(aes(x = hurto, y = estrato_dom, fill = destacar)) +
  geom_col(width = 0.6) +
  geom_text(aes(label = round(hurto), color = destacar),
            hjust = -0.3, size = 4.2, fontface = "bold") +
  scale_fill_manual(values = c(`TRUE` = vino, `FALSE` = gris), guide = "none") +
  scale_color_manual(values = c(`TRUE` = vino, `FALSE` = "grey55"), guide = "none") +
  scale_x_continuous(limits = c(0, 175), expand = c(0, 0)) +
  labs(title = "Las denuncias por hurto predominan en UPZ de estratos medios y altos",
       x = "Denuncias de hurto por cada 10.000 habitantes", y = NULL, caption = fuente) +
  tema_clase +
  theme(panel.grid.major.y = element_blank())

El hurto a personas en Bogotá es, sobre todo, un fenómeno de estratos medios y altos: las UPZ de estratos 5-6 registran 154 denuncias por cada 10.000 habitantes y las de estratos 3-4, 147, frente a solo 52 en los estratos 1-2, es decir, casi tres veces menos. Esto contrasta con la violencia intrafamiliar, que se denuncia más en los estratos bajos, lo que revela que la inseguridad no golpea igual a todos: en unas zonas la amenaza está en el hogar y en otras en la calle. Sin embargo, la baja tasa de denuncias en los estratos 1-2 no indica que el hurto no ocurra; podría deberse a un tema de cultura ciudadana y a la percepción que tiene esta población sobre la importancia de denunciar este tipo de delitos, y sobre cuánto vale el esfuerzo frente al resultado obtenido al hacerlo.

3.3 ¿El hurto y la violencia intrafamiliar se concentran en las mismas UPZ?

med_hurto <- median(datos_f$tasa_hurto_personas)
med_vif   <- median(datos_f$tasa_violencia_intrafamiliar)

mapa <- upz_shp %>%
  left_join(datos %>% select(upz_cod, nom = upz_nombre, loc = localidad, poblacion, pob_baja,
                             tasa_hurto_personas, tasa_violencia_intrafamiliar),
            by = "upz_cod") %>%
  mutate(grupo = case_when(
           is.na(pob_baja) | pob_baja ~ "Excluida (menos de 10.000 hab)",
           tasa_hurto_personas > med_hurto & tasa_violencia_intrafamiliar > med_vif ~ "Ambos altos",
           tasa_hurto_personas > med_hurto ~ "Solo hurto alto",
           tasa_violencia_intrafamiliar > med_vif ~ "Solo VIF alta",
           TRUE ~ "Ambos bajos"),
         grupo = factor(grupo, levels = c("Solo hurto alto", "Solo VIF alta", "Ambos altos",
                                          "Ambos bajos", "Excluida (menos de 10.000 hab)")),
         info = paste0("<b>", nom, "</b><br>", loc,
                       "<br>Población: ", format(poblacion, big.mark = ".", decimal.mark = ","), " hab",
                       "<br>Tasa de hurto: ", round(tasa_hurto_personas, 1),
                       "<br>Tasa de VIF: ", round(tasa_violencia_intrafamiliar, 1),
                       "<br><b>", grupo, "</b>"))



g_mapa <- ggplot(mapa) +
  geom_sf(aes(fill = grupo, text = info), color = "white", linewidth = 0.2) +
  scale_fill_manual(values = c("Solo hurto alto" = azul,
                               "Solo VIF alta"   = vino,
                               "Ambos altos"     = "#3A1F4D",
                               "Ambos bajos"     = gris,
                               "Excluida (menos de 10.000 hab)" = "#EFEFEF"),
                    name = NULL) +
  theme_void()

ggplotly(g_mapa, tooltip = "text") %>%
  layout(
    title = list(
      text = paste0("<b>El hurto y la violencia intrafamiliar se concentran<br>",
                    "en zonas distintas de Bogotá</b>",
                    "<br><span style='font-size:12px; color:grey'>",
                    "Alto = tasa por encima de la mediana de las 101 UPZ</span>"),
      x = 0.01, xanchor = "left", font = list(size = 18, color = noche)),
    margin = list(t = 80),
    legend = list(title = list(text = ""),
                  orientation = "v",
                  x = 0.01, y = 0.01, xanchor = "left", yanchor = "bottom",
                  bgcolor = "rgba(255,255,255,0.85)")) %>%
  config(displayModeBar = FALSE)
cor(datos_f$tasa_hurto_personas, datos_f$tasa_violencia_intrafamiliar, method = "spearman")
## [1] -0.2238769

En el mapa se ve que el hurto y la violencia intrafamiliar ocupan zonas distintas de la ciudad: solo 16 de las 101 UPZ tienen ambos delitos por encima de la mediana, y la correlación entre las dos tasas es baja y negativa (−0,22).

El hurto se concentra en el centro, el norte y el occidente, mientras que en el sur y suroccidente es mucho más bajo, con UPZ como Usme, Timiza o Arborizadora que registran entre 50 y 80 denuncias por 10.000 habitantes, coherente con lo que mostraba el análisis por estrato.

La violencia intrafamiliar, en cambio, se concentra en el sur y el suroccidente, aunque no de forma exclusiva: también hay UPZ del norte con tasas altas, como San Cristóbal Norte, El Rincón, Tibabuyes y Teusaquillo. Además, muchas de las UPZ en vino tienen tasas cercanas a la mediana (17,6), lo que muestra que la violencia intrafamiliar está bastante extendida en la ciudad.

Los picos más extremos de ambos problemas coinciden en el centro histórico: Sagrado Corazón tiene una tasa de violencia intrafamiliar de 232, más de once veces la tasa de Bogotá, y Las Nieves un hurto de casi 1.500. Pero son UPZ con pocos residentes y mucha población flotante, así que sus tasas dicen tanto de la actividad de la zona como del riesgo de quienes viven allí.

Como conclusión, la ciudad necesita respuestas distintas según el territorio, y medir por habitantes residentes puede distorsionar justamente los lugares donde más gente circula.

3.4 ¿La presencia de microtráfico tiene alguna relación con la violencia por homicidios en las UPZ de Bogotá?

g_p4 <- ggplot(datos_f, aes(x = pct_cerca_ollas, y = tasa_homicidios)) +
  geom_point(aes(size = poblacion,
                 text = paste0("<b>", upz_nombre, "</b> (", localidad, ")",
                               "<br>Ollas cerca: ", round(pct_cerca_ollas, 1), " %",
                               "<br>Homicidios: ", round(tasa_homicidios, 2), " por 10.000 hab",
                               "<br>Población: ", format(poblacion, big.mark = "."))),
             color = vino, alpha = 0.5) +
  geom_smooth(method = "lm", se = FALSE, color = noche,
              linetype = "dashed", linewidth = 0.8) +
  scale_size_continuous(range = c(1, 8), guide = "none") +
  labs(title = "Donde hay más ollas de microtráfico, hay más homicidios",
       x = "% de viviendas con ollas de microtráfico cerca",
       y = "Homicidios por 10.000 hab") +
  tema_clase

ggplotly(g_p4, tooltip = "text") %>%
  layout(showlegend = FALSE) %>%
  config(displayModeBar = FALSE)

En la gráfica se puede ver que donde hay más ollas de microtráfico cerca de las viviendas tiende a haber más homicidios (correlación de 0,64), pero la relación es una tendencia y no una regla: la línea sube de forma clara, aunque las UPZ se dispersan bastante a su alrededor. Las dos más críticas están en el centro de la ciudad: Las Cruces, con 75,6 % de viviendas cerca de ollas y 6,25 homicidios por cada 10.000 habitantes, y La Sabana, con 61,4 % y 6,18. Lucero, en Ciudad Bolívar, es el caso de mayor peso humano: con más de 163 mil habitantes y la mitad de sus viviendas expuestas, registra 2,87 homicidios por 10.000.

Sin embargo, la exposición no determina el desenlace: El Rincón y Tibabuyes, en Suba, tienen cerca de un tercio de viviendas expuestas y más de 295 mil habitantes cada una, pero apenas 0,5 homicidios por 10.000, mientras que Álamos, en Engativá, supera los 2 con solo 3,2 % de exposición, aunque con apenas 12 mil habitantes esa tasa corresponde a muy pocos casos.

El microtráfico se asocia con los homicidios, pero no los explica por sí solo: el contexto de cada territorio marca la diferencia.

3.5 ¿Cuáles son las 10 UPZ con menor tasa de hurto, y estas se sienten más seguras que el resto de la ciudad?

med_hurto <- median(datos_f$tasa_hurto_personas)
med_perc  <- median(datos_f$pct_percibe_inseguridad)

datos_f %>%
  slice_min(tasa_hurto_personas, n = 10) %>%
  arrange(tasa_hurto_personas) %>%
  mutate(hurto_rel = 100 * tasa_hurto_personas / med_hurto,       # 100 = UPZ típica
         perc_rel  = 100 * pct_percibe_inseguridad / med_perc,     # 100 = UPZ típica
         upz       = paste0(row_number(), ". ", upz_nombre),
         upz       = fct_rev(fct_inorder(upz))) %>%                # menor hurto arriba
  ggplot(aes(y = upz)) +
  geom_segment(aes(x = hurto_rel, xend = perc_rel, yend = upz),
               color = "grey82", linewidth = 1.3) +
  geom_point(aes(x = hurto_rel, color = "Hurto"), size = 3.8) +
  geom_point(aes(x = perc_rel, color = "Percepción de inseguridad"), size = 3.8) +
  geom_text(aes(x = hurto_rel, label = round(hurto_rel)),
            hjust = 1.8, size = 3.3, color = azul, fontface = "bold") +
  geom_text(aes(x = perc_rel, label = round(perc_rel)),
            hjust = -0.8, size = 3.3, color = vino, fontface = "bold") +
  geom_vline(xintercept = 100, color = noche, linetype = "dashed") +
    annotate("text", x = 101, y = 0.3, label = "UPZ típica de Bogotá = 100",
           hjust = 0, size = 3.1, color = noche) +
  scale_color_manual(values = c("Hurto" = azul, "Percepción de inseguridad" = vino),
                     name = NULL) +
  scale_y_discrete(expand = expansion(add = c(1.2, 0.6))) +
  scale_x_continuous(limits = c(0, 145)) +
  labs(title = "Menos hurto no es sinónimo de seguridad: 7 de las 10 UPZ con menos hurto\nse sienten más inseguras que la UPZ típica",
       x = NULL, y = NULL, caption = fuente) +
  tema_clase +
  theme(legend.position = "top", legend.justification = "left",
        panel.grid.major.y = element_blank())

Tener pocas denuncias de hurto no basta para concluir que una zona es segura: de las diez UPZ de Bogotá con menor tasa de hurto denunciado, solo tres, San Isidro - Patios, Los Libertadores y Verbenal , se sienten igual o más seguras que la UPZ típica . Las otras que registran apenas entre el 30% y el 38% de las denuncias de la UPZ típica, pero su percepción de inseguridad es mayor, con El Tesoro, caso extremo: 38 en denuncias frente a 132 en percepción.

Este desajuste admite al menos dos lecturas que los datos no permiten separar: que la gente se sienta insegura por otros factores distintos al hurto, como otros delitos o el deterioro del entorno, o que en estas zonas se denuncie menos de lo que ocurre, por desconfianza o por dificultad de acceso a los canales de denuncia. En ambos casos, las estadísticas de denuncias por sí solas no alcanzan para decir qué tan segura es una zona.

3.6 ¿Qué genera más miedo en la ciudadanía: el hurto o el deterioro del entorno por la cercanía a ollas de microtráfico y lotes oscuros?

factores <- c(
  pct_cerca_ollas         = "% cerca de ollas",
  pct_cerca_lotes_oscuros = "% cerca de lotes oscuros",
  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.55) +
  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.6, 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 los lotes oscuros",
       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 es mayor en las UPZ donde más viviendas tienen ollas de microtráfico cerca (0,67) y, en menor medida, lotes oscuros (0,35). En cambio, es menor donde hay más hurto (−0,39). Es decir, las zonas con más robos denunciados no son las que más miedo reportan.

El miedo de los bogotanos parece responder más a su entorno que al hurto denunciado. Esto ayuda a entender por qué muchas UPZ con pocas denuncias de hurto se sienten inseguras: lo que preocupa a la gente no es solo que le roben, sino vivir junto a espacios deteriorados y economías ilegales. Reducir la percepción de inseguridad, entonces, no depende solo de bajar el hurto, sino también de intervenir el entorno con mejor iluminación, recuperación de lotes y control del microtráfico.

Sin embargo, se trata de asociaciones entre territorios y no de causas. Además, el signo negativo del hurto podría reflejar que en las zonas de mayores ingresos se denuncia más, no que el hurto proteja del miedo.

3.7 ¿Cuáles son las10 UPZ con mayor porcentaje de viviendas cercanas a lotes baldíos u oscuros, y en cuál de ellas la percepción de inseguridad supera el 90 %?

tabla_lotes <- datos_f %>%
  slice_max(pct_cerca_lotes_oscuros, n = 10)

fila_90 <- which(tabla_lotes$pct_percibe_inseguridad > 90)

tabla_lotes %>%
  mutate(percepcion = format(round(pct_percibe_inseguridad, 1), nsmall = 1, decimal.mark = ","),
         percepcion = ifelse(pct_percibe_inseguridad > 90,
                             paste0("<span style='color:#A6243D'>", percepcion, "</span>",
                                    " <span style='color:#A6243D; font-size:12px'>· supera 90 %</span>"),
                             percepcion)) %>%
  transmute(UPZ = upz_nombre, Localidad = localidad,
            `% viviendas cerca de lotes oscuros` = format(round(pct_cerca_lotes_oscuros, 1), nsmall = 1, decimal.mark = ","),
            `% percibe inseguridad` = percepcion) %>%
  kbl(escape = FALSE) %>%
  kable_styling(bootstrap_options = c("hover", "condensed"), full_width = TRUE) %>%
  row_spec(0, bold = TRUE, color = "white", background = vino) %>%
  row_spec(fila_90, bold = TRUE, background = "#F8E9EC",
           extra_css = "border-left: 5px solid #A6243D;")
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 · supera 90 %
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

Vivir cerca de lotes baldíos u oscuros no basta para explicar el miedo: Zona Franca, en Fontibón, tiene la mayor proporción de viviendas expuestas (59,8 %) y solo el 44,9 % de sus habitantes percibe inseguridad, y algo parecido ocurre con las otras dos UPZ de Fontibón de la lista. En cambio, Corabastos, en Kennedy, con una exposición casi idéntica a la de Tintal Sur (48,9 %), es la única de las diez donde la percepción supera el 90 % (92,1 %).

Esto concuerda con lo que muestra el gráfico anterior, donde los lotes oscuros tienen una correlación débil con la percepción (0,35) frente a las ollas de microtráfico (0,67): el entorno físico importa, pero no actúa solo. Son asociaciones entre territorios, no causas.

3.8 ¿Tener un CAI cerca se asocia con mayor percepción de seguridad en la zona?

datos_f %>%
  mutate(distancia = cut(min_cai_policia, breaks = c(-Inf, 15, 20, Inf), right = FALSE,
                         labels = c("Cerca\n(menos de 15 min)", "Media\n(15 a 20 min)", "Lejos\n(20 min o más)")),
         destacar = distancia == "Cerca\n(menos de 15 min)") %>%
  group_by(distancia, destacar) %>%
  summarise(upz = n(), percepcion = median(pct_percibe_inseguridad), .groups = "drop") %>%
  ggplot(aes(x = distancia, y = percepcion, fill = destacar)) +
  geom_col(width = 0.6) +
  geom_text(aes(label = paste0(round(percepcion), " %"), color = destacar),
            vjust = -0.5, size = 4.2, fontface = "bold") +
  geom_text(aes(y = 3, label = paste0(upz, " UPZ"),
                color = ifelse(destacar, "blanco", "gris_texto")),
            vjust = 0, size = 3.2) +
  scale_fill_manual(values = c(`TRUE` = vino, `FALSE` = gris), guide = "none") +
  scale_color_manual(values = c(`TRUE` = vino, `FALSE` = "grey55",
                                blanco = "white", gris_texto = "grey30"), guide = "none") +
  scale_y_continuous(limits = c(0, 100), labels = function(x) paste0(x, " %")) +
  labs(title = "Tener un CAI más cerca no se asocia con sentirse más seguro",
       subtitle = "Mediana del % que percibe inseguridad según los minutos caminando hasta el CAI · 101 UPZ",
       x = "Minutos caminando hasta el CAI", y = "% que percibe inseguridad", caption = fuente) +
  tema_clase +
  theme(panel.grid.major.x = element_blank())

cor(datos_f$min_cai_policia, datos_f$pct_percibe_inseguridad, method = "spearman")
## [1] 0.01459595

Tener un CAI cerca no se asocia con sentirse más seguro: las UPZ con un CAI a menos de 15 minutos caminando tienen una mediana de 62 % de habitantes que perciben inseguridad, más que las que lo tienen a 20 minutos o más (55 %), y las que están entre 15 y 20 minutos son las que más inseguridad perciben (71 %). Esto no significa que los CAI no sirvan: podría ser que se hayan ubicado donde ya había más problemas, y el tiempo caminando no mide cuánto patrullaje o capacidad de respuesta tiene cada uno. Pero sí indica que la cercanía de la policía, por sí sola, no basta para que la gente se sienta segura, algo coherente con que el miedo se asocie más con el entorno, como las ollas de microtráfico, que con los delitos denunciados.

4. Conclusiones y Limitaciones

4.1 Conclusiones

  • Cada estrato enfrenta un problema distinto en las denuncias. La violencia intrafamiliar denunciada pesa más en los estratos 1–2, aunque también hay casos críticos en los estratos medios.

  • El hurto denunciado se concentra en los estratos medios y altos. Las UPZ de estratos 5–6 y 3–4 tienen casi tres veces más denuncias de hurto que las de estratos 1–2.

  • Los dos delitos ocupan territorios distintos. El hurto se concentra en el centro, el norte y el occidente, y la violencia intrafamiliar en el sur y el suroccidente; solo 16 de 101 UPZ tienen ambos altos.

  • Las ollas de microtráfico acompañan a los homicidios. La relación es clara (0,64), aunque con excepciones: hay UPZ con bastante exposición y pocos homicidios.

  • Menos hurto no significa sentirse más seguro. Siete de las diez UPZ con menos denuncias de hurto se sienten más inseguras que la UPZ típica.

  • El miedo sigue al entorno, no al hurto. La percepción se asocia con las ollas (0,67) y, más débilmente, con los lotes oscuros (0,35), mientras que con las denuncias de hurto la relación es negativa (−0,39).

  • Los lotes oscuros pesan, pero no determinan. Zona Franca tiene la mayor exposición y una percepción baja; solo Corabastos supera el 90 %, y además tiene muchas ollas cerca.

  • La cercanía de un CAI no se asocia con mejor percepción. Las UPZ con un CAI a menos de 15 minutos caminando no se sienten más seguras que las demás (correlación de 0,01).

En síntesis, los lugares donde más se denuncia no son los mismos donde más se siente miedo. En los estratos medios y altos predomina el hurto en la calle; en los estratos bajos, la violencia intrafamiliar, los homicidios ligados al microtráfico y una mayor percepción de inseguridad, aunque se denuncie menos hurto. El miedo de la gente se relaciona más con el deterioro de su entorno, como las ollas de microtráfico y los lotes oscuros, que con los delitos denunciados o con la cercanía de la policía. Por eso, medir la seguridad solo con denuncias deja por fuera a las zonas donde la gente se siente más insegura, y las respuestas deben pensarse según cada territorio.

4.2 Limitaciones

  • Denuncia no es ocurrencia. Hurto, violencia intrafamiliar y homicidios se miden con delitos denunciados. El subregistro suele variar por delito y por territorio: es mayor en hurto y violencia intrafamiliar, y menor en homicidios. Una tasa baja puede significar poca denuncia y no poca victimización.
  • Percepción no es riesgo. Es una sensación declarada en una encuesta. No sabemos si responde a otros delitos, a experiencias previas o a la apariencia del entorno.
  • Las zonas con alta afluencia de personas. En UPZ con pocos residentes y mucha población de paso, como Sagrado Corazón o Las Nieves, la tasa se calcula solo con quienes viven allí, aunque los delitos también afectan a quienes trabajan, estudian o visitan la zona. Por eso la tasa refleja tanto la actividad del lugar como el riesgo de sus habitantes. Excluimos las 11 UPZ con menos de 10.000 habitantes, como el Aeropuerto El Dorado, pero sería interesante contrastar estas tasas con datos de población flotante, que la base no incluye.
  • Las ollas y los CAI son aproximaciones. Medimos el % de viviendas cerca de una olla y los minutos caminando al CAI, no el volumen de microtráfico, el patrullaje ni la calidad del servicio.
  • Periodo corto y fuentes de años distintos. Los delitos cubren solo enero a julio de 2023, y la encuesta es de 2021.
  • Datos agrupados de la encuesta. En 32 UPZ la Encuesta Multipropósito reporta valores compartidos con UPZ vecinas, por lo que su percepción, estrato y entorno no son exactamente los de cada UPZ.