La tenencia de un carro particular constituye una característica relevante para analizar las condiciones económicas y el acceso a alternativas de movilidad de los hogares. Disponer de este bien puede facilitar determinados desplazamientos y ofrecer mayor autonomía; sin embargo, su adquisición y mantenimiento requieren recursos económicos, por lo que su tenencia puede presentar diferencias según las características socioeconómicas y territoriales de los hogares.
La Encuesta Nacional de Calidad de Vida (ECV) 2023 del Departamento Administrativo Nacional de Estadística (DANE) proporciona información sobre las condiciones de vida de los hogares colombianos, incluida la tenencia de bienes, el acceso a servicios y diversas características socioeconómicas (DANE, 2024a). En la base analizada para este trabajo, la proporción de hogares con automóvil particular es del 14,4 % (DANE, 2024b) al aplicar el factor de expansión, mientras que la proporción sin ponderar en la muestra es del 8,5 %. Estas cifras corresponden a procedimientos de cálculo diferentes y, por tanto, deben interpretarse distinguiendo la estimación ponderada de la frecuencia observada en la muestra.
En estudios previos, como el de BBVA Research (2018), que en su informe Situación Automotriz Colombia 2018 estima un modelo logit con datos de la Gran Encuesta Integrada de Hogares (GEIH) de 13 ciudades e identifica factores asociados con la tenencia de carro, entre ellos el nivel de ingresos y de riqueza del hogar, el sexo y la situación laboral del jefe, la composición del hogar y la propiedad de la vivienda; además, reporta diferencias de tenencia entre ciudades. Estos antecedentes permiten plantear que la tenencia de carro puede relacionarse con múltiples características económicas, sociodemográficas y territoriales.
A partir de estos antecedentes, el presente trabajo considera variables relacionadas con los ingresos, la educación, el tamaño del hogar y el territorio, así como la edad y el sexo del jefe del hogar y algunas percepciones sobre la situación económica familiar.
Problema. Aunque existen antecedentes que relacionan la tenencia de automóviles con características económicas, sociodemográficas y territoriales de los hogares, resulta pertinente analizar estas asociaciones a partir de una misma base de hogares colombianos y evaluar qué tan bien permiten clasificar a los hogares entre aquellos que tienen automóvil particular y aquellos que no. Esta clasificación puede contribuir a identificar diferencias en el acceso a la movilidad privada y proporcionar información de interés para el análisis de las brechas socioeconómicas y territoriales.
Se plantea entonces la siguiente pregunta de investigación:
Pregunta de investigación. ¿Qué características económicas, sociodemográficas y del entorno están asociadas con que un hogar colombiano tenga un carro particular, y qué tan bien permiten esas características clasificar a los hogares según tengan o no carro?
En este contexto, la clasificación supervisada ofrece herramientas para estudiar la tenencia de automóvil a partir de las características observadas. La regresión logística permite analizar la asociación entre las variables explicativas y la probabilidad de que un hogar pertenezca a la categoría de hogares con automóvil; el algoritmo de vecinos más cercanos (KNN), por su parte, permite evaluar una alternativa de clasificación basada en la similitud entre observaciones.
Objetivo general. Identificar los factores asociados con la tenencia de carro particular en los hogares colombianos mediante una regresión logística, y comparar su capacidad de clasificación con la de un modelo KNN.
Objetivos específicos.
El informe presenta la metodología, los resultados descriptivos mediante tablas y gráficos, los resultados de los modelos y las conclusiones. Además, el análisis utiliza información de 2023 y tiene un alcance observacional. Por tanto, los resultados permiten describir asociaciones y evaluar el desempeño de los modelos, pero no establecer relaciones causales. Asimismo, dado que los modelos se estiman sin ponderación, sus coeficientes y métricas de clasificación deben interpretarse en relación con los datos utilizados para el ajuste y la evaluación, sin asumir que representan directamente estimaciones para toda la población colombiana.
| Campo | Detalle |
|---|---|
| Entidad que publica | Departamento Administrativo Nacional de Estadística (DANE), Dirección de Metodología y Producción Estadística (DIMPE) |
| Nombre del conjunto de datos | Encuesta Nacional de Calidad de Vida — ECV — 2023 |
| Enlace | microdatos.dane.gov.co/index.php/catalog/827 |
| Archivos específicos utilizados |
Condiciones de vida del hogar y tenencia de bienes; Características y
composición del hogar; Educación; Fuerza de trabajo; Variables de diseño
muestral (integradas en base_integrada_ECV2023.csv)
|
| Variable dependiente |
P1077S15: El hogar posee carro particular (1 = sí; 0 = no)
|
Los datos provienen de la Encuesta Nacional de Calidad de Vida (ECV) 2023 del DANE, una operación estadística de cobertura nacional que caracteriza las condiciones de vida y el bienestar de los hogares: vivienda, servicios públicos, composición del hogar, educación, fuerza de trabajo, uso de tecnologías de información y tenencia de bienes.
Para construir la base de análisis, se integraron cinco tablas de microdatos de la encuesta. La variable dependiente corresponde a la pregunta P1077S15, que identifica si el hogar posee un carro particular. La selección de esta fuente permite estudiar la relación entre características económicas, sociodemográficas y territoriales y la tenencia de este bien.
Justificación de la base. Se seleccionó una base nueva, distinta de la del Taller 1, porque cumple lo que requiere el taller:
Como verificación, la proporción ponderada de hogares con carro obtenida (14,4 %) coincide con la publicada por el DANE (2024b).
Año de referencia. Como el propósito es identificar características asociadas a la tenencia de carro y comparar dos modelos de clasificación, y no estimar la tenencia actual, los resultados deben leerse como una descripción de 2023: el DANE publicó después la ECV 2024 (DANE, 2025).
La unidad de análisis es el hogar encuestado en la ECV 2023 (periodo
de referencia: 2023). Cada fila de la base final es un hogar,
identificado por la combinación de Directorio y
Hogar; la base tiene 86.405 hogares, de los cuales 7.339
tienen carro particular. Los resultados corresponden a la muestra y no a
toda la población colombiana; los porcentajes de tenencia por categoría
se calcularon con el factor de expansión de la encuesta (estimación
nacional), las estadísticas de las variables cuantitativas describen la
muestra sin ponderar y los modelos se ajustaron sin ponderar (véase
Supuestos y robustez del logit).
La ECV entrega la información en varias tablas separadas. Se usaron cinco, y cada una aporta variables distintas:
| Tabla de la ECV 2023 | Qué se tomó de ella | Variable en la base final |
|---|---|---|
| Condiciones de vida del hogar y tenencia de bienes | Si el hogar tiene carro particular (P1077S15), si sus
ingresos alcanzan para los gastos mínimos (P9090), si se
considera pobre (P5230), si tiene internet
(P1075) y el factor de expansión |
Tiene_carro, Capacidad_ingresos,
Se_considera_pobre, Tiene_internet,
Factor_expansion |
| Características y composición del hogar | Número de personas del hogar, y sexo (P6020) y edad
(P6040) del jefe(a) |
Tamano_hogar, Sexo_jefe,
Edad_jefe |
| Educación | Nivel educativo más alto alcanzado por el jefe(a)
(P8587) |
Nivel_educativo |
| Fuerza de trabajo | Ingresos laborales de cada persona (P8624 y
P6750) |
Ingreso_laboral_hogar |
| Variables de diseño muestral | Tipo de bloque muestral y municipio | Ciudad_capital, Region |
Algunas tablas de la ECV contienen una observación por persona, mientras que el presente estudio analiza la tenencia de carros particulares a nivel del hogar. Por esta razón, fue necesario resumir la información individual y convertirla en variables representativas de cada hogar.
El proceso se realizó de la siguiente manera:
P8624) y como
independientes (P6750). Los códigos 98 y 99,
correspondientes a respuestas de no sabe o no informa según la
codificación utilizada, se trataron como datos faltantes.Para integrar las fuentes de información, se utilizó una llave que
permite identificar de manera única cada hogar. Esta se construyó
mediante la combinación del identificador de la vivienda
(DIRECTORIO) y el número del hogar dentro de
ella, que corresponden, en la base final, a las columnas
Directorio y Hogar.
Ese número tiene un nombre distinto según la tabla:
SECUENCIA_P. En la tabla de tenencia de bienes se llama
ORDEN. En esta última tabla, SECUENCIA_P toma
el valor 1 en todos los registros, por lo que no permite distinguir los
hogares.Una vez armonizados los identificadores, se integraron las tablas y se verificó que la base resultante tuviera una sola observación por hogar y no presentara llaves duplicadas. Esta base se utilizó como punto de partida para el proceso de limpieza y la estimación de los modelos.
Una vez integrada la información de las cinco tablas, se realizaron verificaciones de consistencia y se prepararon las variables para el análisis. Se revisó la base para detectar datos faltantes, valores extremos y distribuciones asimétricas. A partir de esa revisión se prepararon tres grupos de variables:
| En la base integrada | En el análisis | Qué se hizo |
|---|---|---|
Ingreso_laboral_hogar |
Log_ingreso, Sin_ingreso_laboral |
Los ingresos faltantes y los valores iguales o inferiores a cero no se utilizaron directamente en la transformación logarítmica. Se creó un indicador para identificar los hogares sin un ingreso laboral reportado. Para los hogares sin un valor de logaritmo disponible, se imputó el promedio del logaritmo de los ingresos laborales positivos. |
Nivel_educativo |
Educacion_jefe |
Se agrupó en cinco niveles (Ninguno/preescolar, Primaria, Secundaria, Media y Superior) y se conservaron los registros sin información en una categoría denominada “Sin dato”, en lugar de excluir esos hogares del análisis. |
Ciudad_capital |
Zona |
Se etiquetó como “Ciudad capital” o “Resto del país” |
La tabla y los puntos que siguen al código detallan los datos faltantes y las demás decisiones.
ruta <- ifelse(file.exists("Datos/base_integrada_ECV2023.csv"),
"Datos/base_integrada_ECV2023.csv", "base_integrada_ECV2023.csv")
d <- read.csv(ruta, sep = ";", dec = ".",
fileEncoding = "UTF-8", stringsAsFactors = FALSE)
n_base <- ncol(d) # columnas de la base integrada, antes de las transformaciones
ing_pos <- ifelse(!is.na(d$Ingreso_laboral_hogar) & d$Ingreso_laboral_hogar > 0,
d$Ingreso_laboral_hogar, NA)
li <- log(ing_pos)
d$Log_ingreso <- ifelse(is.na(li), mean(li, na.rm = TRUE), li)
d$Sin_ingreso_laboral <- as.integer(is.na(li))
edu <- as.character(cut(d$Nivel_educativo, breaks = c(0, 2, 3, 4, 5, 13),
labels = c("Ninguno/preescolar", "Primaria", "Secundaria",
"Media", "Superior")))
edu[is.na(edu)] <- "Sin dato"
reg_ref <- c("Antioquia", "Bogotá", "Caribe", "Central", "Orinoquía-Amazonía",
"Oriental", "Pacífica", "San Andrés", "Valle del Cauca")
d <- d %>%
mutate(
Carro_factor = factor(Tiene_carro, levels = c(0, 1), labels = c("Sin carro", "Con carro")),
Capacidad_ingresos = relevel(factor(Capacidad_ingresos, levels = 1:3,
labels = c("No alcanza", "Solo cubre gastos mínimos",
"Cubre más que gastos mínimos")),
ref = "Solo cubre gastos mínimos"),
Educacion_jefe = factor(edu, levels = c("Ninguno/preescolar", "Primaria", "Secundaria",
"Media", "Superior", "Sin dato")),
Sexo_jefe = factor(Sexo_jefe, levels = c(2, 1), labels = c("Mujer", "Hombre")),
Se_considera_pobre = factor(Se_considera_pobre, levels = c(2, 1), labels = c("No", "Sí")),
Tiene_internet = factor(Tiene_internet, levels = c(2, 1), labels = c("No", "Sí")),
Zona = factor(Ciudad_capital, levels = c(0, 1),
labels = c("Resto del país", "Ciudad capital")),
Region = factor(Region, levels = reg_ref),
Tamano_grupo = cut(Tamano_hogar, breaks = c(0, 1, 2, 3, 4, 5, Inf),
labels = c("1", "2", "3", "4", "5", "6 o más"))
)
if (anyNA(d$Region)) stop("Hay hogares con región sin categoría en reg_ref: revise los nombres (tildes).")
cat("Hogares:", nrow(d), "| Variables:", ncol(d))
## Hogares: 86405 | Variables: 20
Después de estas transformaciones la base de análisis conserva los
86.405 hogares: ninguno se eliminó, porque los datos faltantes se
imputaron o se dejaron como categoría propia. Las 20 columnas son las 15
de la base integrada más cinco que se agregaron para el análisis:
Log_ingreso, Educacion_jefe y
Zona (descritas arriba), Tamano_grupo (el
tamaño del hogar agrupado en 1, 2, 3, 4, 5 y 6 o más personas, usado en
los gráficos) y Carro_factor (la variable dependiente con
las etiquetas “Sin carro” y “Con carro”).
asimetria <- function(x) { x <- x[!is.na(x)]; mean((x - mean(x))^3) / sd(x)^3 }
n_cero <- sum(d$Ingreso_laboral_hogar == 0, na.rm = TRUE)
n_na_i <- sum(is.na(d$Ingreso_laboral_hogar))
n_na_e <- sum(is.na(d$Nivel_educativo))
ing_p <- d$Ingreso_laboral_hogar[!is.na(d$Ingreso_laboral_hogar) & d$Ingreso_laboral_hogar > 0]
tab_cal <- data.frame(
Variable = c("Ingreso laboral del hogar", "Ingreso laboral del hogar (valor 0)", "Nivel educativo del jefe"),
Hogares = c(n_na_i, n_cero, n_na_e),
Porcentaje = c(100 * n_na_i / nrow(d), 100 * n_cero / nrow(d), 100 * n_na_e / nrow(d)),
Tratamiento = c("Se imputa el promedio del log y se marca con un indicador",
"Se trata como \"sin ingreso reportado\" (igual que el faltante)",
"Se deja como categoría \"Sin dato\"")
)
kable(tab_cal, digits = 1, format.args = list(big.mark = ".", decimal.mark = ","),
caption = "Tabla 4. Datos faltantes y su tratamiento")
| Variable | Hogares | Porcentaje | Tratamiento |
|---|---|---|---|
| Ingreso laboral del hogar | 17.123 | 19,8 | Se imputa el promedio del log y se marca con un indicador |
| Ingreso laboral del hogar (valor 0) | 758 | 0,9 | Se trata como “sin ingreso reportado” (igual que el faltante) |
| Nivel educativo del jefe | 1.955 | 2,3 | Se deja como categoría “Sin dato” |
n_otras <- sum(colSums(is.na(d[, c("Tiene_carro", "Capacidad_ingresos", "Tamano_hogar", "Edad_jefe",
"Sexo_jefe", "Se_considera_pobre", "Tiene_internet", "Zona", "Region")])) > 0)
Las demás variables del modelo no tienen datos faltantes.
La categoría “Sin dato” agrupa a los 1.955 hogares (2,3 % de la muestra) cuyo jefe no tiene nivel educativo registrado en la ECV; no incluye códigos de “no sabe / no informa”. Su tasa de tenencia de carro (18,3 % ponderada) es mayor que la de los niveles Ninguno, Primaria, Secundaria y Media, de modo que no es un grupo aleatorio: por eso se conservó como categoría propia en lugar de eliminarlo o imputarlo. Sus jefes son más jóvenes que el promedio, y su OR en el logit debe leerse como el de un grupo con información incompleta, no como un nivel educativo.
Transformación logarítmica: El ingreso laboral es muy asimétrico (asimetría = 39,3) y con el logaritmo pasa a -0,24, casi simétrico; por eso se usa en el modelo. El tamaño del hogar (asimetría 1,1) y la edad del jefe (0,2) no la requieren.
Valores atípicos. Hay 109 hogares con jefe menor de 18 años (de 13 a 17 años), 143 con 10 o más personas (hasta 24) y 15 con ingreso laboral superior a 50 millones de pesos (cerca de 4,9 veces el percentil 99, que es de 10.157.700 pesos). Son valores posibles y no códigos de no respuesta, y no hay un criterio objetivo para descartarlos, por lo que se conservaron. Su influencia en el logit se evalúa en la sección Supuestos y robustez del logit.
La variable dependiente es Tiene_carro,
que toma el valor 1 si el hogar posee carro particular y 0 en caso
contrario. Se seleccionaron diez variables independientes, organizadas
en tres dimensiones: económica, sociodemográfica y del entorno (el
ingreso laboral se representa con dos columnas del modelo,
Log_ingreso y Sin_ingreso_laboral).
| Dimensión | Variable | Origen ECV | Tipo | Justificación |
|---|---|---|---|---|
| Económica | Log_ingreso |
P8624, P6750 |
Numérica | Logaritmo del ingreso laboral del hogar; refleja la capacidad económica para adquirir y mantener un vehículo. |
| Económica | Sin_ingreso_laboral |
P8624, P6750 |
Indicadora | Señala hogares sin ingreso laboral reportado (dato faltante o igual a cero) y permite conservarlos en el modelo. |
| Económica | Capacidad_ingresos |
P9090 |
Categórica (3) | Percepción de si los ingresos cubren los gastos mínimos; aproxima la holgura económica percibida por el hogar. |
| Económica | Se_considera_pobre |
P5230 |
Categórica (2) | Captura la percepción del hogar sobre su condición económica. Es subjetiva y podría estar influida por la propia tenencia de carro, por lo que se lee como asociación. |
| Económica | Tiene_internet |
P1075 |
Categórica (2) | Aproxima el acceso a bienes y servicios del hogar. |
| Sociodemográfica | Educacion_jefe |
P8587 |
Categórica (6) | Nivel educativo del jefe: se asocia con ingresos permanentes y con patrimonio. |
| Sociodemográfica | Tamano_hogar |
Composición del hogar | Numérica | Más integrantes pueden aumentar la necesidad de transporte, pero también podrían restringir el presupuesto. |
| Sociodemográfica | Edad_jefe |
P6040 |
Numérica | Representa la etapa del ciclo de vida y la posible acumulación de recursos. |
| Sociodemográfica | Sexo_jefe |
P6020 |
Categórica (2) | Permite explorar brechas de género en el control de recursos del hogar. |
| Entorno | Zona |
Diseño muestral (BLOQUE) |
Categórica (2) | Captura diferencias entre ciudades capitales y el resto del país en acceso a movilidad e ingresos (ver nota). |
| Entorno | Region |
Diseño muestral (MPIO) |
Categórica (9) | Captura diferencias territoriales entre las regiones DANE en acceso a movilidad, ingresos y condiciones de vida. |
Nota sobre la variable
Zona. La ECV publicada no incluye aquí la clasificación oficial cabecera / centro poblado / rural disperso. Se usó el bloque muestral: los bloques “A” corresponden a municipios capitales y los “R” al resto del país (que mezcla cabeceras de municipios pequeños y áreas rurales). Por esoZonano debe interpretarse como “urbano vs. rural”. La variable se construyó a partir deCiudad_capital, el nombre que tiene en la tabla de diseño muestral.
Las diez variables entran al modelo como once términos (el ingreso
laboral aporta dos: Log_ingreso y
Sin_ingreso_laboral), que generan 23 coeficientes más el
intercepto, una vez codificadas las variables categóricas.
Se emplearon dos modelos de aprendizaje supervisado para clasificar los hogares según la tenencia de carro: regresión logística y K vecinos más cercanos (KNN).
Aprendizaje supervisado. Es un enfoque en el que se entrena un modelo con hogares cuya variable de respuesta (tener o no carro) es conocida. Después, el modelo se evalúa con hogares que no se usaron en el entrenamiento, para medir su capacidad de clasificación, y una vez validado puede aplicarse a hogares nuevos. Como la variable de respuesta es binaria, se trata de un problema de clasificación.
Regresión logística (logit). Modela el logaritmo de
las odds de tener carro como una combinación lineal de las
variables explicativas (Hosmer et al., 2013). Al exponenciar cada
coeficiente se obtiene un odds ratio (OR): un OR mayor que 1
indica mayores odds de tener carro y un OR menor que 1, menores
odds, manteniendo constantes las demás variables. Se usó un
modelo binomial con la función glm, porque el objetivo
incluye interpretar los OR.
KNN. El método KNN clasifica cada hogar según la clase predominante entre sus k vecinos más cercanos del conjunto de entrenamiento (Hastie et al., 2009; James et al., 2021). Como la distancia euclidiana depende de la escala de las variables, estas se estandarizaron con la media y la desviación estándar del conjunto de entrenamiento, y las categóricas se transformaron en variables indicadoras. El valor de k se seleccionó con el AUC en un conjunto de validación.
Matriz de confusión y métricas. La matriz de confusión cruza la clase real con la predicha, y de ella salen todas las métricas:
| Realmente con carro | Realmente sin carro | |
|---|---|---|
| Predicho con carro | Verdaderos positivos (VP) | Falsos positivos (FP) |
| Predicho sin carro | Falsos negativos (FN) | Verdaderos negativos (VN) |
| Métrica | Fórmula | Qué responde |
|---|---|---|
| Exactitud | \(\frac{VP+VN}{VP+VN+FP+FN}\) | ¿Qué porcentaje de todos los hogares clasificó bien? |
| Sensibilidad | \(\frac{VP}{VP+FN}\) | De los hogares que sí tienen carro, ¿cuántos detectó? |
| Especificidad | \(\frac{VN}{VN+FP}\) | De los hogares que no tienen carro, ¿cuántos identificó bien? |
| Precisión | \(\frac{VP}{VP+FP}\) | De los hogares que predijo con carro, ¿cuántos realmente lo tienen? |
| F1 | \(\frac{2\,P\,S}{P+S}\) | Resumen que combina la precisión (P) y la sensibilidad (S) |
El Kappa mide el acuerdo entre las clases predichas y las observadas descontando el acuerdo esperado por azar, y la exactitud balanceada es el promedio de la sensibilidad y la especificidad; ambas son más informativas que la exactitud cuando las clases están desbalanceadas.
ROC y AUC. La exactitud depende del umbral de probabilidad (0,5 por defecto). La curva ROC calcula la sensibilidad y la especificidad para todos los umbrales, y el AUC (área bajo la curva) resume qué tan bien el modelo separa a los dos grupos: 0,5 equivale al azar y 1 a una separación perfecta (Fawcett, 2006).
Validación cruzada. Se divide el entrenamiento en cinco partes (folds); cada una se usa como prueba de un modelo entrenado con las demás, y se promedia el resultado. Sirve para comparar modelos o elegir parámetros sin usar el conjunto de prueba.
Diseño de evaluación. La base se dividió en 70 % para entrenamiento y 30 % para prueba, con una partición estratificada según la variable dependiente (semilla 123), de modo que el desempeño se evalúe en hogares no usados durante el ajuste. Como los hogares con carro son minoritarios, la exactitud por sí sola puede ser engañosa; por eso los modelos se evaluaron con el umbral tradicional de 0,5 y con un umbral igual a la proporción de hogares con carro en el entrenamiento, y se reportaron exactitud, sensibilidad, especificidad, precisión, F1, Kappa, exactitud balanceada y AUC.
Como verificación adicional, ambos modelos se compararon mediante validación cruzada de cinco particiones comunes, usando el ROC como métrica; esta validación se hizo con una submuestra de 20.000 hogares del entrenamiento, por lo que sus resultados no son idénticos a los de los modelos principales.
Finalmente, se verificaron algunos supuestos y la robustez del logit (ponderación por factores de expansión, relación no lineal con la edad y valores atípicos), que se describen en la sección Supuestos y robustez del logit.
Elección del umbral de prevalencia. Además del corte convencional de 0,5, se evaluó un umbral igual a la proporción de hogares con carro en el conjunto de entrenamiento: 5.137 de 60.483 hogares, es decir, 0,0849 (aproximadamente 0,085). Esta elección se justifica por cuatro razones. Primero, con una clase minoritaria muy pocos hogares alcanzan una probabilidad de 0,5: con ese corte solo 968 de los 25.922 hogares de prueba (3,7 %) se clasifican con carro en el logit, y su sensibilidad es de 30,8 %. Segundo, en un logit con intercepto la probabilidad media predicha en el entrenamiento coincide con la proporción observada, por lo que usar la prevalencia como corte equivale a clasificar como «con carro» a los hogares cuya probabilidad estimada supera la de un hogar promedio. En el KNN, cuya probabilidad es la proporción de vecinos con carro, el corte de 0,0849 con k = 41 equivale a exigir al menos 4 vecinos con carro (4/41 = 0,098; 3/41 = 0,073). Tercero, el valor se calcula solo con el entrenamiento y se fija antes de evaluar en la muestra de prueba, por lo que no hay fuga de información, y ambos modelos se comparan con el mismo corte. Cuarto, es una regla simple y reproducible. No es un óptimo: otros criterios (índice de Youden, máximo F1 o costos de error asimétricos) darían cortes distintos. Como salvedad, dado que los modelos no se ponderan, el umbral refleja la prevalencia muestral (8,5 %) y no la nacional (14,4 %).
Herramientas. El análisis se realizó en R (R Core Team) con los paquetes ggplot2 (Wickham, 2016), plotly (Sievert, 2020), pROC (Robin et al., 2011), FNN (Beygelzimer et al.) y caret (Kuhn, 2008); el flujo de entrenamiento, prueba y evaluación sigue el capítulo de aprendizaje supervisado de Paredes (2024).
Esta sección presenta las tablas descriptivas de la base y de las variables; los gráficos correspondientes están en la sección siguiente, Análisis gráfico de la tenencia de carro, organizados por las mismas dimensiones. Los porcentajes de tenencia por categoría se calculan con el factor de expansión (estimación nacional) y también se muestra el porcentaje sin ponderar de la muestra; las estadísticas de las variables cuantitativas describen la muestra sin ponderar.
La base de análisis tiene 86.405 hogares
(observaciones), cada uno con la variable dependiente
(Tiene_carro) y las variables independientes. La tabla
permite explorarla: se puede filtrar por cualquier columna y cambiar el
número de filas. El ingreso laboral se muestra en pesos y el logaritmo
es la versión que entra a los modelos (en los hogares sin ingreso
reportado ese logaritmo está imputado, y la columna “Sin ingreso
laboral” los identifica). Por tamaño, se expone una muestra aleatoria de
2.000 hogares.
set.seed(2025)
vista <- d %>%
transmute(
`Tiene carro` = Carro_factor,
`Ingreso laboral` = Ingreso_laboral_hogar,
`Log. ingreso` = Log_ingreso,
`Sin ingreso laboral` = factor(Sin_ingreso_laboral, levels = c(0, 1), labels = c("No", "Sí")),
`Capacidad de ingresos` = Capacidad_ingresos,
`Se considera pobre` = Se_considera_pobre,
`Educación del jefe` = Educacion_jefe,
`Tamaño del hogar` = Tamano_hogar,
`Edad del jefe` = Edad_jefe,
`Sexo del jefe` = Sexo_jefe,
`Internet` = Tiene_internet,
`Zona` = Zona,
`Región` = Region
) %>%
slice_sample(n = n_mostrar)
datatable(
vista,
rownames = FALSE,
filter = "top",
class = "stripe hover tabla-base",
caption = paste0("Tabla 8. Base de datos de hogares (muestra aleatoria de ", mil(n_mostrar), " hogares)"),
options = list(
pageLength = 5,
lengthMenu = c(5, 10, 25, 50),
autoWidth = FALSE,
columnDefs = list(list(className = "dt-center", targets = "_all")),
language = list(
thousands = ".",
search = "Buscar:",
lengthMenu = "Mostrar _MENU_ registros",
info = "Mostrando _START_ a _END_ de _TOTAL_ hogares",
infoEmpty = "Sin resultados",
infoFiltered = "(filtrado de _MAX_ hogares)",
zeroRecords = "No se encontraron hogares con esos filtros",
paginate = list(`next` = "Siguiente", previous = "Anterior")
)
)
) %>%
formatCurrency("Ingreso laboral", currency = "$", interval = 3,
mark = ".", dec.mark = ",", digits = 0) %>%
formatRound("Log. ingreso", digits = 2, mark = ".", dec.mark = ",")
prev <- data.frame(
Medida = c("Hogares en la muestra", "Hogares con carro (muestra)",
"Proporción con carro, sin ponderar", "Proporción con carro, ponderada (factor de expansión)"),
Valor = c(format(nrow(d), big.mark = ".", decimal.mark = ","), format(sum(d$Tiene_carro), big.mark = "."),
pct(mean(d$Tiene_carro)), pct(weighted.mean(d$Tiene_carro, d$Factor_expansion)))
)
kable(prev, align = c("l", "r"),
caption = "Tabla 9. Distribución de la variable dependiente (tenencia de carro)")
| Medida | Valor |
|---|---|
| Hogares en la muestra | 86.405 |
| Hogares con carro (muestra) | 7.339 |
| Proporción con carro, sin ponderar | 8,5 % |
| Proporción con carro, ponderada (factor de expansión) | 14,4 % |
De los 86.405 hogares de la muestra, 7.339 (8,5 %) tienen carro particular. Al aplicar los factores de expansión, que corrigen las distintas probabilidades de selección del diseño muestral, la estimación nacional sube a 14,4 %. En ambos casos la tenencia es minoritaria, por lo que las clases están desbalanceadas: en la muestra, el 91,5 % de los hogares no tiene carro, y un modelo que clasificara todos los hogares como «sin carro» tendría una exactitud de 91,5 %. Por eso la exactitud, por sí sola, no basta para evaluar un modelo y se complementa con la sensibilidad, la especificidad y el área bajo la curva ROC (AUC).
resumen <- function(x, nombre, d_media = 1, d_resto = 0) {
data.frame(Variable = nombre,
N = mil(sum(!is.na(x))),
Media = num(mean(x, na.rm = TRUE), d_media),
Mediana = num(median(x, na.rm = TRUE), d_resto),
DE = num(sd(x, na.rm = TRUE), d_media),
Mínimo = num(min(x, na.rm = TRUE), d_resto),
Máximo = num(max(x, na.rm = TRUE), d_resto))
}
tab_q <- rbind(
resumen(ing_p, "Ingreso laboral del hogar (COP, solo valores > 0)", d_media = 0),
resumen(d$Tamano_hogar, "Tamaño del hogar (personas)"),
resumen(d$Edad_jefe, "Edad del jefe (años)")
)
kable(tab_q, align = c("l", rep("r", 6)),
caption = "Tabla 10. Estadísticas descriptivas de las variables cuantitativas")
| Variable | N | Media | Mediana | DE | Mínimo | Máximo |
|---|---|---|---|---|---|---|
| Ingreso laboral del hogar (COP, solo valores > 0) | 68.524 | 1.628.082 | 1.140.000 | 3.210.361 | 6.000 | 260.000.000 |
| Tamaño del hogar (personas) | 86.405 | 2,8 | 3 | 1,5 | 1 | 24 |
| Edad del jefe (años) | 86.405 | 49,3 | 49 | 16,7 | 13 | 104 |
En la Tabla 10 destaca la marcada asimetría del ingreso laboral: la media ($1.628.082 COP) supera ampliamente a la mediana ($1.140.000 COP) debido a que unos pocos ingresos extremadamente altos (de hasta $260 millones) elevan el promedio. Esta variable cuenta con 68.524 hogares porque excluye a quienes no reportaron ingresos o tuvieron valor cero. En cambio, el tamaño del hogar (promedio de 2,8 personas) y la edad del jefe (promedio de 49,3 años) muestran distribuciones bastante centradas y simétricas, con medias casi idénticas a sus medianas.
tab_q2 <- d %>%
group_by(`Tenencia de carro` = Carro_factor) %>%
summarise(`Ingreso laboral, mediana (COP)` =
median(Ingreso_laboral_hogar[!is.na(Ingreso_laboral_hogar) & Ingreso_laboral_hogar > 0]),
`Tamaño del hogar, media` = mean(Tamano_hogar),
`Edad del jefe, media` = mean(Edad_jefe), .groups = "drop")
kable(tab_q2, digits = c(0, 0, 2, 1), format.args = list(big.mark = ".", decimal.mark = ","),
caption = "Tabla 11. Variables cuantitativas según tenencia de carro (muestra sin ponderar; ingreso solo de hogares con ingreso laboral mayor que cero)")
| Tenencia de carro | Ingreso laboral, mediana (COP) | Tamaño del hogar, media | Edad del jefe, media |
|---|---|---|---|
| Sin carro | 1.000.000 | 2,78 | 49,0 |
| Con carro | 3.004.000 | 2,83 | 52,5 |
El ingreso laboral es la variable que marca la mayor diferencia: la mediana de ingreso en los hogares con carro ($3.004.000 COP) triplica la de los hogares sin carro ($1.000.000 COP). También se observa que los jefes de hogar con vehículo son en promedio algo mayores (52,5 años frente a 49,0 años), lo que sugiere una mayor estabilidad económica acumulada a lo largo del tiempo. En cambio, el tamaño del hogar es prácticamente idéntico en ambos grupos (alrededor de 2,8 personas), por lo que no marca una distinción relevante por sí solo.
Las tablas siguen las tres dimensiones de la sección Variable dependiente y variables independientes: económica, sociodemográfica y del entorno.
etiquetas_var <- c(Capacidad_ingresos = "Capacidad de ingresos", Se_considera_pobre = "Se considera pobre",
Tiene_internet = "Tiene internet", Educacion_jefe = "Educación del jefe",
Tamano_grupo = "Tamaño del hogar", Sexo_jefe = "Sexo del jefe",
Zona = "Zona", Region = "Región")
tabla_cat <- function(vars) {
bind_rows(lapply(vars, function(var) {
t <- d %>%
group_by(Categoría = .data[[var]]) %>%
summarise(Hogares = n(),
`% con carro (muestra)` = 100 * mean(Tiene_carro),
`% con carro (ponderado)` = 100 * weighted.mean(Tiene_carro, Factor_expansion),
.groups = "drop") %>%
mutate(Categoría = as.character(Categoría), Variable = etiquetas_var[[var]], .before = 1)
if (var == "Capacidad_ingresos")
t <- t[match(c("No alcanza", "Solo cubre gastos mínimos", "Cubre más que gastos mínimos"), t$Categoría), ]
t
}))
}
formato <- list(big.mark = ".", decimal.mark = ",")
kable(tabla_cat(c("Capacidad_ingresos", "Se_considera_pobre", "Tiene_internet")),
digits = 1, format.args = formato, caption = "Tabla 12. Tenencia de carro según variables económicas")
| Variable | Categoría | Hogares | % con carro (muestra) | % con carro (ponderado) |
|---|---|---|---|---|
| Capacidad de ingresos | No alcanza | 41.166 | 2,2 | 3,3 |
| Capacidad de ingresos | Solo cubre gastos mínimos | 41.415 | 11,2 | 16,5 |
| Capacidad de ingresos | Cubre más que gastos mínimos | 3.824 | 46,6 | 56,6 |
| Se considera pobre | No | 35.271 | 17,5 | 24,7 |
| Se considera pobre | Sí | 51.134 | 2,3 | 2,9 |
| Tiene internet | No | 43.485 | 2,3 | 2,6 |
| Tiene internet | Sí | 42.920 | 14,8 | 21,0 |
La Tabla 12 deja ver con claridad cómo la tenencia de carro aumenta de forma marcada a medida que mejora la capacidad económica del hogar. En los hogares donde el ingreso alcanza para más que los gastos mínimos, el 56,6 % (ponderado) tiene vehículo, mientras que cuando el dinero no alcanza, la cifra cae al 3,3 %. Esta misma brecha se evidencia en la pobreza percibida, donde solo el 2,9 % de quienes se consideran pobres tienen carro frente al 24,7 % de quienes no, y en la conectividad, donde contar con internet aumenta la tenencia del 2,6 % al 21,0 %.
kable(tabla_cat(c("Educacion_jefe", "Tamano_grupo", "Sexo_jefe")),
digits = 1, format.args = formato, caption = "Tabla 13. Tenencia de carro según variables sociodemográficas")
| Variable | Categoría | Hogares | % con carro (muestra) | % con carro (ponderado) |
|---|---|---|---|---|
| Educación del jefe | Ninguno/preescolar | 6.880 | 0,9 | 1,1 |
| Educación del jefe | Primaria | 31.753 | 3,8 | 4,7 |
| Educación del jefe | Secundaria | 10.896 | 4,3 | 5,8 |
| Educación del jefe | Media | 20.633 | 7,0 | 9,2 |
| Educación del jefe | Superior | 14.288 | 27,6 | 36,1 |
| Educación del jefe | Sin dato | 1.955 | 10,0 | 18,3 |
| Tamaño del hogar | 1 | 18.446 | 5,8 | 10,6 |
| Tamaño del hogar | 2 | 23.828 | 9,3 | 15,9 |
| Tamaño del hogar | 3 | 19.876 | 9,4 | 15,6 |
| Tamaño del hogar | 4 | 13.858 | 10,7 | 17,2 |
| Tamaño del hogar | 5 | 6.310 | 8,1 | 12,6 |
| Tamaño del hogar | 6 o más | 4.087 | 4,4 | 7,9 |
| Sexo del jefe | Mujer | 37.911 | 5,9 | 10,0 |
| Sexo del jefe | Hombre | 48.494 | 10,6 | 18,0 |
En la Tabla 13 se observa que la tenencia de carro varía según las características del hogar, siendo el nivel educativo del jefe la variable que más marca la diferencia. Cuando el jefe de hogar solo estudió primaria o secundaria, la presencia de vehículo no supera el 5,8 % (ponderado). Sin embargo, si cuenta con educación superior, la tenencia aumenta a 36,1 %, lo que sugiere que la educación se asocia con mayores ingresos y capacidad de compra del hogar.
Respecto al tamaño de la familia, los datos muestran una tendencia en forma de curva. La tenencia de vehículo alcanza sus puntos más altos en hogares medianos de 2 a 4 personas, donde se mueve entre el 15,6 % y el 17,2 %. En cambio, esta cifra disminuye en personas que viven solas (10,6 %) y cae todavía más en familias numerosas de 6 o más integrantes (7,9 %), lo que podría deberse a que el presupuesto de hogares grandes se destina a otras necesidades (hipótesis que este informe no contrasta).
Por último, se observa una brecha marcada según el sexo de quien encabeza el hogar. Los hogares liderados por hombres registran casi el doble de tenencia de carro (18,0 % ponderado) frente a aquellos a cargo de mujeres (10,0 %), diferencia que puede reflejar desigualdades de ingresos y de acceso a activos, además de diferencias en la composición del hogar.
kable(tabla_cat(c("Zona", "Region")),
digits = 1, format.args = formato, caption = "Tabla 14. Tenencia de carro según variables del entorno")
| Variable | Categoría | Hogares | % con carro (muestra) | % con carro (ponderado) |
|---|---|---|---|---|
| Zona | Resto del país | 65.085 | 6,3 | 9,1 |
| Zona | Ciudad capital | 21.320 | 15,1 | 21,1 |
| Región | Antioquia | 3.882 | 8,2 | 13,2 |
| Región | Bogotá | 2.860 | 20,9 | 25,7 |
| Región | Caribe | 18.662 | 5,3 | 8,2 |
| Región | Central | 16.056 | 10,8 | 13,8 |
| Región | Orinoquía-Amazonía | 17.180 | 4,8 | 6,2 |
| Región | Oriental | 15.259 | 12,7 | 14,9 |
| Región | Pacífica | 8.463 | 5,9 | 7,2 |
| Región | San Andrés | 880 | 5,6 | 5,7 |
| Región | Valle del Cauca | 3.163 | 12,1 | 17,4 |
En la Tabla 14 se aprecian importantes diferencias territoriales en la tenencia de carro particular, comenzando por el tipo de zona. En las ciudades capitales, más de uno de cada cinco hogares (21,1 % ponderado) cuenta con automóvil, mientras que en el resto del país la cifra cae al 9,1 %. Esto podría reflejar que la concentración de infraestructura, oferta de servicios e ingresos en las grandes zonas urbanas favorece la adquisición de vehículo propio.
Como referencia, el DANE (2024b) reporta que en 2023 el 17,2 % de los
hogares de las cabeceras y el 4,9 % de los de centros poblados y rural
disperso tenían carro particular. Esa clasificación no coincide con la
variable Zona de este informe (ciudad capital frente al
resto del país), por lo que las cifras no son comparables entre sí,
aunque ambas muestran una brecha territorial en el mismo sentido.
A nivel regional, Bogotá encabeza la lista con la mayor tasa de tenencia, alcanzando un 25,7 % (ponderado). Le siguen el Valle del Cauca con un 17,4 %, la región Oriental con un 14,9 %, la región Central (13,8 %) y Antioquia (13,2 %). Estas zonas agrupan los principales centros urbanos e industriales del país, lo que podría contribuir a su mayor tasa de tenencia.
En el otro extremo, las proporciones más bajas se registran en zonas periféricas o con dinámicas de transporte distintas, como San Andrés (5,7 %), Orinoquía-Amazonía (6,2 %), la región Pacífica (7,2 %) y el Caribe (8,2 %). Estas diferencias indican que la tenencia de carro se asocia no solo con las características del hogar, sino también con el territorio.
Esta sección presenta los gráficos que acompañan las tablas de la sección anterior. Siguen el orden de las tres dimensiones de las variables independientes (económica, sociodemográfica y del entorno), después de la distribución de la variable dependiente, y cierran con la relación entre variables. Los gráficos de barras usan el factor de expansión y los de ingreso y edad describen la muestra sin ponderar (véase Unidad de análisis y construcción de la base). Los valores exactos aparecen en las tablas de la sección anterior y al pasar el cursor sobre cada gráfico.
Muestra la distribución de hogares con y sin carro particular. Las barras representan la proporción estimada de hogares y permiten ver qué tan común es la tenencia de carro en la población.
tabla_auto <- d %>%
group_by(Carro_factor) %>%
summarise(hogares = sum(Factor_expansion), .groups = "drop") %>%
mutate(porcentaje = 100 * hogares / sum(hogares),
etiqueta = paste0(num(porcentaje, 1), " %"))
g1 <- ggplot(tabla_auto,
aes(x = Carro_factor, y = porcentaje, fill = Carro_factor,
text = paste0(etiqueta, "<br>Hogares expandidos: ",
format(round(hogares), big.mark = ".", decimal.mark = ",")))) +
geom_col(width = 0.65) +
geom_text(aes(label = etiqueta), nudge_y = max(tabla_auto$porcentaje) * 0.05, size = 4) +
scale_fill_manual(values = c("Sin carro" = col_no, "Con carro" = col_si)) +
labs(title = "Gráfico 1. Tenencia de carro particular",
subtitle = "Porcentaje estimado de hogares (con factor de expansión)",
x = NULL, y = "Porcentaje de hogares") +
expand_limits(y = max(tabla_auto$porcentaje) * 1.15) +
tema
ggplotly(g1, tooltip = "text") %>%
finalizar(b = 100, subtitulo = "Porcentaje estimado de hogares (con factor de expansión)")
Fuente: Elaboración propia. ECV, DANE, 2023.
Expone la distribución poblacional de la variable dependiente de la tenencia de vehículo tras aplicar los factores de expansión de la ECV 2023. Se evidencia una estructura asimétrica en los datos, donde la prevalencia de la clase positiva (hogares con automóvil) es del 14,4 %, frente a un 85,6 % perteneciente a la clase de referencia (hogares sin automóvil).
Compara la distribución del ingreso laboral mensual del hogar entre hogares sin carro y con carro, usando solo los hogares con ingreso laboral reportado mayor que cero. El eje vertical está en escala logarítmica porque el ingreso es muy asimétrico.
g2 <- d %>%
filter(!is.na(Ingreso_laboral_hogar), Ingreso_laboral_hogar > 0) %>%
ggplot(aes(x = Carro_factor, y = Ingreso_laboral_hogar / 1e6, fill = Carro_factor)) +
geom_boxplot(outlier.size = 0.8, outlier.colour = "#6A5F94") +
scale_y_log10(breaks = c(0.01, 0.1, 1, 10, 100),
labels = function(x) sub("\\.", ",", as.character(x))) +
scale_fill_manual(values = c("Sin carro" = col_no, "Con carro" = col_si)) +
labs(title = "Gráfico 2. Ingreso laboral del hogar según tenencia de carro",
x = NULL, y = "Millones de COP (escala logarítmica)") +
tema
ggplotly(g2) %>%
finalizar(b = 100, subtitulo = "Hogares con ingreso laboral reportado mayor que cero")
Fuente: Elaboración propia. ECV, DANE, 2023.
El Gráfico 2 refleja una clara diferencia en el ingreso laboral del hogar según la tenencia de vehículo. Al analizar la distribución en escala logarítmica, se observa que el 50 % central de los hogares con carro se ubica en tramos salariales sensiblemente más altos, registrando una mediana cercana a los 3 millones de pesos ($3.004.000 COP), frente al millón de pesos ($1.000.000 COP) del grupo sin carro. Aunque hay tramos de ingreso donde ambos grupos coinciden, la diferencia de nivel entre los dos bloques confirma que el ingreso laboral se asocia fuertemente con tener automóvil. De igual forma, presentar los datos en escala logarítmica resulta fundamental para controlar la gran dispersión de los ingresos y manejar adecuadamente los valores extremos.
grafico_barras("Capacidad_ingresos",
"Gráfico 3. Tenencia de carro según suficiencia de ingresos",
"Porcentaje de hogares con carro en cada categoría",
"Percepción sobre los ingresos", ordinal = TRUE,
orden = c("No alcanza", "Solo cubre gastos mínimos", "Cubre más que gastos mínimos"))
Fuente: Elaboración propia. ECV, DANE, 2023.
Se muestra cómo la percepción sobre la suficiencia de los ingresos del hogar se relaciona de forma directa con la tenencia de carro. Entre las familias que afirman que el dinero no les alcanza, apenas un 3,3 % cuenta con vehículo. En cambio, cuando el ingreso alcanza para cubrir los gastos mínimos, la proporción sube al 16,5 %, ubicándose ligeramente por encima del promedio nacional del 14,4 %. El contraste más fuerte se da en los hogares con mayor libertad económica, donde los ingresos superan las necesidades básicas: allí más de la mitad (56,6 %) tiene automóvil propio. Estos resultados confirman una clara asociación entre la comodidad financiera percibida y la presencia de carro en el hogar, mostrando que este tipo de activo suele estar reservado para familias con presupuesto suficiente para ir más allá del consumo básico.
grafico_barras("Se_considera_pobre",
"Gráfico 4. Tenencia de carro y autopercepción de pobreza",
"Porcentaje de hogares con carro en cada categoría",
"El hogar se considera pobre")
Fuente: Elaboración propia. ECV, DANE, 2023.
Se muestra la relación entre la tenencia de automóvil y la pobreza subjetiva reportada por los hogares. Entre las familias que manifiestan no ser pobres, el 24,7 % cuenta con vehículo, superando de manera clara el promedio nacional del 14,4 %. En contraste, dentro del grupo que se declara en situación de pobreza, la tenencia cae a apenas un 2,9 %. Esta brecha refleja cómo la valoración del bienestar socioeconómico se vincula directamente con la tenencia de bienes durables. Sin embargo, al tratarse de una medida de carácter subjetivo, esta diferencia debe entenderse como una simple relación descriptiva y no como una relación de causalidad, pues contar con automóvil incide naturalmente en la evaluación que hace la familia sobre sus condiciones de vida.
grafico_barras("Tiene_internet",
"Gráfico 5. Tenencia de carro según conexión a internet",
"Porcentaje de hogares con carro en cada categoría",
"El hogar tiene internet")
Fuente: Elaboración propia. ECV, DANE, 2023.
Se evidencia la tenencia de vehículo según la conectividad a internet en el hogar. Entre las familias que disponen de este servicio, el 21,0 % posee automóvil, superando con holgura el promedio nacional del 14,4 %. En contraste, en los hogares sin acceso a internet, la presencia de carro se reduce a un mínimo 2,6 %.
Compara la tasa de tenencia de carro entre los niveles educativos agrupados del jefe del hogar, incluida la categoría “Sin dato”. Se incluye porque la educación puede estar relacionada con oportunidades laborales e ingresos.
grafico_barras("Educacion_jefe", "Gráfico 6. Tenencia de carro según educación del jefe",
"Porcentaje de hogares con carro en cada nivel educativo",
"Nivel educativo del jefe del hogar", ordinal = TRUE)
Fuente: Elaboración propia. ECV, DANE, 2023.
Se refleja una clara relación entre el nivel de escolaridad del jefe del hogar y la tenencia de automóvil. A medida que se incrementa el nivel educativo, la proporción de hogares con vehículo sube de manera progresiva, pasando de apenas un 1,1 % en quienes no tienen estudios hasta un 9,2 % en educación media, manteniéndose en todos estos tramos por debajo de la media nacional (14,4 %).
El cambio más representativo se da en la educación superior, donde la tenencia aumenta de forma marcada al 36,1 %. Este comportamiento evidencia cómo una mayor formación académica se asocia fuertemente con una mayor capacidad de ingresos y un mejor acceso a bienes durables en el hogar.
La categoría “Sin dato” (jefes sin nivel educativo registrado) presenta una tasa de 18,3 %, superior a la de los niveles Ninguno a Media; por eso se mantuvo como categoría propia.
grafico_barras("Tamano_grupo", "Gráfico 7. Tenencia de carro según tamaño del hogar",
"Porcentaje de hogares con carro según número de integrantes",
"Número de integrantes del hogar", ordinal = TRUE)
Fuente: Elaboración propia. ECV, DANE, 2023.
Se observa una relación no lineal entre el número de integrantes del hogar y la tenencia de automóvil. La proporción de hogares con vehículo es menor en viviendas unipersonales (10,6 %), pero supera el promedio nacional (14,4 %) en familias de tamaño medio (2 a 4 personas), alcanzando su nivel más alto en hogares de 4 integrantes (17,2 %).
Sin embargo, a partir de los 5 miembros la tenencia disminuye al 12,6 % y cae de forma pronunciada al 7,9 % en hogares de 6 o más personas.
col_sin_8 <- "#A48AE0" # lila claro (mismo que en los gráficos ROC)
col_con_8 <- "#4E2FB0" # violeta oscuro
niveles_8 <- c("Sin carro", "Con carro")
# Espacios al final para que la leyenda no recorte el texto
etiquetas_8 <- paste0(niveles_8, "\u00A0\u00A0\u00A0\u00A0")
g8 <- ggplot(d, aes(x = Edad_jefe, fill = Carro_factor, color = Carro_factor)) +
geom_density(alpha = 0.30, linewidth = 1.1) +
scale_fill_manual(values = c("Sin carro" = col_sin_8, "Con carro" = col_con_8),
breaks = niveles_8, labels = etiquetas_8) +
scale_color_manual(values = c("Sin carro" = col_sin_8, "Con carro" = col_con_8),
breaks = niveles_8, labels = etiquetas_8) +
labs(title = "Gráfico 8. Distribución de la edad del jefe del hogar",
x = "Edad (años)", y = "Densidad", fill = NULL, color = NULL) +
tema +
theme(legend.position = "right")
ggplotly(g8) %>%
layout(legend = list(x = 0.98, y = 0.98, xanchor = "right", yanchor = "top",
bgcolor = "rgba(255,255,255,0.75)",
font = list(size = 16),
entrywidth = 150, entrywidthmode = "pixels")) %>%
finalizar(b = 100, r = 30,
subtitulo = "Curvas de densidad por tenencia de carro (muestra sin ponderar)")
Fuente: Elaboración propia. ECV, DANE, 2023.
Muestra la distribución de la edad del jefe del hogar según la tenencia de vehículo. Se observa que los hogares con carro concentran sus jefaturas en etapas más maduras, principalmente entre los 40 y los 60 años. En cambio, en los hogares sin vehículo existe una mayor presencia de jefes jóvenes, especialmente por debajo de los 35 años. Aunque ambas curvas tienden a alinearse hacia las edades más avanzadas, la diferencia en los tramos intermedios refleja la influencia del ciclo de vida: la tenencia de automóvil es más frecuente en las edades asociadas a la etapa de mayor estabilidad y consolidación económica del hogar.
grafico_barras("Sexo_jefe",
"Gráfico 9. Tenencia de carro según sexo del jefe",
"Porcentaje de hogares con carro en cada categoría",
"Sexo del jefe del hogar")
Fuente: Elaboración propia. ECV, DANE, 2023.
Muestra una diferencia en la tenencia de carro según el sexo de la persona al frente del hogar. En las viviendas con jefatura masculina, la tasa de tenencia se ubica en el 18,0 %, por encima del promedio nacional (14,4 %). En contraste, en aquellas lideradas por mujeres, la cifra desciende al 10,0 %.
grafico_barras("Zona",
"Gráfico 10. Tenencia de carro: ciudad capital y resto del país",
"Porcentaje de hogares con carro en cada zona",
"Zona")
Fuente: Elaboración propia. ECV, DANE, 2023.
Se evidencia una diferencia marcada en la tenencia de automóvil según la ubicación geográfica del hogar. En las ciudades capitales, el 21,1 % de los hogares cuenta con vehículo, una cifra que supera el promedio nacional del 14,4 %. En el resto del país, en cambio, esta proporción cae al 9,1 %. Esta distancia refleja la concentración de ingresos y servicios en los centros urbanos principales.
grafico_barras("Region", "Gráfico 11. Tenencia de carro según región",
"Porcentaje de hogares con carro en cada región",
"Región", ancho = 9, ordenar_por_tasa = TRUE)
Fuente: Elaboración propia. ECV, DANE, 2023.
Se evidencia cómo se distribuye la tenencia de automóvil entre las distintas regiones del país. Bogotá encabeza la lista con un 25,7 %, seguida por Valle del Cauca (17,4 %) y la región Oriental (14,9 %), las cuales superan el promedio nacional del 14,4 %. Por su parte, las regiones Central (13,8 %) y Antioquia (13,2 %) se ubican cerca de la media, mientras que los niveles más bajos se registran en la región Caribe (8,2 %), Pacífica (7,2 %), Orinoquía-Amazonía (6,2 %) y San Andrés (5,7 %). Estas diferencias pueden estar asociadas con la estructura urbana y con las condiciones socioeconómicas de cada región, aspectos que este informe no mide directamente.
La matriz resume la relación lineal entre la tenencia de carro y las variables cuantitativas de la base y la variable dependiente (0/1). Las correlaciones van de −1 a 1: valores positivos indican que ambas variables tienden a aumentar juntas; valores negativos, que tienden a moverse en sentidos opuestos; valores cercanos a cero indican una relación lineal débil. La correlación no implica causalidad.
# 1. Solo variables cuantitativas + variable dependiente
corr_datos <- d %>%
transmute(
`Tiene carro (0/1)` = as.numeric(Tiene_carro),
`Log ingreso laboral` = ifelse(Sin_ingreso_laboral == 1, NA, Log_ingreso),
`Tamaño del hogar` = as.numeric(Tamano_hogar),
`Edad del jefe` = as.numeric(Edad_jefe)
)
# 2. Matriz de correlación y formato largo
cm_cor <- cor(corr_datos, use = "pairwise.complete.obs")
corr_larga <- as.data.frame(as.table(cm_cor)) %>%
mutate(
Var1 = factor(Var1, levels = colnames(cm_cor)),
Var2 = factor(Var2, levels = colnames(cm_cor))
)
# 3. Construcción del gráfico base con ggplot2
g12 <- ggplot(corr_larga,
aes(x = Var1, y = Var2, fill = Freq,
text = paste0(as.character(Var1), " / ", as.character(Var2),
"<br>Correlación: ", round(Freq, 2)))) +
geom_tile(color = "white", linewidth = 0.4) +
geom_text(aes(label = sprintf("%.2f", Freq)), size = 3.2, color = "#2B2250") +
scale_fill_gradient2(low = "#E4572E", mid = "white", high = "#4E2FB0",
midpoint = 0, limits = c(-1, 1), name = "Correlación") +
labs(title = "Gráfico 12. Matriz de correlación de variables cuantitativas",
subtitle = "Valores entre −1 y 1; asociación lineal, no causalidad",
x = NULL, y = NULL) +
tema +
theme(
axis.text.x = element_text(angle = 45, hjust = 1, vjust = 1),
legend.position = "right"
)
# 4. Renderizado con Plotly
ggplotly(g12, tooltip = "text") %>%
layout(xaxis = list(tickangle = -45)) %>%
finalizar(b = 140, l = 150, r = 50, t = 80)
Fuente: Elaboración propia. ECV, DANE, 2023.
En el diagrama se evidencia que el logaritmo del ingreso laboral es la variable con mayor correlación lineal con la tenencia de vehículo (0,35), confirmando el peso de la capacidad económica en el hogar. En cambio, la edad del jefe (0,06) y el tamaño del hogar (0,01) muestran valores muy cercanos a cero, lo que indica una asociación lineal débil. Esto, por sí solo, no descarta relaciones no lineales como las que sugieren los Gráficos 7 y 8, por lo que una correlación simple no alcanza a capturar toda su dinámica.
Esta sección presenta las tablas y los gráficos de los modelos de clasificación. Su numeración continúa la de las secciones anteriores (Tablas 15 a 24 y Gráficos 13 a 20), y cada gráfico indica su fuente debajo. Los modelos se ajustaron con la muestra de entrenamiento y se evaluaron en la muestra de prueba (véase Modelos y métricas de evaluación).
Alcance de las estimaciones. Los porcentajes descriptivos se presentaron de dos formas: sin ponderar (frecuencias observadas en la muestra) y ponderados con el factor de expansión de la ECV (estimación aproximada de las proporciones nacionales). Los modelos, en cambio, se ajustan y evalúan sin ponderar. Por tanto, sus coeficientes, probabilidades predichas y métricas describen el desempeño en las particiones de entrenamiento y prueba, donde el 8,5 % de los hogares tiene carro, y no constituyen por sí solos estimaciones representativas de la población colombiana, donde es el 14,4 %. Esto condiciona la lectura de la precisión y del umbral de prevalencia (véanse Diseño de evaluación y Limitaciones de los modelos).
formula_x <- ~ Log_ingreso + Sin_ingreso_laboral + Capacidad_ingresos + Tamano_hogar + Edad_jefe +
Sexo_jefe + Se_considera_pobre + Tiene_internet + Zona + Educacion_jefe + Region
# Partición estratificada 70/30
set.seed(123)
idx_tr <- sort(unlist(lapply(split(seq_len(nrow(d)), d$Tiene_carro),
function(i) sample(i, size = round(0.7 * length(i))))))
tr <- d[idx_tr, ]
te <- d[-idx_tr, ]
umbral <- mean(tr$Tiene_carro)
# Matriz de diseño estandarizada para KNN
mm <- model.matrix(formula_x, data = d)[, -1]
mu <- colMeans(mm[idx_tr, ]); sdv <- apply(mm[idx_tr, ], 2, sd)
Z <- scale(mm, center = mu, scale = sdv)
Ztr <- Z[idx_tr, ]; Zte <- Z[-idx_tr, ]
ytr <- factor(tr$Tiene_carro, levels = c(0, 1))
yte <- te$Tiene_carro
cm <- cor(mm); diag(cm) <- 0
Entrenamiento: 60.483 hogares; prueba: 25.922 hogares. Umbral de prevalencia (proporción de carros en entrenamiento): 0,0849 (véase Diseño de evaluación). La mayor correlación absoluta entre variables explicativas (ya codificadas) es 0,47, por lo que no se observa multicolinealidad severa.
etiqueta_term <- function(x) {
x <- sub("^\\(Intercept\\)$", "Intercepto", x)
x <- sub("^Log_ingreso$", "Log del ingreso laboral (por unidad de log)", x)
x <- sub("^Sin_ingreso_laboral$", "Sin ingreso laboral reportado", x)
x <- sub("^Tamano_hogar$", "Tamaño del hogar (por persona)", x)
x <- sub("^Edad_jefe$", "Edad del jefe (por año)", x)
x <- sub("^Capacidad_ingresosNo alcanza", "Ingresos: no alcanza", x)
x <- sub("^Capacidad_ingresosCubre más que gastos mínimos", "Ingresos: cubre más que el mínimo", x)
x <- sub("^Educacion_jefe", "Educación jefe: ", x)
x <- sub("^Region", "Región: ", x)
x <- sub("^Sexo_jefeHombre", "Sexo jefe: Hombre", x)
x <- sub("^Tiene_internetSí", "Tiene internet: Sí", x)
x <- sub("^Se_considera_pobreSí", "Se considera pobre: Sí", x)
x <- sub("^ZonaCiudad capital", "Zona: Ciudad capital", x)
x
}
fit_lg <- glm(Tiene_carro ~ Log_ingreso + Sin_ingreso_laboral + Capacidad_ingresos + Tamano_hogar + Edad_jefe +
Sexo_jefe + Se_considera_pobre + Tiene_internet + Zona + Educacion_jefe + Region,
data = tr, family = binomial)
co <- summary(fit_lg)$coefficients
ci <- exp(confint.default(fit_lg))
tab_or <- data.frame(
Coeficiente = co[, "Estimate"], OR = exp(co[, "Estimate"]),
`IC95% inf` = ci[, 1], `IC95% sup` = ci[, 2],
`Valor p` = co[, "Pr(>|z|)"], check.names = FALSE
)
tab_or$`Valor p` <- ifelse(tab_or$`Valor p` < 0.001, "<0,001", format(round(tab_or$`Valor p`, 3), decimal.mark = ","))
rownames(tab_or) <- etiqueta_term(rownames(tab_or))
kable(tab_or, digits = 3, format.args = formato,
caption = "Tabla 15. Regresión logística: coeficientes y odds ratios (muestra de entrenamiento)")
| Coeficiente | OR | IC95% inf | IC95% sup | Valor p | |
|---|---|---|---|---|---|
| Intercepto | -18,960 | 0,000 | 0,000 | 0,000 | <0,001 |
| Log del ingreso laboral (por unidad de log) | 0,857 | 2,355 | 2,228 | 2,490 | <0,001 |
| Sin ingreso laboral reportado | 0,467 | 1,595 | 1,443 | 1,762 | <0,001 |
| Ingresos: no alcanza | -0,525 | 0,591 | 0,536 | 0,653 | <0,001 |
| Ingresos: cubre más que el mínimo | 0,809 | 2,245 | 2,026 | 2,487 | <0,001 |
| Tamaño del hogar (por persona) | 0,062 | 1,064 | 1,038 | 1,092 | <0,001 |
| Edad del jefe (por año) | 0,032 | 1,032 | 1,030 | 1,035 | <0,001 |
| Sexo jefe: Hombre | 0,763 | 2,146 | 1,995 | 2,308 | <0,001 |
| Se considera pobre: Sí | -0,879 | 0,415 | 0,379 | 0,455 | <0,001 |
| Tiene internet: Sí | 0,950 | 2,586 | 2,353 | 2,841 | <0,001 |
| Zona: Ciudad capital | 0,099 | 1,105 | 1,022 | 1,194 | 0,012 |
| Educación jefe: Primaria | 0,956 | 2,602 | 1,939 | 3,490 | <0,001 |
| Educación jefe: Secundaria | 1,144 | 3,138 | 2,299 | 4,285 | <0,001 |
| Educación jefe: Media | 1,533 | 4,630 | 3,434 | 6,244 | <0,001 |
| Educación jefe: Superior | 2,273 | 9,708 | 7,197 | 13,097 | <0,001 |
| Educación jefe: Sin dato | 1,950 | 7,029 | 4,900 | 10,083 | <0,001 |
| Región: Bogotá | 0,433 | 1,542 | 1,248 | 1,905 | <0,001 |
| Región: Caribe | -0,051 | 0,950 | 0,790 | 1,143 | 0,587 |
| Región: Central | 0,473 | 1,605 | 1,348 | 1,910 | <0,001 |
| Región: Orinoquía-Amazonía | -0,277 | 0,758 | 0,627 | 0,916 | 0,004 |
| Región: Oriental | 0,629 | 1,876 | 1,578 | 2,231 | <0,001 |
| Región: Pacífica | 0,281 | 1,324 | 1,080 | 1,623 | 0,007 |
| Región: San Andrés | -1,110 | 0,329 | 0,219 | 0,496 | <0,001 |
| Región: Valle del Cauca | 0,302 | 1,353 | 1,089 | 1,681 | 0,006 |
El modelo logit permite estimar la asociación de cada variable con la tenencia de carro manteniendo constantes las demás. El nivel educativo del jefe muestra la asociación más fuerte: frente a «ninguno/preescolar», los hogares cuyo jefe tiene educación superior presentan 9,71 veces las odds de tener carro, y las odds crecen con cada nivel educativo. El ingreso laboral también se asocia positivamente (OR de 2,36 por cada unidad del logaritmo). Los hogares cuyos ingresos cubren más que los gastos mínimos tienen 2,25 veces las odds de los que solo los cubren, y tener internet o un jefe hombre se asocia con 2,59 y 2,15 veces las odds, respectivamente.
Una posible explicación es que la educación aproxime el ingreso permanente y el acceso al crédito, y que el internet funcione como indicador de bienestar general; sin embargo, estas explicaciones no se contrastaron con los datos. Del mismo modo, el OR del sexo del jefe puede reflejar la composición del hogar y no un efecto directo del sexo. Los coeficientes y los intervalos de confianza al 95 % (Gráfico 13) describen asociaciones en la muestra de entrenamiento, no relaciones causales.
or <- function(nm) num(unname(exp(coef(fit_lg))[nm]), 2)
orn <- function(nm) unname(exp(coef(fit_lg))[nm])
or_edu <- orn(c("Educacion_jefePrimaria", "Educacion_jefeSecundaria", "Educacion_jefeMedia", "Educacion_jefeSuperior"))
mono_edu <- all(diff(c(1, or_edu)) > 0)
or_reg <- orn(grep("^Region", names(coef(fit_lg)), value = TRUE))
imp <- drop1(fit_lg, test = "Chisq")
imp <- imp[rownames(imp) != "<none>", ]
p_reg <- imp["Region", "Pr(>Chi)"]
imp_tab <- data.frame(Variable = rownames(imp), gl = imp$Df, LR = imp$LRT, p = imp$`Pr(>Chi)`)
imp_tab <- imp_tab[order(-imp_tab$LR), ]
imp_tab$p <- ifelse(imp_tab$p < 0.001, "<0,001", format(round(imp_tab$p, 3), decimal.mark = ","))
nom_var <- c(Log_ingreso = "Log del ingreso laboral", Sin_ingreso_laboral = "Sin ingreso laboral reportado",
Capacidad_ingresos = "Capacidad de ingresos", Tamano_hogar = "Tamaño del hogar",
Edad_jefe = "Edad del jefe", Sexo_jefe = "Sexo del jefe",
Se_considera_pobre = "Se considera pobre", Tiene_internet = "Tiene internet",
Zona = "Zona", Educacion_jefe = "Educación del jefe", Region = "Región")
imp_show <- imp_tab
imp_show$Variable <- unname(nom_var[imp_show$Variable])
kable(imp_show, digits = c(0, 0, 1, 0), row.names = FALSE,
col.names = c("Variable", "gl", "Razón de verosimilitud (χ²)", "Valor p"),
format.args = formato,
caption = "Tabla 16. Aporte de cada variable al logit (prueba de razón de verosimilitud al quitarla del modelo)")
| Variable | gl | Razón de verosimilitud (χ²) | Valor p |
|---|---|---|---|
| Log del ingreso laboral | 1 | 1.041,1 | <0,001 |
| Educación del jefe | 5 | 772,6 | <0,001 |
| Edad del jefe | 1 | 610,3 | <0,001 |
| Sexo del jefe | 1 | 442,4 | <0,001 |
| Tiene internet | 1 | 432,1 | <0,001 |
| Se considera pobre | 1 | 385,4 | <0,001 |
| Capacidad de ingresos | 2 | 380,6 | <0,001 |
| Región | 8 | 376,1 | <0,001 |
| Sin ingreso laboral reportado | 1 | 81,7 | <0,001 |
| Tamaño del hogar | 1 | 22,6 | <0,001 |
| Zona | 1 | 6,2 | 0,012 |
nombres <- c(Log_ingreso = "el ingreso laboral", Educacion_jefe = "la educación del jefe",
Edad_jefe = "la edad del jefe", Sexo_jefe = "el sexo del jefe",
Tiene_internet = "la conexión a internet", Se_considera_pobre = "la autopercepción de pobreza",
Capacidad_ingresos = "la capacidad de ingresos", Region = "la región",
Sin_ingreso_laboral = "no tener ingreso laboral reportado",
Tamano_hogar = "el tamaño del hogar", Zona = "ser ciudad capital")
La Tabla 16 mide cuánto empeora el ajuste del modelo al retirar cada variable. Todas aportan de forma estadísticamente significativa (p < 0,05). El ingreso laboral (χ² = 1.041,1) y la educación del jefe (χ² = 772,6) son las de mayor aporte, lo que indica que la capacidad económica del hogar y el nivel educativo son los factores más asociados con la tenencia de carro.
En un segundo nivel se ubican la edad del jefe (χ² = 610,3), el sexo del jefe (χ² = 442,4), la conexión a internet (χ² = 432,1), la autopercepción de pobreza (χ² = 385,4) y la suficiencia de ingresos (χ² = 380,6). Por último, la región (χ² = 376,1), la ausencia de ingreso laboral reportado (χ² = 81,7), el tamaño del hogar (χ² = 22,6) y la ciudad capital (χ² = 6,2) tienen aportes menores, aunque permiten reconocer diferencias territoriales y de composición del hogar.
or_df <- data.frame(Variable = names(coef(fit_lg)), OR = exp(coef(fit_lg)),
lo = ci[, 1], hi = ci[, 2])[-1, ]
# Nombres legibles y cortos para el eje y (una sola línea cada uno)
or_df$Variable <- etiqueta_term(or_df$Variable)
# Etiqueta más corta solo para el eje del gráfico (la tabla conserva el nombre completo)
or_df$Variable <- sub("Log del ingreso laboral \\(por unidad de log\\)",
"Log del ingreso laboral", or_df$Variable)
# Parte en dos renglones las etiquetas largas del eje (solo en este gráfico)
or_df$Variable <- vapply(strwrap(or_df$Variable, width = 30, simplify = FALSE),
paste, character(1), collapse = "<br>")
or_df$Variable <- factor(or_df$Variable, levels = or_df$Variable[order(or_df$OR)])
p_or <- ggplot(or_df, aes(y = Variable,
text = paste0(Variable, ": OR = ", round(OR, 2),
" (IC 95 %: ", round(lo, 2), " a ", round(hi, 2), ")"))) +
geom_vline(xintercept = 1, linetype = "dashed", color = "#AFA4C8") +
geom_segment(aes(x = lo, xend = hi, yend = Variable), color = "#A48AE0", linewidth = 1) +
geom_point(aes(x = OR), color = "#4E2FB0", size = 2.5) +
scale_x_log10() +
labs(title = "Gráfico 13. Odds ratios del modelo logit (IC 95 %)",
subtitle = "Los intervalos que cruzan el valor 1 no son estadísticamente significativos",
x = "Odds ratio (escala logarítmica)", y = NULL) +
tema
ggplotly(p_or, tooltip = "text") %>%
finalizar(b = 90, l = 300,
subtitulo = "Los intervalos que cruzan el valor 1 no son estadísticamente significativos")
Fuente: Elaboración propia. ECV, DANE, 2023.
El Gráfico 13 presenta los odds ratios del modelo logit con sus intervalos de confianza al 95 %, en escala logarítmica. La línea punteada en 1 marca ausencia de asociación: los intervalos que la cruzan (como el del Caribe) no son estadísticamente significativos. La escala logarítmica permite comparar de forma simétrica las variables asociadas con mayores odds (OR > 1) y con menores odds (OR < 1).
Interpretación de los odds ratios (manteniendo constantes las demás variables; los supuestos del modelo se discuten en la sección Supuestos y robustez del logit):
La elección de k se hizo con un conjunto de validación extraído del entrenamiento (20.000 hogares para ajustar y 6.000 para validar), comparando el AUC (Tabla 17 y Gráfico 14).
set.seed(1)
sub <- sample(seq_len(nrow(Ztr)), 26000)
a <- sub[1:20000]; v <- sub[20001:26000]
grid <- c(5, 11, 21, 41, 81, 121, 201, 301)
prob_knn <- function(train, test, cl, k) {
kn <- FNN::knn(train = train, test = test, cl = cl, k = k, prob = TRUE, algorithm = "brute")
pr <- attr(kn, "prob")
ifelse(as.character(kn) == "1", pr, 1 - pr)
}
auc_k <- sapply(grid, function(k) {
p <- prob_knn(Ztr[a, ], Ztr[v, ], ytr[a], k)
as.numeric(auc(roc(ytr[v], p, levels = c("0", "1"), direction = "<", quiet = TRUE)))
})
tab_k <- data.frame(k = grid, `AUC en validación` = round(auc_k, 4), check.names = FALSE)
k_opt <- grid[which.max(auc_k)]
kable(tab_k, format.args = formato,
caption = "Tabla 17. Selección del número de vecinos (k) según el AUC en validación")
| k | AUC en validación |
|---|---|
| 5 | 0,8161 |
| 11 | 0,8515 |
| 21 | 0,8652 |
| 41 | 0,8788 |
| 81 | 0,8768 |
| 121 | 0,8772 |
| 201 | 0,8744 |
| 301 | 0,8733 |
La Tabla 17 muestra el AUC en validación para cada valor de k. Con k = 5 el AUC es 0,8161: con pocos vecinos la clasificación es sensible al ruido de casos individuales (sobreajuste). El AUC aumenta hasta k = 41 (0,8788), el máximo, y entre k = 81 y k = 301 se mantiene entre 0,873 y 0,877.
p_k <- ggplot(tab_k, aes(x = k, y = `AUC en validación`)) +
geom_line(color = "#A48AE0") +
geom_point(color = "#4E2FB0", size = 2.5) +
geom_point(data = subset(tab_k, k == k_opt), color = "#E4572E", size = 4) +
scale_x_log10(breaks = tab_k$k) +
labs(title = "Gráfico 14. AUC en validación según el número de vecinos (k)",
x = "k (escala logarítmica)", y = "AUC") +
tema +
theme(axis.title.y = element_text(margin = margin(r = 25)))
ggplotly(p_k) %>%
finalizar(b = 90, subtitulo = "El punto naranja marca el k elegido (mayor AUC)")
Fuente: Elaboración propia. ECV, DANE, 2023.
El Gráfico 14 ilustra lo anterior: el AUC crece con rapidez entre k = 5 y k = 41 (punto naranja) y luego se estabiliza. Por eso se adoptó k = 41 en el modelo final.
p_knn <- prob_knn(Ztr, Zte, ytr, k_opt)
p_lg <- as.numeric(predict(fit_lg, newdata = te, type = "response"))
Se comparan el logit y el KNN en la muestra de prueba con el umbral 0,5 y con el umbral de prevalencia (Tablas 18 a 21 y Gráficos 15 a 18).
metricas <- function(y, p, u) {
pred <- as.integer(p >= u)
tp <- sum(pred == 1 & y == 1); tn <- sum(pred == 0 & y == 0)
fp <- sum(pred == 1 & y == 0); fn <- sum(pred == 0 & y == 1)
sens <- tp / (tp + fn); prec <- ifelse(tp + fp == 0, NA, tp / (tp + fp))
c(Exactitud = (tp + tn) / length(y), Sensibilidad = sens,
Especificidad = tn / (tn + fp), Precision = prec,
F1 = 2 * prec * sens / (prec + sens), VP = tp, FP = fp, FN = fn, VN = tn)
}
roc_lg <- roc(yte, p_lg, levels = c(0, 1), direction = "<", quiet = TRUE)
roc_knn <- roc(yte, p_knn, levels = c(0, 1), direction = "<", quiet = TRUE)
auc_lg <- as.numeric(auc(roc_lg)); auc_knn <- as.numeric(auc(roc_knn))
res <- rbind(
data.frame(Modelo = "Logit", Umbral = "0,5", t(metricas(yte, p_lg, 0.5)), check.names = FALSE),
data.frame(Modelo = "KNN", Umbral = "0,5", t(metricas(yte, p_knn, 0.5)), check.names = FALSE),
data.frame(Modelo = "Logit", Umbral = paste0("Prevalencia (", num(umbral, 3), ")"),
t(metricas(yte, p_lg, umbral)), check.names = FALSE),
data.frame(Modelo = "KNN", Umbral = paste0("Prevalencia (", num(umbral, 3), ")"),
t(metricas(yte, p_knn, umbral)), check.names = FALSE)
)
res$AUC <- rep(c(auc_lg, auc_knn), 2)
kable(res[, c("Modelo", "Umbral", "AUC", "Exactitud", "Sensibilidad", "Especificidad", "Precision", "F1")],
col.names = c("Modelo", "Umbral", "AUC", "Exactitud", "Sensibilidad", "Especificidad", "Precisión", "F1"),
digits = 3, row.names = FALSE, format.args = formato,
caption = "Tabla 18. Desempeño en la muestra de prueba por modelo y umbral")
| Modelo | Umbral | AUC | Exactitud | Sensibilidad | Especificidad | Precisión | F1 |
|---|---|---|---|---|---|---|---|
| Logit | 0,5 | 0,891 | 0,930 | 0,308 | 0,988 | 0,701 | 0,428 |
| KNN | 0,5 | 0,876 | 0,928 | 0,282 | 0,988 | 0,685 | 0,400 |
| Logit | Prevalencia (0,085) | 0,891 | 0,807 | 0,812 | 0,806 | 0,280 | 0,416 |
| KNN | Prevalencia (0,085) | 0,876 | 0,792 | 0,810 | 0,790 | 0,264 | 0,398 |
Se evalúa el comportamiento de los modelos Logit y KNN en la muestra de prueba utilizando dos criterios de clasificación: el umbral estándar de 0,5 y el umbral ajustado a la prevalencia de la muestra de entrenamiento (0,0849). De manera general, la regresión logística muestra un desempeño global ligeramente superior, alcanzando un AUC de 0,891 frente al 0,876 obtenido por KNN. Es importante resaltar que el valor del AUC permanece idéntico en ambos umbrales para cada modelo, ya que esta métrica evalúa la capacidad de ordenamiento de las probabilidades de forma independiente al punto de corte elegido.
Al aplicar el umbral tradicional de 0,5, ambos algoritmos alcanzan una exactitud global elevada, cercana al 93 %. No obstante, este indicador responde principalmente a la mayor proporción de hogares que no poseen vehículo en la muestra. Si bien la especificidad es casi perfecta (98,8 %), la capacidad para detectar los hogares que sí tienen carro es reducida, alcanzando una sensibilidad de solo 30,8 % en Logit y 28,2 % en KNN, lo que implica que la mayoría de los casos positivos quedan sin identificar.
Ajustar el corte al nivel de prevalencia (0,085) logra un balance mucho más efectivo para el análisis. Con este cambio, la sensibilidad aumenta de forma sustancial hasta un 81,2 % en Logit y un 81,0 % en KNN, logrando capturar a más de 8 de cada 10 hogares con automóvil. Aunque la precisión disminuye al 28,0 % debido al incremento natural en la detección de casos, la especificidad se mantiene equilibrada en un 80,6 %, confirmando que el modelo Logit calibrado por prevalencia ofrece la mejor relación de desempeño para identificar hogares con vehículo.
kable(res[, c("Modelo", "Umbral", "VP", "FP", "FN", "VN")], row.names = FALSE,
format.args = formato,
caption = "Tabla 19. Matrices de confusión por modelo y umbral (VP = verdaderos positivos: hogares con carro bien clasificados)")
| Modelo | Umbral | VP | FP | FN | VN |
|---|---|---|---|---|---|
| Logit | 0,5 | 679 | 289 | 1.523 | 23.431 |
| KNN | 0,5 | 621 | 285 | 1.581 | 23.435 |
| Logit | Prevalencia (0,085) | 1.788 | 4.601 | 414 | 19.119 |
| KNN | Prevalencia (0,085) | 1.783 | 4.980 | 419 | 18.740 |
Se detallan los conteos de las matrices de confusión para los modelos Logit y KNN en la muestra de prueba, comparando los resultados del umbral estándar de 0,5 frente al umbral ajustado por prevalencia (0,085). Estas cifras permiten entender en detalle cómo influye la selección del punto de corte en la capacidad de clasificar correctamente a los hogares con automóvil (verdaderos positivos, VP) y a aquellos sin él (verdaderos negativos, VN).
Con el umbral tradicional de 0,5, ambos modelos adoptan un criterio bastante estricto para clasificar positivos. Aunque esto mantiene muy bajo el número de falsos positivos (289 en Logit y 285 en KNN), deja sin detectar a la gran mayoría de los hogares que verdaderamente poseen vehículo, generando un número elevado de falsos negativos (1.523 en Logit y 1.581 en KNN). Bajo este corte, el modelo Logit logra una ligera ventaja al identificar correctamente a 679 hogares con carro, frente a los 621 alcanzados por KNN.
Al calibrar el umbral al nivel de prevalencia (0,085), la capacidad para detectar hogares con vehículo mejora de forma notable. Los verdaderos positivos aumentan a 1.788 en Logit y 1.783 en KNN, al tiempo que los falsos negativos se reducen de forma drástica a solo 414 y 419 hogares, respectivamente. Aunque esta mayor apertura eleva los falsos positivos (4.601 en Logit y 4.980 en KNN), permite identificar a más del 80 % de los hogares con carro en la muestra. En la comparación directa con este umbral ajustado, el modelo Logit resulta más eficiente al lograr la misma efectividad de aciertos positivos pero generando 379 falsos positivos menos que KNN.
# Matriz de confusión con caret (clase positiva = "1": hogar con carro)
cm_fun <- function(p, u) {
confusionMatrix(factor(as.integer(p >= u), levels = c(0, 1)),
factor(yte, levels = c(0, 1)), positive = "1")
}
cm_list <- list(cm_fun(p_lg, 0.5), cm_fun(p_knn, 0.5), cm_fun(p_lg, umbral), cm_fun(p_knn, umbral))
tab_cm <- data.frame(
Modelo = c("Logit", "KNN", "Logit", "KNN"),
Umbral = c("0,5", "0,5", "Prevalencia", "Prevalencia"),
Kappa = sapply(cm_list, function(x) unname(x$overall["Kappa"])),
`Exactitud balanceada` = sapply(cm_list, function(x) unname(x$byClass["Balanced Accuracy"])),
check.names = FALSE
)
kable(tab_cm, digits = 3, row.names = FALSE, format.args = formato,
caption = "Tabla 20. Kappa y exactitud balanceada (muestra de prueba)")
| Modelo | Umbral | Kappa | Exactitud balanceada |
|---|---|---|---|
| Logit | 0,5 | 0,397 | 0,648 |
| KNN | 0,5 | 0,368 | 0,635 |
| Logit | Prevalencia | 0,332 | 0,809 |
| KNN | Prevalencia | 0,309 | 0,800 |
# Prueba de DeLong para comparar los AUC
rt <- roc.test(roc_lg, roc_knn, method = "delong")
p_delong <- pfmt(rt$p.value)
Con el umbral de 0,5, el logit obtiene 0,397 y el KNN 0,368; con el umbral de prevalencia, 0,332 y 0,309. El Kappa disminuye porque aumentan los falsos positivos, pero la exactitud balanceada mejora de forma notable (Tabla 20), pues el modelo detecta mucho mejor los hogares con carro. En ambos umbrales el logit supera ligeramente al KNN.
Los Gráficos 15 y 16 muestran las matrices de confusión del logit y del KNN con el umbral de prevalencia: cuántos hogares de la muestra de prueba clasifica correctamente cada modelo (diagonal) y cuántos confunde.
grafico_cm <- function(cm_tabla, titulo) {
df <- as.data.frame(cm_tabla)
df$Prediction <- factor(df$Prediction, levels = c("1", "0"), labels = c("Con carro", "Sin carro"))
df$Reference <- factor(df$Reference, levels = c("0", "1"), labels = c("Sin carro", "Con carro"))
df$pct <- 100 * df$Freq / ave(df$Freq, df$Reference, FUN = sum)
g <- ggplot(df, aes(x = Reference, y = Prediction, fill = pct,
text = paste0("Clase real: ", Reference, "<br>Clase predicha: ", Prediction,
"<br>Hogares: ", format(Freq, big.mark = ".", decimal.mark = ","),
"<br>", num(pct, 1), " % de la clase real"))) +
geom_tile(color = "white", linewidth = 1.5) +
scale_fill_gradient(low = "#F0EAFB", high = "#6B46C1", limits = c(0, 100)) +
labs(x = "Clase real", y = "Clase predicha", fill = "% de la clase real") +
theme_minimal(base_size = 12) +
theme(panel.grid = element_blank())
etiquetas <- lapply(seq_len(nrow(df)), function(i) list(
x = as.integer(df$Reference[i]), y = as.integer(df$Prediction[i]),
text = paste0("<b>", format(df$Freq[i], big.mark = ".", decimal.mark = ","), "</b><br>",
"<span style='font-size:13px'>", num(df$pct[i], 1), " %</span>"),
showarrow = FALSE, xref = "x", yref = "y",
font = list(size = 20, color = "#2B2250")))
ggplotly(g, tooltip = "text") %>%
layout(title = list(
text = paste0("<b>", titulo, "</b><br><span style='font-size:13px;color:#6A5F94'>",
"Umbral de prevalencia · % respecto a la clase real</span>"),
x = 0.05, xanchor = "left", font = list(color = "#4E2FB0", size = 17)),
annotations = etiquetas,
margin = list(t = 100, b = 90, l = 110, r = 30)) %>%
htmlwidgets::appendContent(htmltools::tags$p(class = "fuente-graf", fuente_graf))
}
grafico_cm(cm_list[[3]]$table, "Gráfico 15. Matriz de confusión del modelo logit")
Fuente: Elaboración propia. ECV, DANE, 2023.
El Gráfico 15 muestra la matriz de confusión del logit con el umbral de prevalencia (0,085). El modelo identifica correctamente 1.788 de los 2.202 hogares con carro (sensibilidad de 81,2 %) y deja sin detectar 414 (18,8 %). Entre los hogares sin carro, clasifica bien 19.119 (especificidad de 80,6 %) y genera 4.601 falsos positivos (19,4 %). Frente al KNN (Gráfico 16), el logit comete 379 falsos positivos menos con una detección de positivos prácticamente igual.
grafico_cm(cm_list[[4]]$table, "Gráfico 16. Matriz de confusión del modelo KNN")
Fuente: Elaboración propia. ECV, DANE, 2023.
El Gráfico 16 muestra la matriz de confusión del KNN con el umbral de prevalencia (0,085). El modelo identifica correctamente 1.783 de los 2.202 hogares con carro (sensibilidad de 81,0 %) y deja sin detectar 419 (19,0 %). Entre los hogares sin carro, clasifica bien 18.740 (especificidad de 79,0 %) y genera 4.980 falsos positivos (21,0 %). Con este umbral el KNN detecta la clase minoritaria, pero con más falsos positivos que el logit.
nom_lg <- paste0("Logit (AUC = ", num(auc_lg), ")")
nom_knn <- paste0("KNN, k = ", k_opt, " (AUC = ", num(auc_knn), ")")
rocdf <- rbind(
data.frame(Modelo = nom_lg, fpr = 1 - roc_lg$specificities, tpr = roc_lg$sensitivities),
data.frame(Modelo = nom_knn, fpr = 1 - roc_knn$specificities, tpr = roc_knn$sensitivities)
) %>%
mutate(fpr = round(fpr, 3), tpr = round(tpr, 3)) %>%
distinct(Modelo, fpr, tpr) %>%
mutate(Modelo = factor(Modelo, levels = c(nom_lg, nom_knn)))
p_roc <- ggplot(rocdf, aes(x = fpr, y = tpr, color = Modelo)) +
geom_line(linewidth = 1.1) +
geom_abline(linetype = "dashed", color = "#AFA4C8") +
scale_color_manual(values = setNames(c("#4E2FB0", "#A48AE0"), c(nom_lg, nom_knn))) +
labs(title = "Gráfico 17. Curvas ROC en la muestra de prueba",
x = "1 - Especificidad", y = "Sensibilidad", color = NULL) +
tema +
theme(legend.position = "bottom")
ggplotly(p_roc) %>%
layout(legend = list(orientation = "h", y = -0.25)) %>%
finalizar(b = 150, subtitulo = "Logit y KNN; la línea punteada es el azar (AUC = 0,5)")
Fuente: Elaboración propia. ECV, DANE, 2023.
El Gráfico 17 compara las curvas ROC del logit y del KNN (k = 41) en la muestra de prueba. Ambas se alejan de la diagonal (azar), lo que indica una buena capacidad para separar los hogares con y sin carro, y se superponen en gran parte del recorrido. El logit alcanza un AUC de 0,891 frente a 0,876 del KNN: la diferencia es pequeña, aunque la prueba de DeLong la señala como estadísticamente significativa.
Comparaciones principales
v <- function(m, u, col) res[res$Modelo == m & grepl(u, res$Umbral, fixed = TRUE), col]
mets <- c("Exactitud", "Sensibilidad", "Especificidad", "Precision", "F1")
tab_gan <- do.call(rbind, lapply(c("0,5", "Prevalencia"), function(u) {
data.frame(Umbral = u, Métrica = c("Exactitud", "Sensibilidad", "Especificidad", "Precisión", "F1"),
Logit = sapply(mets, function(m) v("Logit", u, m)),
KNN = sapply(mets, function(m) v("KNN", u, m)))
}))
tab_gan$`Mejor modelo` <- ifelse(abs(tab_gan$Logit - tab_gan$KNN) < 0.005, "Empate práctico",
ifelse(tab_gan$Logit > tab_gan$KNN, "Logit", "KNN"))
kable(tab_gan, digits = 3, row.names = FALSE, format.args = list(decimal.mark = ","),
caption = "Tabla 21. ¿Qué modelo es mejor en cada métrica? (diferencias menores a 0,005 se consideran empate)")
| Umbral | Métrica | Logit | KNN | Mejor modelo |
|---|---|---|---|---|
| 0,5 | Exactitud | 0,930 | 0,928 | Empate práctico |
| 0,5 | Sensibilidad | 0,308 | 0,282 | Logit |
| 0,5 | Especificidad | 0,988 | 0,988 | Empate práctico |
| 0,5 | Precisión | 0,701 | 0,685 | Logit |
| 0,5 | F1 | 0,428 | 0,400 | Logit |
| Prevalencia | Exactitud | 0,807 | 0,792 | Logit |
| Prevalencia | Sensibilidad | 0,812 | 0,810 | Empate práctico |
| Prevalencia | Especificidad | 0,806 | 0,790 | Logit |
| Prevalencia | Precisión | 0,280 | 0,264 | Logit |
| Prevalencia | F1 | 0,416 | 0,398 | Logit |
La Tabla 21 compara los modelos en diez escenarios (cinco métricas bajo dos umbrales), considerando empate una diferencia menor a 0,005. El logit supera al KNN en siete escenarios, empata en tres y no es superado en ninguno.
Bajo el umbral de 0,5, Logit supera a KNN en sensibilidad (0,308 vs. 0,282), precisión (0,701 vs. 0,685) y F1 (0,428 vs. 0,400), empatando en exactitud y especificidad. Al ajustar por prevalencia, ambos modelos empatan en sensibilidad (0,812 vs. 0,810), pero Logit vuelve a superar en especificidad (0,806), exactitud (0,807), precisión (0,280) y F1 (0,416). En síntesis, el logit resulta preferible: mantiene la misma detección de hogares con carro con menos falsos positivos.
met_long <- res %>%
mutate(Umbral = ifelse(Umbral == "0,5", "Umbral 0,5", "Umbral de prevalencia")) %>%
select(Modelo, Umbral, Exactitud, Sensibilidad, Especificidad, Precision, F1) %>%
pivot_longer(c(Exactitud, Sensibilidad, Especificidad, Precision, F1),
names_to = "Métrica", values_to = "Valor") %>%
mutate(Métrica = recode(Métrica, Precision = "Precisión"),
Métrica = factor(Métrica, levels = c("Exactitud", "Sensibilidad", "Especificidad",
"Precisión", "F1")),
Umbral = factor(Umbral, levels = c("Umbral 0,5", "Umbral de prevalencia")))
g18 <- ggplot(met_long, aes(x = Métrica, y = 100 * Valor, fill = Modelo)) +
geom_col(aes(text = paste0(Modelo, " - ", Métrica, ": ", num(100 * Valor, 1), " %")),
position = position_dodge(width = 0.8), width = 0.7) +
facet_wrap(~ Umbral) +
scale_fill_manual(values = c("Logit" = "#4E2FB0", "KNN" = "#C6B4EE")) +
labs(title = "Gráfico 18. Comparación de métricas de clasificación: logit y KNN",
subtitle = "Muestra de prueba, según el umbral de clasificación",
x = NULL, y = "Porcentaje (%)", fill = NULL) +
expand_limits(y = 105) +
tema +
theme(legend.position = "bottom",
axis.text.x = element_text(angle = 30, hjust = 1))
ggplotly(g18, tooltip = "text") %>%
layout(legend = list(orientation = "h", y = -0.35)) %>%
finalizar(b = 150, subtitulo = "Muestra de prueba, según el umbral de clasificación")
Fuente: Elaboración propia. ECV, DANE, 2023.
Compara el desempeño del logit y del KNN bajo ambos umbrales. El umbral de prevalencia corrige la baja sensibilidad del corte de 0,5 (menor a 31 %) y equilibra la sensibilidad y la especificidad en torno a 80 %. El logit iguala o supera al KNN en todas las métricas, con diferencias pequeñas.
Balance. De las 10 comparaciones métrica-umbral de la tabla, el logit es mejor en 7, el KNN en 0 y hay empate práctico en 3. Además del desempeño, el logit es interpretable (odds ratios con intervalos de confianza), se ajusta y se aplica mucho más rápido y no requiere conservar el conjunto de entrenamiento; el KNN no entrega coeficientes, es sensible a la escala de las variables y al valor de k, y debe comparar cada hogar nuevo con todo el entrenamiento.
Como verificación adicional, se comparan ambos modelos con validación
cruzada de 5 particiones comunes sobre una submuestra de 20.000 hogares
del entrenamiento (para que el KNN sea manejable), usando el ROC como
métrica de selección. Con returnTrain = TRUE cada
fold entrena con el 80 % de la submuestra y evalúa en el 20 %
restante.
set.seed(28)
tr_c <- tr[sample(nrow(tr), 20000), ]
tr_c$y <- factor(ifelse(tr_c$Tiene_carro == 1, "Si", "No"), levels = c("Si", "No"))
folds <- createFolds(tr_c$y, k = 5, returnTrain = TRUE)
ctrl <- trainControl(method = "cv", index = folds, classProbs = TRUE,
summaryFunction = twoClassSummary, savePredictions = "final")
f_cv <- y ~ Log_ingreso + Sin_ingreso_laboral + Capacidad_ingresos + Tamano_hogar + Edad_jefe +
Sexo_jefe + Se_considera_pobre + Tiene_internet + Zona + Educacion_jefe + Region
m_glm <- train(f_cv, data = tr_c, method = "glm", metric = "ROC", trControl = ctrl)
m_knn <- train(f_cv, data = tr_c, method = "knn", metric = "ROC", trControl = ctrl,
preProcess = c("zv", "center", "scale"),
tuneGrid = data.frame(k = c(21, 41, 81, 121)))
cv_res <- resamples(list(Logit = m_glm, KNN = m_knn))
roc_cv <- cv_res$values[, c("Logit~ROC", "KNN~ROC")]
tab_cv <- data.frame(Modelo = c("Logit", paste0("KNN (k = ", m_knn$bestTune$k, ")")),
`ROC medio` = colMeans(roc_cv), `Desviación entre folds` = apply(roc_cv, 2, sd),
check.names = FALSE)
kable(tab_cv, digits = 3, row.names = FALSE, format.args = formato,
caption = "Tabla 22. ROC en validación cruzada (5 folds comunes)")
| Modelo | ROC medio | Desviación entre folds |
|---|---|---|
| Logit | 0,890 | 0,012 |
| KNN (k = 121) | 0,872 | 0,012 |
La Tabla 22 resume el ROC en la validación cruzada de cinco particiones comunes. El logit obtiene un ROC medio de 0,890 y el KNN (k = 121) de 0,872, con la misma desviación entre folds (0,012). Este resultado es consistente con la ventaja del logit observada en la muestra de prueba.
Distinción entre los procedimientos de ajuste del KNN. Se usaron dos procedimientos con propósitos distintos. En el modelo principal, k se seleccionó dividiendo el entrenamiento en ajuste (20.000 hogares) y validación (6.000) sobre una grilla de ocho valores (5 a 301); el mayor AUC se obtuvo con k = 41 (0,8788), y ese modelo, reentrenado con todo el entrenamiento, es el que se evalúa en las Tablas 18 a 21 y los Gráficos 15 a 18. En la validación cruzada complementaria, con cinco particiones comunes sobre una submuestra de 20.000 hogares y una grilla de cuatro valores (21, 41, 81 y 121), el mejor resultado fue k = 121 (ROC medio de 0,8725); esos modelos se usan solo en las Tablas 22 y 23 y los Gráficos 19 y 20. Los valores difieren porque cambian el procedimiento, la grilla y los datos de evaluación, y porque las diferencias de AUC entre valores de k son mínimas (alrededor de 0,002 entre 41 y 121 en ambos procedimientos), por lo que ninguna de las dos selecciones es claramente superior. Por eso los resultados de cada procedimiento se interpretan por separado.
roc_long <- tidyr::pivot_longer(roc_cv, everything(), names_to = "Modelo", values_to = "ROC")
roc_long$Modelo <- sub("~ROC", "", roc_long$Modelo)
roc_long$Modelo <- factor(roc_long$Modelo, levels = c("KNN", "Logit"))
plot_ly(roc_long, x = ~ROC, y = ~Modelo, color = ~Modelo,
colors = c(KNN = "#A48AE0", Logit = "#4E2FB0"),
type = "box", orientation = "h",
boxpoints = "all", jitter = 0.4, pointpos = 0,
marker = list(size = 7, opacity = 0.8),
line = list(width = 2)) %>%
layout(title = list(
text = "<b>Gráfico 19. ROC por fold en la validación cruzada</b><br><sup>Cada punto es uno de los 5 folds.La caja resume su distribución</sup>",
x = 0.5, xanchor = "center", y = 0.95, yanchor = "top",
font = list(color = "#4E2FB0", size = 14)),
font = list(color = "#6A5F94"),
xaxis = list(title = list(text = "<b>ROC (AUC)</b>", standoff = 15),
gridcolor = "#F0EAFA", zeroline = FALSE),
yaxis = list(title = list(text = "<b>Modelo</b>", standoff = 15),
gridcolor = "#F0EAFA", automargin = TRUE),
showlegend = FALSE,
margin = list(t = 110, b = 90, l = 90, r = 30)) %>%
htmlwidgets::appendContent(
htmltools::tags$p(class = "fuente-graf", fuente_graf))
Fuente: Elaboración propia. ECV, DANE, 2023.
El Gráfico 19 muestra el ROC de cada uno de los cinco folds. El logit obtuvo valores entre 0,870 y 0,905, y el KNN entre 0,857 y 0,890. Aunque los rangos se solapan, al comparar fold por fold el logit superó al KNN en los cinco folds, con una diferencia media de 0,017 (calculada con valores sin redondear). La desviación entre folds es similar en ambos modelos (0,012, Tabla 22). Como los folds comparten los mismos datos, este resultado indica consistencia entre particiones, no una prueba formal de superioridad.
res_k <- m_knn$results
g20 <- ggplot(res_k, aes(x = k, y = ROC)) +
geom_line(color = "#A48AE0") +
geom_point(aes(text = paste0("k = ", k, "<br>ROC medio: ", num(ROC, 4))),
color = "#4E2FB0", size = 2.5) +
geom_point(data = subset(res_k, k == m_knn$bestTune$k), color = "#E4572E", size = 4) +
scale_x_continuous(breaks = res_k$k) +
scale_y_continuous(breaks = seq(0.86, 0.875, by = 0.0025), labels = function(x) num(x, 4)) +
labs(title = "Gráfico 20. ROC del KNN en validación cruzada según k",
x = "k", y = "ROC (AUC)") +
tema +
theme(axis.title.y = element_text(margin = margin(r = 25)))
ggplotly(g20, tooltip = "text") %>%
layout(yaxis = list(title = list(standoff = 25))) %>%
finalizar(b = 110, l = 115,
subtitulo = "El punto naranja marca el k con mejor ROC; el eje vertical abarca solo 0,011 de AUC")
Fuente: Elaboración propia. ECV, DANE, 2023.
El Gráfico 20 muestra el ROC del KNN para k = 21, 41, 81 y 121. Aumenta de 0,862 (k = 21) a 0,870 (k = 41) y luego se estabiliza, con el máximo en k = 121 (0,8725, punto naranja). La escala vertical abarca solo 0,011 de AUC, por lo que las diferencias entre valores de k son pequeñas. Que el k óptimo difiera del de la validación simple se explica en la distinción anterior.
te$y <- factor(ifelse(te$Tiene_carro == 1, "Si", "No"), levels = c("Si", "No"))
pred_knn_c <- predict(m_knn, newdata = te)
pred_glm_c <- predict(m_glm, newdata = te)
cm_knn_c <- confusionMatrix(pred_knn_c, te$y, positive = "Si")
cm_glm_c <- confusionMatrix(pred_glm_c, te$y, positive = "Si")
resumen_cm <- data.frame(
Métrica = c("Exactitud", "Kappa", "Sensibilidad", "Especificidad",
"Valor predictivo positivo", "Valor predictivo negativo",
"Exactitud balanceada"),
KNN = c(cm_knn_c$overall["Accuracy"], cm_knn_c$overall["Kappa"],
cm_knn_c$byClass[c("Sensitivity", "Specificity", "Pos Pred Value",
"Neg Pred Value", "Balanced Accuracy")]),
Logit = c(cm_glm_c$overall["Accuracy"], cm_glm_c$overall["Kappa"],
cm_glm_c$byClass[c("Sensitivity", "Specificity", "Pos Pred Value",
"Neg Pred Value", "Balanced Accuracy")])
)
kable(resumen_cm, digits = 3, row.names = FALSE, format.args = formato,
caption = "Tabla 23. Desempeño en la muestra de prueba, modelos de validación cruzada (umbral 0,5)")
| Métrica | KNN | Logit |
|---|---|---|
| Exactitud | 0,925 | 0,930 |
| Kappa | 0,293 | 0,399 |
| Sensibilidad | 0,208 | 0,309 |
| Especificidad | 0,992 | 0,988 |
| Valor predictivo positivo | 0,700 | 0,708 |
| Valor predictivo negativo | 0,931 | 0,939 |
| Exactitud balanceada | 0,600 | 0,648 |
La Tabla 23 evalúa en la muestra de prueba los modelos entrenados con la submuestra de 20.000 hogares, con el umbral de 0,5. El logit obtiene una exactitud balanceada de 0,648 y un Kappa de 0,399, frente a 0,600 y 0,293 del KNN. La diferencia principal está en la sensibilidad: el logit detecta el 30,9 % de los hogares con carro y el KNN solo el 20,8 %. El KNN tiene una especificidad ligeramente mayor (99,2 % frente a 98,8 %), pero porque clasifica casi todos los hogares como «sin carro». En conjunto, el logit supera al KNN en casi todas las métricas.
Los resultados del logit descansan en supuestos que conviene declarar de forma explícita, y algunos se pueden verificar con los datos.
# (a) Logit ponderado por el factor de expansión (reescalado a media 1)
tr$w <- tr$Factor_expansion / mean(tr$Factor_expansion)
fit_w <- glm(formula(fit_lg), data = tr, family = quasibinomial, weights = w)
comp <- data.frame(Variable = names(coef(fit_lg)),
`OR sin pesos` = exp(coef(fit_lg)),
`OR con pesos` = exp(coef(fit_w)),
check.names = FALSE)[-1, ]
comp$Variable <- etiqueta_term(comp$Variable)
mismo_sentido <- mean(sign(log(comp[["OR sin pesos"]])) == sign(log(comp[["OR con pesos"]])))
kable(comp, digits = 2, row.names = FALSE, format.args = formato,
caption = "Tabla 24. Robustez: odds ratios sin y con factores de expansión")
| Variable | OR sin pesos | OR con pesos |
|---|---|---|
| Log del ingreso laboral (por unidad de log) | 2,36 | 2,44 |
| Sin ingreso laboral reportado | 1,59 | 1,98 |
| Ingresos: no alcanza | 0,59 | 0,55 |
| Ingresos: cubre más que el mínimo | 2,25 | 2,25 |
| Tamaño del hogar (por persona) | 1,06 | 1,10 |
| Edad del jefe (por año) | 1,03 | 1,03 |
| Sexo jefe: Hombre | 2,15 | 1,96 |
| Se considera pobre: Sí | 0,42 | 0,38 |
| Tiene internet: Sí | 2,59 | 2,73 |
| Zona: Ciudad capital | 1,10 | 1,18 |
| Educación jefe: Primaria | 2,60 | 2,53 |
| Educación jefe: Secundaria | 3,14 | 3,06 |
| Educación jefe: Media | 4,63 | 4,36 |
| Educación jefe: Superior | 9,71 | 10,38 |
| Educación jefe: Sin dato | 7,03 | 7,04 |
| Región: Bogotá | 1,54 | 1,19 |
| Región: Caribe | 0,95 | 1,08 |
| Región: Central | 1,60 | 1,55 |
| Región: Orinoquía-Amazonía | 0,76 | 1,12 |
| Región: Oriental | 1,88 | 1,58 |
| Región: Pacífica | 1,32 | 1,57 |
| Región: San Andrés | 0,33 | 0,33 |
| Región: Valle del Cauca | 1,35 | 1,35 |
# (b) Término cuadrático para la edad del jefe (centrada en 50 años)
fit_q <- update(fit_lg, . ~ . + I((Edad_jefe - 50)^2))
p_q <- anova(fit_lg, fit_q, test = "Chisq")$`Pr(>Chi)`[2]
prob_q <- as.numeric(predict(fit_q, newdata = te, type = "response"))
auc_q <- as.numeric(auc(roc(yte, prob_q, levels = c(0, 1), direction = "<", quiet = TRUE)))
# (c) Sin valores atípicos: ingreso > 50 millones, jefe < 18 años u hogares de 10 o más personas
atip <- with(tr, (!is.na(Ingreso_laboral_hogar) & Ingreso_laboral_hogar > 5e7) |
Edad_jefe < 18 | Tamano_hogar >= 10)
fit_sa <- update(fit_lg, data = tr[!atip, ])
prob_sa <- as.numeric(predict(fit_sa, newdata = te, type = "response"))
auc_sa <- as.numeric(auc(roc(yte, prob_sa, levels = c(0, 1), direction = "<", quiet = TRUE)))
mismo_sa <- mean(sign(coef(fit_sa)[-1]) == sign(coef(fit_lg)[-1]))
robusto_sa <- mismo_sa >= 0.95 & abs(auc_sa - auc_lg) < 0.01
Multicolinealidad: se revisó en la preparación de los datos (correlación máxima de 0,47 entre variables codificadas); no se observa multicolinealidad severa.
Linealidad en el logit: se asume que las variables continuas (logaritmo del ingreso, edad y tamaño del hogar) tienen un efecto lineal sobre el logit. Para la edad, que aporta mucho al modelo pero con un OR por año cercano a 1, se probó agregar un término cuadrático: mejora de forma estadísticamente significativa el ajuste (p < 0,001) y el AUC en la muestra de prueba pasa de 0,891 a 0,893. Por simplicidad, el modelo principal conserva la edad lineal.
Independencia de las observaciones: no se verificó y probablemente no se cumple del todo. En la segunda etapa de su diseño, la ECV selecciona segmentos o conglomerados de aproximadamente 10 viviendas contiguas y encuesta todas las viviendas, hogares y personas de cada segmento (DANE, 2024a), por lo que hogares del mismo segmento pueden parecerse entre sí, y hay 342 hogares adicionales en viviendas con más de un hogar. En consecuencia, los errores estándar, intervalos de confianza y valores p del logit pueden ser demasiado optimistas y deben leerse con cautela. Además, hogares de un mismo segmento pueden haber quedado repartidos entre entrenamiento y prueba, lo que podría hacer las métricas algo optimistas.
Ponderación: El modelo principal no usa factores de expansión. Como verificación, se ajustó el mismo logit ponderando cada hogar por su factor de expansión (Tabla 24): 91 % de los coeficientes mantiene el mismo sentido. Las variables principales conservan magnitudes similares: educación superior (9,71 frente a 10,38), internet (2,59 frente a 2,73) y logaritmo del ingreso laboral (2,36 frente a 2,44). En cambio, los efectos regionales son sensibles a la ponderación: el OR de Bogotá pasa de 1,54 a 1,19, el de Oriental de 1,88 a 1,58 y el de Pacífica de 1,32 a 1,57, y los de Orinoquía-Amazonía (0,76 a 1,12) y Caribe (0,95 a 1,08) cambian de sentido, aunque el del Caribe no es significativo en el modelo sin pesos. San Andrés (0,33) y Valle del Cauca (1,35) no cambian. Por tanto, los resultados sobre ingreso, educación y percepciones del hogar son robustos, mientras que las diferencias entre regiones deben interpretarse con cautela. Esta comparación sirve solo para los OR: los errores estándar de un modelo ponderado no reflejan el diseño muestral complejo de la encuesta, por lo que no se reportan.
Valores atípicos: se ajustó nuevamente el logit excluyendo del entrenamiento los 191 hogares atípicos (jefe menor de 18 años, 10 o más personas o ingreso laboral superior a 50 millones). Con esa exclusión, 100 % de los coeficientes mantiene el mismo sentido y el AUC en la muestra de prueba prácticamente no cambia (0,891 en ambos casos); por tanto, las conclusiones no cambian de forma apreciable. Esta verificación se hizo solo para el logit.
Para este problema se recomienda el modelo logit. Al comparar los dos modelos en la muestra de prueba, el logit fue igual o mejor que el KNN en todas las métricas. En exactitud hay un empate práctico con el umbral de 0,5 (93,0 % el logit y 92,8 % el KNN), y con el umbral de prevalencia el logit queda un poco arriba (80,7 % frente a 79,2 %). Aun así, la exactitud aporta poca información en este caso, porque un modelo que respondiera siempre “sin carro” acertaría cerca del 91,5 %.
En sensibilidad, con el umbral de 0,5, los dos modelos detectan muy pocos hogares con carro (30,8 % el logit y 28,2 % el KNN). Con el umbral de prevalencia, la sensibilidad sube a cerca del 81 % en ambos (81,2 % y 81,0 %). En cuanto al AUC, el logit separa mejor a los hogares, con 0,891 frente a 0,876 en la muestra de prueba (DeLong p < 0,001) y 0,890 frente a 0,872 en la validación cruzada, con la misma variación entre folds (0,012). En total, el logit fue mejor en 7 de las 10 comparaciones entre métricas y umbrales, empató en 3 y el KNN no ganó ninguna.
La diferencia entre los modelos es pequeña, pero el logit tiene otras ventajas: entrega odds ratios con intervalos de confianza, se ajusta mucho más rápido y no necesita conservar los datos de entrenamiento para clasificar un hogar nuevo. Como su desempeño es igual o ligeramente superior y además permite interpretar las asociaciones, se recomienda el logit. Se recomienda usarlo con el umbral de prevalencia (0,085) y no con 0,5, porque con 0,5 detecta solo el 30,8 % de los hogares con carro y con el de prevalencia, el 81,2 %.
Desbalance de clases. Solo el 14,4 % de los hogares tiene carro (8,5 % en la muestra sin ponderar). Por eso la exactitud engaña: un modelo que dijera siempre “sin carro” acertaría el 91,5 % de las veces sin aprender nada.
Brechas descriptivas. El análisis descriptivo ya mostraba las brechas que después confirmó el modelo. La tenencia de carro sube con la educación del jefe del hogar, de 1,1 % cuando tiene ninguna educación o preescolar a 36,1 % cuando tiene educación superior. También sube con la percepción de ingresos: tiene carro el 56,6 % de los hogares cuyos ingresos cubren más que los gastos mínimos, frente a 16,5 % de los que solo los cubren y 3,3 % de los que no alcanzan. La correlación simple del log del ingreso laboral con tener carro es moderada (0,35, solo hogares con ingreso reportado). El tamaño del hogar tiene un comportamiento distinto: la tenencia sube de 10,6 % en hogares de una persona a 17,2 % en los de cuatro, y después baja (12,6 % con cinco personas y 7,9 % con seis o más), es decir, no es una relación lineal.
Modelo logit. Según la razón de verosimilitud (Tabla 16), las variables que más aportan al ajuste son el ingreso laboral, la educación del jefe, la edad del jefe, el sexo del jefe y el acceso a internet. Un hogar cuyo jefe tiene educación superior tiene 9,71 veces las odds de tener carro frente a uno cuyo jefe no tiene estudios o solo preescolar. Tener internet las multiplica por 2,59, tener jefe hombre por 2,15 y declarar que los ingresos cubren más que los gastos mínimos por 2,25. En cambio, considerarse pobre las reduce (OR de 0,42). El tamaño del hogar (OR de 1,06) y estar en una ciudad capital (OR de 1,10) aportan poco cuando se controla por las demás variables; en el caso del tamaño, probablemente porque su relación con el carro no es lineal (Gráfico 7).
Robustez. Los resultados de ingreso, educación, internet, pobreza percibida y capacidad de ingresos son estables al ponderar con el factor de expansión (Tabla 24). Los efectos regionales no lo son: el OR de Bogotá pasa de 1,54 a 1,19, y los de Orinoquía-Amazonía (0,76 a 1,12) y Caribe (0,95 a 1,08) cambian de sentido. El 91 % de los coeficientes conserva su sentido, pero no necesariamente su magnitud. Al excluir los hogares atípicos, el 100 % mantiene su sentido y el AUC no cambia (0,891).
Comparación de modelos. El logit y el KNN rinden casi igual, con una ventaja leve del logit (AUC de 0,891 frente a 0,876). Lo que sí cambia mucho el resultado es el umbral. Con 0,5 el modelo acierta el 93 %, pero detecta solo el 30,8 % de los hogares con carro. Con el umbral de prevalencia detecta el 81,2 %, pero solo el 28 % de los hogares que predice con carro realmente lo tienen (4.601 falsos positivos frente a 1.788 verdaderos positivos).
Transporte: como el 85,6 % de los hogares no tiene carro y la tenencia se concentra en los hogares con más educación e ingresos, los resultados sugieren que convendría que la planificación del transporte priorice el transporte público y otras formas de movilidad, y no solo la infraestructura para carros.
Equidad: hay brechas por nivel educativo, ingresos y sexo del jefe del hogar, y son estables al ponderar con el factor de expansión. Las diferencias regionales son menos robustas (Tabla 24), con excepción de San Andrés y Valle del Cauca, y el efecto del Caribe no es estadísticamente significativo. Conviene abordar las brechas con políticas de acceso a la movilidad, pero con cuidado: el OR por sexo puede reflejar la composición del hogar (por ejemplo, hogares con un solo adulto o con cónyuge que aporta ingresos) y no un efecto del sexo en sí.
Uso del modelo: sirve para describir perfiles de hogares y priorizar grupos, pero no para tomar decisiones sobre un hogar en particular, porque su precisión es baja (28 % con el umbral de prevalencia, es decir, solo 28 de cada 100 hogares que predice con carro realmente lo tienen).
Para mejorar el estudio: modelar el tamaño del hogar por categorías o con un término cuadrático, porque el Gráfico 7 sugiere que su relación con la tenencia de carro no es lineal; modelar también la edad con un término cuadrático (mejora el ajuste, p < 0,001, aunque el AUC apenas pasa de 0,891 a 0,893); incluir moto y bicicleta; usar la clasificación oficial urbano/rural y el ingreso total del hogar; tener en cuenta los conglomerados de la encuesta en los errores estándar; imputar el ingreso solo con datos de entrenamiento; y probar modelos más flexibles, como árboles o bosques aleatorios.
El logit elegido tiene algunas limitaciones: sus resultados son asociaciones y no causas; supone que la edad, el ingreso y el tamaño del hogar actúan de forma lineal, y para el tamaño el Gráfico 7 sugiere que no es así; no se cumple del todo la independencia entre hogares, por lo que los valores p y los intervalos pueden ser optimistas; la pobreza percibida y la capacidad de ingresos son subjetivas y podrían estar influidas por la propia tenencia de carro, así que parte de su poder predictivo podría ser circular. Además, el 20,7 % de los hogares (17.881) tiene el ingreso imputado, porque su ingreso laboral falta o es igual a cero, y el promedio usado para imputar se calculó con toda la base antes de partirla (una fuga mínima). «Zona» tampoco equivale a urbano/rural. Por último, los modelos no se ponderaron con el factor de expansión, por lo que el umbral de prevalencia (0,085) y la precisión describen la muestra, donde el 8,5 % de los hogares tiene carro, y no la población, donde es el 14,4 %.
El KNN, por su parte, no entrega coeficientes, es sensible a la escala de las variables y al valor de k, y debe comparar cada hogar nuevo con todo el conjunto de entrenamiento. Además, k se eligió con 20.000 hogares, aunque el modelo final usa todo el entrenamiento.
Ambos modelos comparten un límite importante: por el desbalance de clases, su precisión es baja (28 % con el umbral de prevalencia) y los datos describen solo el año 2023.
Sí, en parte.
Primera parte de la pregunta (qué características se asocian con tener carro). Se respondió. Según la razón de verosimilitud (Tabla 16), las variables que más aportan al modelo son el ingreso laboral, la educación del jefe, la edad del jefe, el sexo del jefe y el acceso a internet. Los resultados de ingreso y educación son estables al ponderar con el factor de expansión (Tabla 24). Los efectos de regiones específicas no lo son, así que deben leerse con cautela.
Segunda parte (qué tan bien permiten clasificar a los hogares). Se respondió con matices. Las características ordenan bien a los hogares (AUC de 0,89 en la muestra de prueba y en la validación cruzada), pero para clasificar uno por uno la precisión es baja: solo 28 de cada 100 hogares predichos con carro realmente lo tienen. Con el umbral de 0,5 la precisión sube, pero el modelo detecta solo el 30,8 % de los hogares con carro.
Objetivo general. Se cumplió en lo descriptivo e interpretativo: se identificaron los factores asociados con la regresión logística y se comparó su capacidad de clasificación con la del KNN, con un resultado levemente favorable al logit. Estos resultados describen asociaciones en 2023 y no permiten afirmar causalidad. Además, la pobreza percibida y la capacidad de ingresos son variables subjetivas, y parte de su poder predictivo podría ser circular.
BBVA Research. (2018). Situación automotriz Colombia 2018. https://www.bbvaresearch.com/wp-content/uploads/2018/03/SituacionAutomotriz2018.pdf
Beygelzimer, A., Kakade, S., Langford, J., Arya, S., Mount, D., & Li, S. (2013). FNN: Fast nearest neighbor search algorithms and applications [Paquete de R]. https://cran.r-project.org/package=FNN
Departamento Administrativo Nacional de Estadística. (2024a). Encuesta Nacional de Calidad de Vida 2023: Microdatos anonimizados, diccionario de datos y documentación metodológica . https://microdatos.dane.gov.co/index.php/catalog/827
Departamento Administrativo Nacional de Estadística. (2024b). Presentación de resultados: Encuesta Nacional de Calidad de Vida 2023. https://www.dane.gov.co/files/operaciones/ECV/pres-ECV-2023.pdf
Departamento Administrativo Nacional de Estadística. (2025). Encuesta Nacional de Calidad de Vida 2024: Microdatos anonimizados. https://microdatos.dane.gov.co/index.php/catalog/861
Fawcett, T. (2006). An introduction to ROC analysis. Pattern Recognition Letters, 27(8), 861–874. https://doi.org/10.1016/j.patrec.2005.10.006
Hastie, T., Tibshirani, R., & Friedman, J. (2009). The elements of statistical learning (2.ª ed.). Springer.
Hosmer, D. W., Lemeshow, S., & Sturdivant, R. X. (2013). Applied logistic regression (3.ª ed.). Wiley.
James, G., Witten, D., Hastie, T., & Tibshirani, R. (2021). An introduction to statistical learning: With applications in R (2.ª ed.). Springer.
Kuhn, M. (2008). Building predictive models in R using the caret package. Journal of Statistical Software, 28(5), 1–26. https://doi.org/10.18637/jss.v028.i05
Lobo, J. M., Jiménez-Valverde, A., & Real, R. (2008). AUC: A misleading measure of the performance of predictive distribution models. Global Ecology and Biogeography, 17(2), 145–151. https://doi.org/10.1111/j.1466-8238.2007.00358.x
Paredes Inilupu, D. (2024). Data science con R. https://bookdown.org/dparedesi/data-science-con-r/
R Core Team. (2025). R: A language and environment for statistical computing. R Foundation for Statistical Computing. https://www.R-project.org/
Robin, X., Turck, N., Hainard, A., Tiberti, N., Lisacek, F., Sanchez, J.-C., & Müller, M. (2011). pROC: An open-source package for R and S+ to analyze and compare ROC curves. BMC Bioinformatics, 12, 77. https://doi.org/10.1186/1471-2105-12-77
Sievert, C. (2020). Interactive web-based data visualization with R, plotly, and shiny. CRC Press.
Wickham, H. (2016). ggplot2: Elegant graphics for data analysis. Springer.