Informe del Estudio Econométrico

CONTEXTO Y DATOS

Introducción

La estabilidad financiera y la capacidad de generación de utilidades dentro del sector corporativo constituyen uno de los pilares más relevantes para el desarrollo económico y la sostenibilidad productiva de un país. En Colombia, las empresas operan en un entorno caracterizado por constantes fluctuaciones en las tasas de interés, presiones inflacionarias sobre los costos de producción y variaciones en la demanda agregada. Según los reportes consolidados por la Superintendencia de Sociedades de Colombia, la dinámica empresarial evidencia una marcada heterogeneidad en el desempeño contable de las organizaciones, donde una proporción significativa de firmas enfrenta escenarios de pérdidas operacionales que comprometen su liquidez y supervivencia en el mercado.

En la práctica financiera, la incapacidad de identificar a tiempo los factores de riesgo que llevan a una empresa a registrar pérdidas puede generar graves repercusiones en el sistema económico. Para los establecimientos de crédito y entidades bancarias, una mala evaluación del estado de rentabilidad de un solicitante se traduce en el otorgamiento de préstamos de alto riesgo que aumentan la cartera morosa y la exposición al incumplimiento (default). Por otra parte, para los entes reguladores y de supervisión estatal, no contar con herramientas analíticas oportunas dificulta el diseño de políticas públicas de fomento y la detección preventiva de vulnerabilidades financieras en sectores estratégicos de la producción nacional.

Dentro del contexto contable y corporativo, la clasificación de una empresa como rentable o no rentable representa una etapa crítica para la toma de decisiones estratégicas. Sin embargo, este diagnóstico resulta complejo debido a la gran cantidad de datos financieros que deben analizarse a partir de los estados de situación financiera y de resultados. Variables como el volumen de ingresos operacionales, el nivel de activos, la estructura de pasivos exigibles y el macrosector económico al que pertenece la firma contienen patrones de comportamiento complejos. La correcta interpretación de estos indicadores requiere metodologías cuantitativas rigurosas, dado que una clasificación errónea por parte de un analista o entidad crediticia conlleva consecuencias drásticas: denegar financiamiento a una firma rentable limita su crecimiento operativo, mientras que financiar a una empresa estructuralmente no rentable acelera su insolvencia y destruye valor económico.

Frente a este escenario, surge el interés de implementar herramientas analíticas basadas en econometría y aprendizaje automático que permitan apoyar los procesos de diagnóstico y evaluación del riesgo financiero. Más allá de sustituir el juicio experto de los analistas de riesgo, estos modelos buscan proporcionar una metodología objetiva y reproducible capaz de extraer patrones subyacentes en la información contable y facilitar la discriminación entre empresas rentables y no rentables. De esta forma, la modelación predictiva contribuye a reducir los errores de evaluación y a fortalecer las decisiones de inversión y otorgamiento de crédito en el mercado colombiano.

A partir de este marco conceptual, el presente trabajo tiene como objetivo desarrollar e implementar modelos de clasificación supervisada capaces de predecir la probabilidad de rentabilidad en las empresas colombianas, utilizando para ello información contable y sectorial reportada ante la Superintendencia de Sociedades. Para abordar de manera rigurosa esta problemática, se consolida una muestra representativa de \(50,000\) observaciones contables independientes, sobre la cual se definen las variables explicativas y se evalúan dos algoritmos de aprendizaje supervisado: K-Nearest Neighbors (KNN) y Regresión Logística (LOGIT), con el propósito de comparar su desempeño relativo, analizar su capacidad discriminativa y determinar la herramienta más adecuada para este diagnóstico económico.

Metodología

En la primera fase del estudio se llevó a cabo un proceso sistemático de preparación, limpieza y estructuración de la base de datos de estados financieros proveniente de la Superintendencia de Sociedades. A partir del repositorio empresarial que abarca un universo de \(50,000\) informes corporativos, se ejecutó una selección rigurosa de las variables financieramente más informativas para responder al objetivo de clasificación de la rentabilidad: ingresos operacionales, total de activos, total de pasivos, total de patrimonio, ganancia o pérdida del ejercicio y el macrosector de actividad económica.

Posteriormente, se verificó la consistencia y calidad técnica de la información. Se aplicó un protocolo de depuración enfocado en la verificación de registros con valores faltantes (NA o vacíos) en cualquiera de las variables seleccionadas, evitando sesgos derivados de imputaciones en magnitudes de gran escala. Asimismo, se conservaron las observaciones con reportes en cero (\(0\)) mediante la posterior aplicación de la función de suavizado \(\log(1+x)\) (log1p), consolidando una muestra final de \(50,000\) observaciones independientes con información contable completa y representativa de la estructura productiva colombiana.

El factor o variable de respuesta del modelo se construyó de forma binaria a partir del rubro contable Ganancia (Pérdida): asignando la etiqueta Rentable a las empresas con utilidad neta estrictamente positiva y No_Rentable a aquellas con resultados nulos o pérdidas. Por su parte, las demás variables financieras y sectoriales sirvieron como predictores, al estar directamente vinculadas con la escala de operación, la estructura de financiamiento, la eficiencia en el uso del capital y el riesgo específico según la rama de actividad económica.

Para examinar con rigor el rendimiento de los algoritmos y garantizar que puedan emplearse con fines predictivos en la evaluación del riesgo crediticio o la supervisión financiera real, la base de datos se dividió aleatoriamente bajo un esquema del \(70\%\) para el conjunto de entrenamiento (\(35,000\) observaciones) y del \(30\%\) para el conjunto de prueba o validación (\(15,000\) observaciones). Esta partición permitió que los modelos aprendieran los patrones estructurales de la rentabilidad sobre los datos de entrenamiento y, posteriormente, fueran evaluados en su capacidad de generalización sobre un conjunto de prueba completamente independiente no introducido en la estimación inicial, evitando el sobreajuste (overfitting) de los parámetros.

Descripción de variables

Para construir las especificaciones econométricas y de aprendizaje supervisado, se seleccionaron predictores cuantitativos y cualitativos presentes en los estados financieros que permiten caracterizar la solidez, la escala operativa, el nivel de endeudamiento y la vulnerabilidad sectorial de las empresas colombianas.

El factor de respuesta (\(Y\)) corresponde a la variable dependiente binaria Rentable, la cual representa la clasificación final del desempeño financiero del ejercicio. Se divide en dos clases mutuamente excluyentes: No_Rentable (empresas que registraron utilidades nulas o saldo negativo en su ejercicio, representando un riesgo directo de insolvencia) y Rentable (empresas capaces de generar excedentes netos de capital tras cubrir la totalidad de sus costos, gastos e impuestos).

Las siguientes variables fueron integradas dentro del análisis explicativo y exploratorio:

  • Ingresos (Ingresos Operacionales): Mide el volumen total de ventas o facturación generada por la empresa en el desarrollo de su objeto social primario. Esta variable es un indicador fundamental de la capacidad del negocio para atraer demanda del mercado y generar flujo de caja bruto. En la práctica económica, volúmenes de ingresos elevados permiten absorber de forma más eficiente los costos fijos mediante economías de escala, incrementando sustancialmente la probabilidad de obtener una ganancia neta positiva al cierre del periodo.
  • Activos (Total Activos): Representa el valor monetario total de los recursos, infraestructura, maquinaria, propiedades y derechos bajo el control de la empresa. El tamaño del activo refleja la escala operativa y la capacidad instalada de la firma. Las organizaciones con una base amplia de activos poseen una mayor capacidad de respuesta operativa ante fluctuaciones de mercado y una mayor solidez para respaldar sus operaciones, lo que se asocia con un margen de resistencia superior frente a escenarios de pérdidas.
  • Pasivos (Total Pasivos): Cuantifica el monto total de las obligaciones, deudas y compromisos financieros contraídos por la empresa con terceros (bancos, proveedores, empleados y Estado). Un volumen de pasivo elevado impone una carga fija por concepto de servicio a la deuda y amortización de capital, reduciendo el margen de utilidad disponible. En el modelado probabilístico, el pasivo actúa como la principal variable de vulnerabilidad y riesgo financiero, donde incrementos desproporcionados en el endeudamiento reducen la probabilidad de que la firma registre un saldo de rentabilidad positivo.
  • Patrimonio (Total Patrimonio - Variable Descriptiva): Corresponde a la participación residual en los activos de la empresa una vez deducidos todos sus pasivos. Esta variable se conserva dentro de la investigación para el análisis descriptivo bivariado (diagramas de caja y matrices de correlación), dado que permite visualizar la masa patrimonial neta de las firmas según su estado de rentabilidad. Sin embargo, Patrimonio es excluida explícitamente de la especificación final de los modelos Logit y KNN. Esta decisión responde a que el patrimonio surge de una identidad contable matemática exacta (\(\text{Patrimonio} = \text{Activos} - \text{Pasivos}\)). Incluir simultáneamente los tres rubros generaría una relación de dependencia lineal y multicolinealidad perfecta que impediría la convergencia numérica de la función de verosimilitud en el algoritmo de Regresión Logística.
  • Macrosector (Sector de Actividad Económica): Variable categórica que clasifica a las empresas en ramas productivas clave (Comercio, Construcción, Manufactura, Minero, Servicios y Agropecuario). La inclusión del macrosector es esencial para capturar la heterogeneidad estructural de la economía colombiana, reconociendo que los márgenes de ganancia, las dinámicas de rotación de cartera y la intensidad de capital difieren notablemente entre sectores. Esta variable permite controlar los efectos fijos sectoriales que afectan de forma diferenciada la probabilidad de rentabilidad.

Tomadas en conjunto, estas variables capturan de forma integral la escala, la eficiencia operativa, la estructura de capital y el entorno sectorial de las empresas colombianas, garantizando un marco conceptual sólido y ajustado a la realidad de los datos.

Modelos Utilizados

Modelo de K-Nearest Neighbors (KNN)

El algoritmo de K-Nearest Neighbors (KNN) es un método no paramétrico de aprendizaje supervisado que clasifica una observación en función de la etiqueta predominantemente representada entre sus \(k\) vecinos más cercanos en el espacio de características. Con el propósito de realizar una comparación metodológica rigurosa y directa frente al modelo Logit, el algoritmo KNN fue entrenado exactamente sobre las mismas variables cuantitativas transformadas en logaritmo y estandarizadas mediante \(Z\)-score (Ingresos, Activos y Pasivos). Esta homogenización de escalas resultó indispensable, dado que KNN calcula distancias euclidianas y la presencia de magnitudes dispares o no estandarizadas habría causado que la variable de mayor tamaño absoluto dominara injustificadamente la métrica de distancia.

Para garantizar la estabilidad operativa del algoritmo, se realizó una imputación explícita a la media estandarizada (valor cero) sobre casillas con valores no definidos residuales, previniendo interrupciones por valores faltantes en la matriz de distancias. Adicionalmente, se introdujo un ruido infinitesimal aleatorio (jitter) sobre la matriz de entrenamiento para romper empates exactos en las distancias euclidianas derivados de observaciones con valores contables idénticos o ceros repetidos. La configuración del modelo se fijó en un valor óptimo de vecinos seleccionado mediante validación cruzada (\(10\)-fold CV), estableciendo un balance óptimo entre sesgo y varianza dentro del proceso de votación de clases.

Modelo de Regresión Logística (LOGIT)

La Regresión Logística es un modelo econométrico de respuesta binaria diseñado para estimar la probabilidad condicional de que una observación pertenezca a la clase positiva (\(Y = 1\), equivalente a Rentable) en función de una combinación lineal de predictores. Para abordar la heterogeneidad y las amplitudes de los datos contables, se aplicó inicialmente una transformación logarítmica suavizada mediante la función \(\log(1+x)\) sobre los rubros cuantitativos de Ingresos, Activos y Pasivos. Esta transformación redujo el sesgo de las colas pesadas de la distribución y estabilizó las varianzas operacionales.

Posteriormente, los predictores fueron estandarizados mediante el método \(Z\)-score (centrado en la media y escalado por la desviación estándar) utilizando los parámetros calculados únicamente sobre el conjunto de entrenamiento, evitando cualquier fuga de información (data leakage). Como decisión metodológica central, se excluyó explícitamente la variable Patrimonio del conjunto de predictores para resolver la multicolinealidad perfecta generada por la identidad contable, garantizando la convergencia del algoritmo mediante estimación por máxima verosimilitud en 6 iteraciones de Fisher Scoring. La especificación final incluyó las variables financieras estandarizadas junto con las variables cualitativas indicadoras del Macrosector económico, permitiendo interpretar la magnitud y dirección de los coeficientes estimados sobre la log-probabilidad de rentabilidad.

Evaluación del Desempeño y Criterios de Selección

El rendimiento de ambos algoritmos sobre el conjunto de prueba independiente (\(30\%\) de la muestra) se evaluó mediante una matriz de confusión y un conjunto integral de métricas de clasificación, incluyendo la Exactitud global (Accuracy), la Sensibilidad (Sensitivity), la Especificidad (Specificity) y el Coeficiente Kappa de Cohen, tomando la condición de empresa Rentable como la clase positiva de interés.

En la práctica financiera, la relevancia económica de detectar correctamente las empresas con utilidades verdaderas es crítica: incurrir en un falso negativo (clasificar como no rentable a una empresa financieramente viable) implica la pérdida de oportunidades de negocio y la denegación de financiamiento a firmas con capacidad productiva, mientras que un falso positivo (clasificar como rentable a una firma en pérdidas) expone al sistema crediticio a un alto riesgo de impago y mora. Por esta razón, la evaluación no se limitó al umbral estático por defecto (\(0.50\)), sino que incorporó la calibración de un umbral optimizado (\(0.2216\)) en el modelo Logit para compensar el desbalance muestral, finalizando con el análisis de las curvas ROC (Receiver Operating Characteristic) y la comparación del Área Bajo la Curva (AUC) como criterio definitivo para medir la capacidad de discriminación global de los modelos.

ANALISIS

3.1 Estadísticos Descriptivos de Variables Cuantitativas

# Definición explícita de las variables cuantitativas de análisis
vars_cuant <- c("Ingresos", "Activos", "Pasivos", "Patrimonio")

# Coeficiente de asimetría poblacional (momento de orden 3 estandarizado)
asimetria <- function(x) {
  x <- x[!is.na(x)]
  m3 <- mean((x - mean(x))^3)
  v2 <- mean((x - mean(x))^2)
  if (v2 == 0) return(0)
  m3 / (v2^(1.5))
}

# Resumen estadístico completo para una variable cuantitativa
resumen_cuant <- function(x) {
  c(
    n         = length(x),
    Media     = mean(x),
    Desv_Est  = sd(x),
    Minimo    = min(x),
    Q1        = unname(quantile(x, 0.25)),
    Mediana   = median(x),
    Q3        = unname(quantile(x, 0.75)),
    Maximo    = max(x),
    CV_pct    = (sd(x) / mean(x)) * 100,  # Coeficiente de variación (%)
    Asimetria = asimetria(x)
  )
}

# Generación de la tabla global de estadísticos descriptivos
tabla_desc <- as.data.frame(t(sapply(datos_clasificacion[, vars_cuant], resumen_cuant)))

# Presentación formateada de la Tabla 2
knitr::kable(
  format(round(tabla_desc, 2), big.mark = ","),
  col.names = c("N", "Media", "Desv. Est.", "Mínimo", "Q1", "Mediana", "Q3", "Máximo", "CV (%)", "Asimetría"),
  align     = c("c", "r", "r", "r", "r", "r", "r", "r", "r", "r"),
  caption   = "Tabla 1: Estadísticos Descriptivos Generales de Variables Cuantitativas (Valores en COP)"
) %>% estilo_tabla()
Tabla 1: Estadísticos Descriptivos Generales de Variables Cuantitativas (Valores en COP)
N Media Desv. Est. Mínimo Q1 Mediana Q3 Máximo CV (%) Asimetría
Ingresos 50,000 0.17 1.37 0.01 0.03 0.05 0.10 144.82 797.46 67.97
Activos 50,000 0.23 2.42 0.00 0.02 0.04 0.09 216.85 1,070.95 62.55
Pasivos 50,000 0.12 1.42 0.00 0.01 0.02 0.05 130.54 1,219.87 68.71
Patrimonio 50,000 0.11 1.12 -3.69 0.01 0.01 0.04 91.03 1,025.70 46.59

Para la investigación, esta comprobación empírica justifica de manera rigurosa la estrategia de preparación de datos. Mientras que en la visualización exploratoria bivariada es válido filtrar únicamente observaciones strictly positivas (\(x > 0\)), para la fase de modelado en Regresión Logística y KNN resulta técnicamente indispensable sustituir el logaritmo directo por la función de suavizado \(\log(1+x)\) (log1p) sobre valores no negativos (\(\max(0,x)\)). Esta transformación elimina el riesgo de indeterminación matemática, garantiza la preservación intacta del tamaño muestral (\(N = 50,000\)) y comprime la varianza de las colas sin excluir ninguna observación del análisis econométrico ni del espacio de distancias.

Diagnóstico de Dominios Monetarios y Valores No Positivos

Dado que la transformación logarítmica estándar (\(\log_{10}(x)\)) solo está definida para valores estrictamente positivos (\(x > 0\)), se realiza el conteo e identificación de registros con valores nulos o negativos en el dataset:

# Conteo e identificación de valores no positivos
tabla_ceros <- data.frame(
  Variable  = vars_cuant,
  Negativos = sapply(vars_cuant, function(v) sum(datos_clasificacion[[v]] < 0)),
  Ceros     = sapply(vars_cuant, function(v) sum(datos_clasificacion[[v]] == 0)),
  Positivos = sapply(vars_cuant, function(v) sum(datos_clasificacion[[v]] > 0)),
  row.names = NULL
)
tabla_ceros$Pct_no_positivos <- round(
  100 * (tabla_ceros$Negativos + tabla_ceros$Ceros) / nrow(datos_clasificacion), 2
)

# Presentación formateada de la Tabla 3
knitr::kable(
  tabla_ceros,
  col.names = c("Variable", "Valores < 0", "Valores = 0", "Valores > 0", "% No Positivos"),
  align     = c("l", "c", "c", "c", "c"),
  caption   = "Tabla 2: Evaluación de Frecuencias en el Dominio Monetario por Variable"
) %>% estilo_tabla()
Tabla 2: Evaluación de Frecuencias en el Dominio Monetario por Variable
Variable Valores < 0 Valores = 0 Valores > 0 % No Positivos
Ingresos 0 0 50000 0.00
Activos 0 1429 48571 2.86
Pasivos 0 7402 42598 14.80
Patrimonio 780 9765 39455 21.09

El análisis cuantitativo del dominio numérico refleja que la gran mayoría de los registros en Ingresos Operacionales, Total Activos y Total Pasivos se ubican en el rango estrictamente positivo (\(> 0\)). Sin embargo, la presencia constatada de empresas con ingresos nulos (\(= 0\)), pasivos nulos y patrimonio negativo (\(< 0\)) —producto de pérdidas acumuladas que superan la estructura de capital— impone una restricción matemática directa: la función logarítmica estándar (\(\log_{10}(x)\)) no está definida para valores \(x \le 0\), generando indefiniciones (\(\text{NaN}\) o \(-\infty\)).

Para la investigación, esta comprobación empírica justifica de manera rigurosa la estrategia de preparación de datos. Mientras que en la visualización exploratoria bivariada es válido filtrar únicamente observaciones estrictamente positivas (\(x > 0\)), para la fase de modelado en Regresión Logística y KNN resulta técnicamente indispensable sustituir el logaritmo directo por la función de suavizado \(\log(1 + x)\) (\(\text{log1p}\)) sobre valores no negativos (\(\max(0, x)\)). Esta transformación elimina el riesgo de indeterminación matemática, garantiza la preservación intacta del tamaño muestral (\(N = 29,815\)) y comprime la varianza de las colas sin excluir ninguna observación del análisis econométrico ni del espacio de distancias.

3.2 Estadísticos por Grupo de Diagnóstico

Para evaluar si existen diferencias cuantitativas estructurales según el estado de rentabilidad corporativa, se segmentan los indicadores financieros entre las empresas clasificadas como Rentable y No_Rentable. Asimismo, se analiza la distribución condicional de la rentabilidad a través de los diferentes macrosectores económicos.

# Resumen numérico comparativo entre empresas Rentables y No Rentables
resumen_grupo <- function(x) {
  c(
    n        = length(x),
    Media    = mean(x),
    Mediana  = median(x),
    Desv_Est = sd(x),
    Min      = min(x),
    Max      = max(x)
  )
}

desc_grupo <- do.call(rbind, lapply(vars_cuant, function(v) {
  m <- t(sapply(split(datos_clasificacion[[v]], datos_clasificacion$Rentable), resumen_grupo))
  data.frame(Variable = v, Grupo = rownames(m), m, row.names = NULL)
}))

# Presentación formateada de la Tabla 4
knitr::kable(
  format(desc_grupo, big.mark = ","),
  col.names = c("Variable", "Estado", "N", "Media", "Mediana", "Desv. Est.", "Mínimo", "Máximo"),
  align     = c("l", "c", "c", "r", "r", "r", "r", "r"),
  caption   = "Tabla 3: Comparativo Descriptivo de Variables Cuantitativas según Estado de Rentabilidad (COP)"
) %>% estilo_tabla()
Tabla 3: Comparativo Descriptivo de Variables Cuantitativas según Estado de Rentabilidad (COP)
Variable Estado N Media Mediana Desv. Est. Mínimo Máximo
Ingresos No_Rentable 37,317 0.08213924 0.04 0.3606754 0.01 25.86
Ingresos Rentable 12,683 0.43321139 0.12 2.6216599 0.01 144.82
Activos No_Rentable 37,317 0.07999142 0.03 0.7185994 0.00 102.52
Activos Rentable 12,683 0.65424978 0.13 4.6108633 0.00 216.85
Pasivos No_Rentable 37,317 0.05274942 0.01 0.5984543 0.00 100.20
Pasivos Rentable 12,683 0.30242687 0.05 2.6086750 0.00 130.54
Patrimonio No_Rentable 37,317 0.02689873 0.01 0.2595698 -3.69 27.58
Patrimonio Rentable 12,683 0.35182134 0.06 2.1632797 -1.49 91.03

La desagregación de las variables cuantitativas según la condición de rentabilidad expone patrones diferenciadores en la escala de las organizaciones. Al contrastar las métricas entre grupos, se observa que las empresas clasificadas como Rentable mantienen medianas y promedios aritméticos sensiblemente superiores en Ingresos Operacionales y Total Activos en comparación con la categoría No_Rentable. Esta diferencia en la tendencia central refleja que las firmas que logran generar utilidad neta positiva operan, en promedio, sobre una mayor base de infraestructura y volumen de facturación.

No obstante, las mediciones de dispersión indican un solapamiento considerable en los rangos intercuartílicos y extremos de ambos grupos. Para Total Pasivos, las diferencias en la mediana entre firmas rentables y no rentables se reducen de forma sustancial, evidenciando que el volumen absoluto de obligaciones financieras no constituye un factor discriminativo aislable por sí solo. Desde la perspectiva del modelado econométrico y de aprendizaje automático, este comportamiento confirma que la separación entre clases no responde a un único umbral lineal sobre una variable, sino a la interacción multidimensional entre la masa operativa y el apalancamiento. Para el algoritmo KNN, este solapamiento en las medianas exige la estandarización previa para evitar distorsiones por varianza, mientras que en la Regresión Logística fundamenta la inclusión conjunta de activos y pasivos para aislar el efecto del tamaño relativo del negocio.

# Análisis de rentabilidad relativa por Macrosector
tabla_cont  <- table(datos_clasificacion$Macrosector, datos_clasificacion$Rentable)
prop_sector <- round(prop.table(tabla_cont, margin = 1) * 100, 2)

tabla_sector <- data.frame(
  Macrosector  = rownames(tabla_cont),
  No_Rentable  = as.numeric(tabla_cont[, "No_Rentable"]),
  Rentable     = as.numeric(tabla_cont[, "Rentable"]),
  Pct_Rentable = as.numeric(prop_sector[, "Rentable"]),
  stringsAsFactors = FALSE
) %>% arrange(desc(Pct_Rentable))

# Presentación formateada de la Tabla 4
knitr::kable(
  tabla_sector,
  col.names = c("Macrosector", "No Rentable (N)", "Rentable (N)", "% Empresas Rentables"),
  align     = c("l", "c", "c", "c"),
  caption   = "Tabla 4: Distribución Frecuencial y Rentabilidad Relativa por Macrosector Económico"
) %>% estilo_tabla()
Tabla 4: Distribución Frecuencial y Rentabilidad Relativa por Macrosector Económico
Macrosector No Rentable (N) Rentable (N) % Empresas Rentables
MINERO 534 413 43.61
SERVICIOS 10710 4979 31.74
MANUFACTURA 7092 2941 29.31
AGROPECUARIO 1576 566 26.42
CONSTRUCCIÓN 2933 921 23.90
COMERCIO 14472 2863 16.52
# Visualización: Porcentaje de empresas rentables por macrosector
g_sector <- ggplot(tabla_sector, aes(x = reorder(Macrosector, Pct_Rentable), y = Pct_Rentable)) +
  geom_col(fill = "#377EB8", width = 0.6) +
  geom_text(aes(label = paste0(Pct_Rentable, "%")), hjust = -0.15, size = 3.8, fontface = "bold", color = "#151E3D") +
  coord_flip() +
  ylim(0, max(tabla_sector$Pct_Rentable) * 1.18) +
  theme_minimal(base_size = 13) +
  theme(
    plot.title   = element_text(face = "bold", color = "#151E3D", size = 14, hjust = 0.5),
    axis.title   = element_text(face = "bold", color = "#151E3D"),
    axis.text    = element_text(color = "#151E3D", fontface = "bold"),
    panel.grid.major.x = element_blank()
  ) +
  labs(
    title = "Proporción de Empresas Rentables por Macrosector",
    x     = NULL,
    y     = "% de Empresas Rentables en el Sector"
  )

print(g_sector)

La evaluación de la rentabilidad condicional a nivel de macrosector revela una marcada heterogeneidad en la probabilidad a priori de generar utilidades según el entorno de actividad económica. La Tabla 5 y la Figura 3 demuestran que la tasa de conversión a firmas rentables difiere sensiblemente entre sectores, reflejando distintas estructuras de costos fijos, requerimientos de capital de trabajo y márgenes de operación inherentes a cada industria.

Para el propósito de la investigación, esta variabilidad sectorial justifica la integración de la variable categórica Macrosector dentro del espacio de atributos de los clasificadores. En la Regresión Logística, su incorporación actúa como un control cualitativo mediante variables dummy, ajustando el intercepto base del logit según el riesgo estructural de la industria; en el modelo KNN, aunque el algoritmo opera primariamente sobre el espacio métrico continuo de las variables financieras estandarizadas, la caracterización sectorial confirma que las observaciones no se distribuyen de manera homogénea en la muestra, reforzando la necesidad de validar la sensibilidad diagnóstica mediante particionamiento estratificado.

Distribución y Frecuencia de la Variable Respuesta (Y)

Este análisis exploratorio inicia con el estudio de la variable dependiente binaria Rentable, la cual sintetiza el desempeño contable neto al cierre del ejercicio financiero.

A continuación, se presenta la distribución frecuencial y porcentual obtenida tras el proceso de depuración de la muestra:

# Frecuencia absoluta y relativa de la variable objetivo
tabla_y <- table(datos_clasificacion$Rentable)
prop_y  <- prop.table(tabla_y) * 100

df_y <- data.frame(
  Estado = c("No_Rentable", "Rentable"),
  Frecuencia = as.numeric(tabla_y),
  Porcentaje = round(as.numeric(prop_y), 2)
)

# Tabla
#Carga de librería para tablas estilizadas
library(kableExtra)

# 1. Tabulación y frecuencias numéricas puras
tabla_y <- table(datos_clasificacion$Rentable)
prop_y  <- prop.table(tabla_y) * 100

# Se mantiene Frecuencia como NUMÉRICA para que el gráfico no falle
df_y <- data.frame(
  Estado     = names(tabla_y), 
  Frecuencia = as.numeric(tabla_y),
  Porcentaje = as.numeric(prop_y)
)

# 2. Creación de tabla formateada dinámicamente
df_y_tabla <- df_y
df_y_tabla$Frecuencia <- format(df_y_tabla$Frecuencia, big.mark = ",")
df_y_tabla$Porcentaje <- paste0(round(df_y_tabla$Porcentaje, 2), "%")

knitr::kable(
  df_y_tabla, 
  col.names = c("Estado de Rentabilidad", "N° de Empresas", "Porcentaje (%)"),
  align     = c("l", "c", "c"),
  caption   = "Tabla 5: Distribución Frecuencial de la Variable Objetivo"
) %>%
  kable_styling(
    bootstrap_options = c("striped", "hover", "condensed", "responsive"),
    full_width        = FALSE,
    position          = "center",
    font_size         = 16
  ) %>%
  row_spec(0, background = "#151E3D", color = "white", bold = TRUE) %>%
  column_spec(1, bold = TRUE, color = "#151E3D") %>%
  column_spec(2, bold = TRUE) %>%
  column_spec(3, bold = TRUE, color = "#2C3E4C")
Tabla 5: Distribución Frecuencial de la Variable Objetivo
Estado de Rentabilidad N° de Empresas Porcentaje (%)
No_Rentable 37,317 74.63%
Rentable 12,683 25.37%

Distribución Frecuencial de la Variable Objetivo y reemplázalos por estos:La estructura tabular de la variable dependiente \(Y\) evidencia una composición heterogénea dentro de la muestra depurada de \(50,000\) observaciones. La categoría No_Rentable concentra la masa principal con \(37,317\) organizaciones (equivalentes al \(74.63\%\) del total), mientras que la categoría Rentable registra \(12,683\) firmas (que representan el \(25.37\%\) restante). Desde la perspectiva del análisis financiero corporativo, este resultado refleja que la generación de excedentes netos de capital tras cubrir la totalidad de costos operacionales, gastos financieros y obligaciones fiscales no constituye el comportamiento predeterminado en el tejido productivo colombiano. Por el contrario, aproximadamente tres de cada cuatro empresas operan en márgenes nulos o de pérdida neta. Esta asimetría estructural fundamenta la relevancia de investigar la escala de activos y el volumen de facturación como determinantes críticos para alcanzar el umbral de rentabilidad.

Para representar de forma visual la proporción de cada categoría dentro de la muestra depurada, se genera el gráfico de barras correspondiente.La visualización de las frecuencias absolutas ilustra gráficamente la disparidad entre los dos grupos de estudio, estableciendo una relación muestral cercana a \(3:1\) a favor de las empresas no rentables. En el ámbito del análisis de datos y la formulación de modelos de clasificación, esta configuración inicial plantea un desafío metodológico relevante respecto a la distribución de la información. Dado que la categoría No_Rentable representa la gran mayoría de las observaciones (\(74.63\%\)), el espacio de entrenamiento se encuentra densamente poblado por registros de firmas en pérdida o neutralidad operativa. Desde el punto de vista conceptual, esta desproporción implica que cualquier algoritmo de clasificación supervisada enfrentará una mayor exposición a la clase dominante, lo que requiere un tratamiento cuidadoso durante la fase de modelación para evitar que el aprendizaje priorice la identificación de la categoría mayoritaria en detrimento de la detección de las empresas rentables.

Para representar de forma visual la proporción de cada categoría dentro de la muestra depurada, se genera el gráfico de barras correspondiente.

# Gráfico de barras bivariado para la variable respuesta
g1_y <- ggplot(df_y, aes(x = Estado, y = Frecuencia, fill = Estado)) +
  geom_bar(stat = "identity", width = 0.5, show.legend = FALSE) +
  geom_text(
    aes(label = paste0(round(Porcentaje, 2), "% (n = ", format(Frecuencia, big.mark = ","), ")")), 
    vjust = -0.5, 
    fontface = "bold", 
    size = 4.5, 
    color = "#151E3D"
  ) +
  scale_fill_manual(values = c("No_Rentable" = "#8B2252", "Rentable" = "#377EB8")) +
  scale_y_continuous(limits = c(0, max(df_y$Frecuencia) * 1.15), labels = scales::comma) +
  theme_minimal(base_size = 13) +
  theme(
    plot.title   = element_text(face = "bold", color = "#151E3D", size = 15, hjust = 0.5),
    axis.title   = element_text(face = "bold", color = "#151E3D"),
    axis.text    = element_text(color = "#151E3D", fontface = "bold"),
    panel.grid.major.x = element_blank()
  ) +
  labs(
    title = "Distribución de Empresas según Rentabilidad (Y)",
    x     = "Estado de Rentabilidad",
    y     = "Número de Empresas"
  )

print(g1_y)

La visualización de las frecuencias absolutas ilustra gráficamente la disparidad entre los dos grupos de estudio, estableciendo una relación muestral cercana a \(3:1\) a favor de las empresas no rentables. En el ámbito del análisis de datos y la formulación de modelos de clasificación, esta configuración inicial plantea un desafío metodológico relevante respecto a la distribución de la información.

Dado que la categoría No_Rentable representa la gran mayoría de las observaciones (\(74.64\%\)), el espacio de entrenamiento se encuentra densamente poblado por registros de firmas en pérdida o neutralidad operativa. Desde el punto de vista conceptual, esta desproporción implica que cualquier algoritmo de clasificación supervisada enfrentará una mayor exposición a la clase dominante, lo que requiere un tratamiento cuidadoso durante la fase de modelación para evitar que el aprendizaje priorice la identificación de la categoría mayoritaria en detrimento de la detección de las empresas rentables.

En consecuencia, el diagnóstico exploratorio de la variable objetivo evidencia la necesidad de examinar posteriormente la relación bivariada entre los estados de rentabilidad y las variables explicativas cuantitativas (Ingresos, Activos y Pasivos), con el fin de identificar si existen diferencias de escala o dispersión que permitan discriminar con claridad a las firmas pertenecientes a la clase minoritaria (Rentable).

Distribución de Densidad Bivariada de las Variables Explicativas Cuantitativas

Para examinar el comportamiento de los predictores cuantitativos (Ingresos, Activos y Pasivos) y su capacidad preliminar para discriminar la rentabilidad empresarial, se evalúan sus distribuciones continuas. Dado que las magnitudes financieras corporativas presentan diferencias de escala de varios órdenes de magnitud y una marcada asimetría positiva (sesgo a la derecha), se aplica una transformación en escala logarítmica (\(\log_{10}\)) sobre las observaciones con valores positivos para facilitar la representación gráfica y la comparación de densidades.

Gráficos de Densidad e Histogramas Bivariados

Distribución de Ingresos Operacionales
# Carga de librería requerida para arreglos multipanel
library(gridExtra)

# 1. Densidad e Histograma para Ingresos Operacionales
h_ing <- ggplot(subset(datos_clasificacion, Ingresos > 0), 
                aes(x = Ingresos, fill = Rentable, color = Rentable)) +
  geom_histogram(aes(y = ..density..), alpha = 0.4, position = "identity", bins = 30) +
  geom_density(alpha = 0.2, size = 1) +
  scale_x_log10() +
  theme_minimal() +
  scale_fill_manual(values = c("#8B2252", "#377EB8")) +
  scale_color_manual(values = c("#8B2252", "#377EB8")) +
  labs(title = "Densidad de Ingresos Operacionales", x = "Ingresos (Log10)", y = "Densidad")
print(h_ing)

En su escala original, la variable Ingresos Operacionales presenta una distribución fuertemente asimétrica hacia la derecha, con una alta concentración de frecuencias en niveles bajos y una cola larga que abarca pocas empresas con volúmenes de facturación extraordinarios. Tras la transformación logarítmica, la distribución adquiere una forma aproximadamente unimodal y acampanada, extendiéndose de manera continua a lo largo del rango de escala.

Al comparar las subpoblaciones, la curva de densidad del grupo Rentable presenta un desplazamiento claro hacia la derecha respecto al grupo No_Rentable, evidenciando que las empresas con mayor volumen de ventas tienen una mayor concentración poblacional en la categoría de utilidad neta positiva. Sin embargo, existe una zona de solapamiento considerable en los tramos intermedios de la distribución. Para la investigación, este comportamiento implica que los ingresos son un predictor discriminativo relevante pero no suficiente por sí solo: en la Regresión Logística, su inclusión aporta una señal directa sobre la escala del negocio, mientras que en KNN contribuye a separar las observaciones en el espacio multidimensional cuando se evalúa conjuntamente con la estructura de costos y activos.

Distribución de Total Activos
# Carga de librería requerida para arreglos multipanel
library(gridExtra)


# 2. Densidad e Histograma para Total Activos
h_act <- ggplot(subset(datos_clasificacion, Activos > 0), 
                aes(x = Activos, fill = Rentable, color = Rentable)) +
  geom_histogram(aes(y = ..density..), alpha = 0.4, position = "identity", bins = 30) +
  geom_density(alpha = 0.2, size = 1) +
  scale_x_log10() +
  theme_minimal() +
  scale_fill_manual(values = c("#8B2252", "#2F4F4F")) +
  scale_color_manual(values = c("#8B2252", "#2F4F4F")) +
  labs(title = "Densidad de Total Activos", x = "Activos (Log10)", y = "Densidad")
print(h_act )

La distribución de Total Activos exhibe una marcada asimetría positiva en niveles brutos, la cual se suaviza mediante la escala logarítmica hacia una forma unimodal con dispersión amplia. Visualmente, es la variable cuantitativa que muestra la separación más definida entre las modas de ambos grupos diagnósticos, con la distribución de las firmas Rentable visiblemente desplazada hacia valores superiores de patrimonio e infraestructura.

Esta menor intersección relativa convierte a Total Activos en una de las variables con mayor capacidad discriminativa individual dentro del estudio. En el contexto del modelado, esta clara separación en los centros de masa favorece al algoritmo KNN al establecer fronteras de distancia más definidas en el eje del tamaño de la empresa, mientras que en la Regresión Logística se perfila como un predictor estructural clave para capturar el efecto de la escala sobre la probabilidad de rentabilidad.

Distribución de Total Pasivos
# Carga de librería requerida para arreglos multipanel
library(gridExtra)
# 3. Densidad e Histograma para Total Pasivos
h_pas <- ggplot(subset(datos_clasificacion, Pasivos > 0), 
                aes(x = Pasivos, fill = Rentable, color = Rentable)) +
  geom_histogram(aes(y = ..density..), alpha = 0.4, position = "identity", bins = 30) +
  geom_density(alpha = 0.2, size = 1) +
  scale_x_log10() +
  theme_minimal() +
  scale_fill_manual(values = c("#8B2252", "#2F4F4F")) +
  scale_color_manual(values = c("#8B2252", "#2F4F4F")) +
  labs(title = "Densidad de Total Pasivos", x = "Pasivos (Log10)", y = "Densidad")
print(h_pas)

La variable Total Pasivos presenta un comportamiento unimodal en escala logarítmica, caracterizado por el mayor grado de solapamiento o superposición entre los grupos Rentable y No_Rentable. A diferencia de Ingresos y Activos, las curvas de ambos grupos comparten casi la misma ubicación central y dispersión, diferenciándose únicamente por un ligero desplazamiento de la cola superior en las empresas rentables.

Desde la perspectiva del análisis exploratorio, el alto solapamiento indica que el volumen total de obligaciones o deuda, evaluado de manera aislada, es la variable visualmente menos discriminativa del conjunto. Sin embargo, esta aparente limitación constituye su mayor valor para la investigación: al medir una dimensión financiera distinta (el apalancamiento y riesgo exigible) que no es idéntica a la masa operativa de los activos, añade información no redundante al sistema. En el modelo Logit, su inclusión permite controlar el riesgo financiero manteniendo constantes la escala y la facturación, mientras que en KNN aporta una dimensión adicional indispensable para la métrica de distancia euclidiana.

En síntesis, las distribuciones confirman la presencia de asimetría positiva y diferencias de dispersión en todas las variables, ratificando la necesidad metodológica de aplicar la transformación logarítmica y la estandarización Z-score para homogeneizar las escalas antes del entrenamiento de los clasificadores.

3.3 Variable Categórica: Macrosector

library(kableExtra)

knitr::kable(tabla_sector,
             format.args = list(big.mark = ","),
             align   = c("l", "r", "r", "r"),
             caption = "Empresas por macrosector y porcentaje de rentables") %>%
  kable_styling(bootstrap_options = c("hover"),
                full_width = TRUE,
                position   = "center",
                font_size  = 14) %>%
  row_spec(0, bold = TRUE, color = "white", background = "#1F4E79")
Empresas por macrosector y porcentaje de rentables
Macrosector No_Rentable Rentable Pct_Rentable
MINERO 534 413 43.61
SERVICIOS 10,710 4,979 31.74
MANUFACTURA 7,092 2,941 29.31
AGROPECUARIO 1,576 566 26.42
CONSTRUCCIÓN 2,933 921 23.90
COMERCIO 14,472 2,863 16.52

La muestra tiene 50.000 empresas, de las cuales el 25,37 % es rentable (ganancia mayor que cero), y la tabla muestra que esa proporción cambia mucho según el macrosector. Minero es el más rentable (43,61 %), seguido por Servicios (31,74 %) y Manufactura (29,31 %), que superan el promedio. Agropecuario (26,42 %) queda casi igual a la media, y Construcción (23,90 %) y Comercio (16,52 %) quedan por debajo. La brecha entre el mejor y el peor sector es de 27,09 puntos porcentuales. Comercio, el sector con más empresas (17.335), concentra además el 38,78 % de las no rentables. La tabla muestra una asociación, no una causa. Aun así, esa diferencia entre sectores justifica incluir el macrosector como variable explicativa en el modelo Logit.

library(plotly)
g_sector <- ggplot(tabla_sector,
                   aes(x = reorder(Macrosector, Pct_Rentable), y = Pct_Rentable)) +
  geom_col(fill = "#377EB8") +
  geom_text(aes(label = paste0(Pct_Rentable, "%")), hjust = -0.1, size = 3.5) +
  coord_flip() +
  ylim(0, max(tabla_sector$Pct_Rentable) * 1.15) +
  theme_minimal() +
  labs(title = "Porcentaje de empresas rentables por macrosector",
       x = NULL, y = "% de empresas rentables")
ggplotly(g_sector)

El gráfico de barras es la representación visual de la tabla anterior, donde el sector Minero encabeza la clasificación con 43,61 %, seguido por Servicios (31,74 %) y Manufactura (29,31 %), sectores que superan el 25,37 % de rentabilidad de la muestra completa. Agropecuario (26,42 %) se mantiene prácticamente en el nivel general, mientras que Construcción (23,90 %) y Comercio (16,52 %) se ubican por debajo de él. La diferencia entre la barra más larga y la más corta equivale a 27,09 puntos porcentuales, lo que evidencia una dispersión considerable entre sectores.

BOXPLOT

3.3.1Diagrama de Cajas: Ingresos Operacionales según Rentabilidad

# Carga de librería para gráficos interactivos en RMD
library(plotly)

# Generación del gráfico base ggplot2 con paleta corporativa
g2_ing <- ggplot(subset(datos_clasificacion, !is.na(Ingresos) & Ingresos > 0),
                 aes(x = Rentable, y = Ingresos, fill = Rentable)) +
  geom_boxplot(alpha = 0.7, outlier.colour = "#8B2252", outlier.size = 1.2) +
  scale_y_log10(labels = scales::comma) +
  scale_fill_manual(values = c("No_Rentable" = "#8B2252", "Rentable" = "#2F4F4F")) +
  theme_minimal(base_size = 13) +
  theme(
    plot.title   = element_text(face = "bold", color = "#151E3D", size = 14, hjust = 0.5),
    axis.title   = element_text(face = "bold", color = "#151E3D"),
    axis.text    = element_text(color = "#151E3D", fontface = "bold"),
    legend.position = "none",
    panel.grid.major.x = element_blank()
  ) +
  labs(
    title = "Figura 3A: Distribución de Ingresos Operacionales según Rentabilidad",
    x     = "Estado de Rentabilidad",
    y     = "Ingresos Operacionales (Escala Log10)"
  )

# Renderizado interactivo compatible con R Markdown
ggplotly(g2_ing)

Para analizar cómo influye el nivel de ingresos en la rentabilidad de las organizaciones, se examina la distribución de la variable Ingresos Operacionales (en escala logarítmica \(\log_{10}\)) comparando las empresas No_Rentable frente a las Rentable.

El diagrama de cajas refleja que las empresas no rentables presentan su rango intercuartílico (\(IQR\)) ubicado en el tramo inferior de la escala, con una mediana claramente desplazada hacia valores menores de facturación. Por su parte, las empresas rentables exhiben su caja (\(Q_1\) a \(Q_3\)) ubicada en un nivel sensiblemente superior, registrando una mediana más elevada y un límite superior del bigote que se extiende hacia volúmenes de ventas considerablemente mayores.

El solapamiento entre los rangos centrales de ambas cajas es sumamente reducido, dado que el límite superior de la caja no rentable coincide prácticamente con el límite inferior (\(Q_1\)) de la caja rentable. Para la investigación, este comportamiento confirma que los Ingresos Operacionales son un indicador con una alta capacidad de separación bivariada entre ambos grupos. En el modelo KNN, esta diferenciación facilita la delimitación de fronteras de distancia en el espacio de atributos, mientras que en la Regresión Logística aporta un predictor de gran peso discriminativo.

3.3.2 Diagrama de Cajas: Total Activos por Rentabilidad

# Código base ggplot2 para Activos
g2_act <- ggplot(subset(datos_clasificacion, !is.na(Activos) & Activos > 0),
                 aes(x = Rentable, y = Activos, fill = Rentable)) +
  geom_boxplot(alpha = 0.7, outlier.colour = "#8B2252", outlier.size = 1.2) +
  scale_y_log10(labels = scales::comma) +
  scale_fill_manual(values = c("No_Rentable" = "#8B2252", "Rentable" = "#2F4F4F")) +
  theme_minimal(base_size = 13) +
  theme(
    plot.title      = element_text(face = "bold", color = "#151E3D", size = 14, hjust = 0.5),
    axis.title      = element_text(face = "bold", color = "#151E3D"),
    axis.text       = element_text(color = "#151E3D", fontface = "bold"),
    legend.position = "none",
    panel.grid.major.x = element_blank()
  ) +
  labs(
    title = "Figura 3B: Distribución de Total Activos según Rentabilidad",
    x     = "Estado de Rentabilidad",
    y     = "Total Activos (Escala Log10)"
  )

# Renderizado del gráfico interactivo
ggplotly(g2_act)

El comportamiento de Total Activos revela una separación estructural drástica en la capacidad patrimonial de las empresas según su estado de rentabilidad. La caja del grupo rentable se ubica en un nivel significativamente superior, con un primer cuartil (\(Q_1\)) que apenas entra en contacto con el límite superior (\(Q_3\)) del grupo no rentable. Esta disposición indica que la masa crítica de infraestructura, maquinaria, propiedades y capital de trabajo requerida para operar de manera rentable se sitúa en una escala cuantitativa sustancialmente mayor que la de aquellas firmas que registran pérdidas.

Los bigotes del grupo rentable se extienden sobre un rango de magnitud excepcionalmente amplio, alcanzando valores superiores en la escala logarítmica. Para la investigación, la longitud de este bigote superior no es un simple detalle geométrico: demuestra que las empresas viables no pertenecen a un único tamaño corporativo, sino que conviven pymes rentables con grandes conglomerados de alta capacidad operativa. En contraste, el grupo no rentable presenta un bigote inferior comprimido y una acumulación importante de puntos atípicos (outliers) hacia valores altos. Esto significa que, aunque existen empresas con grandes masas de activos que entran en estado de no rentabilidad (casos de subutilización de capacidad instalada o activos improductivos), la regla general en el mercado es que la insuficiencia de activos fijos actúa como una barrera estructural para la generación de utilidades.

3.3.3 Diagrama de Cajas: Total Pasivos por Rentabilidad

# Código base ggplot2 para Pasivos
g2_pas <- ggplot(subset(datos_clasificacion, !is.na(Pasivos) & Pasivos > 0),
                 aes(x = Rentable, y = Pasivos, fill = Rentable)) +
  geom_boxplot(alpha = 0.7, outlier.colour = "#8B2252", outlier.size = 1.2) +
  scale_y_log10(labels = scales::comma) +
  scale_fill_manual(values = c("No_Rentable" = "#8B2252", "Rentable" = "#2F4F4F")) +
  theme_minimal(base_size = 13) +
  theme(
    plot.title      = element_text(face = "bold", color = "#151E3D", size = 14, hjust = 0.5),
    axis.title      = element_text(face = "bold", color = "#151E3D"),
    axis.text       = element_text(color = "#151E3D", fontface = "bold"),
    legend.position = "none",
    panel.grid.major.x = element_blank()
  ) +
  labs(
    title = "Figura 3C: Distribución de Total Pasivos según Rentabilidad",
    x     = "Estado de Rentabilidad",
    y     = "Total Pasivos (Escala Log10)"
  )

# Renderizado del gráfico interactivo
ggplotly(g2_pas)

Para examinar la relación entre la estructura de endeudamiento y la rentabilidad, se evalúa el comportamiento de la variable Total Pasivos (en escala logarítmica \(\log_{10}\)) en las dos categorías diagnósticas.

El gráfico evidencia diferencias claras en la capacidad de financiamiento exigible. Las empresas no rentables presentan un rango intercuartílico ubicado en niveles más reducidos y una mediana inferior. En contraste, las empresas rentables exhiben una caja ubicada en un nivel más alto y una mediana superior, reflejando que las firmas en estado de ganancia sostienen mayores volúmenes de pasivos, comportamiento asociado a una mayor escala operativa y mayor acceso al crédito comercial y bancario.

A diferencia de Ingresos y Activos, en Total Pasivos se registra un solapamiento parcial entre los rangos centrales de ambas distribuciones. Sin embargo, la mediana del grupo rentable supera el límite del percentil 75 (\(Q_3\)) del grupo no rentable, lo que demuestra que, aunque el endeudamiento tiene una mayor variabilidad (reflejada en la mayor longitud de la caja y bigotes en las empresas rentables), continúa aportando señal discriminativa. La presencia de observaciones atípicas por encima de los bigotes confirma la existencia de empresas con pasivos excepcionales que no distorsionan la tendencia central gracias a la compresión logarítmica.

3.3.4 Diagrama de Cajas: Total Patrimonio por Rentabilidad y Justificación de Exclusión

# Código base ggplot2 para Patrimonio
g2_pat <- ggplot(subset(datos_clasificacion, !is.na(Patrimonio) & Patrimonio > 0),
                 aes(x = Rentable, y = Patrimonio, fill = Rentable)) +
  geom_boxplot(alpha = 0.7, outlier.colour = "#8B2252", outlier.size = 1.2) +
  scale_y_log10(labels = scales::comma) +
  scale_fill_manual(values = c("No_Rentable" = "#8B2252", "Rentable" = "#2F4F4F")) +
  theme_minimal(base_size = 13) +
  theme(
    plot.title      = element_text(face = "bold", color = "#151E3D", size = 14, hjust = 0.5),
    axis.title      = element_text(face = "bold", color = "#151E3D"),
    axis.text       = element_text(color = "#151E3D", fontface = "bold"),
    legend.position = "none",
    panel.grid.major.x = element_blank()
  ) +
  labs(
    title = "Figura 3D: Distribución de Total Patrimonio según Rentabilidad (Exploratorio)",
    x     = "Estado de Rentabilidad",
    y     = "Total Patrimonio (Escala Log10)"
  )

# Renderizado del gráfico interactivo
ggplotly(g2_pat)

El Total Patrimonio refleja la brecha más pronunciada en la salud financiera de las organizaciones. La caja de las empresas no rentables se encuentra comprimida en los niveles más bajos de la escala, con su mediana situada en la base misma del rango intercuartílico. Por el contrario, el grupo rentable posiciona su centro de masa en una franja muy superior, registrando una disparidad que supera ampliamente a las observadas en ingresos y pasivos.

Esta concentración cercana a cero en el grupo no rentable responde al deterioro acumulado del capital social: las pérdidas consecutivas absorben las reservas y erosionan la participación de los socios, dejando a la empresa en una posición de extrema vulnerabilidad o patrimonio neto negativo. En las empresas rentables, la amplitud de la caja y de los bigotes evidencia la retención continua de utilidades que alimenta el patrimonio con el paso del tiempo. Así, la ubicación del patrimonio en este gráfico es una manifestación directa del historial acumulado de desempeño: las empresas no rentables sufren la destrucción sistemática de su patrimonio, mientras que las rentables consolidan su estructura de capital.

Justificación Econométrica de Exclusión

Desde la perspectiva contable y financiera, el Total Patrimonio no constituye un recurso operativo independiente dentro de la estructura de la firma, sino que representa el valor residual de las propiedades y derechos de la empresa una vez deducidas todas sus obligaciones con terceros. Esta naturaleza financiera se traduce en una identidad algebraica exacta donde el patrimonio equivale conceptualmente a la diferencia directa entre el Total Activos y el Total Pasivos (\(\text{Patrimonio} = \text{Activos} - \text{Pasivos}\)). En el marco metodológico del proyecto, cuyo objetivo es identificar los factores determinantes de la rentabilidad a partir de la masa operativa y la estructura de financiamiento, la inclusión simultánea de los tres rubros contables generaría una redundancia de información cuantitativa por combinación lineal perfecta.

Dado que los activos reflejan la capacidad productiva instalada y los pasivos capturan el nivel de endeudamiento y riesgo financiero exigible, la variable patrimonio no aporta variabilidad explicativa autónoma que no se encuentre ya contenida de forma implícita en la interacción entre la masa de inversión y la deuda. Por tanto, para mantener una especificación parsimoniosa y metodológicamente sólida, el estudio conserva la variable en este apartado únicamente para la caracterización patrimonial del sector, excluyéndola de la matriz final de atributos donde Ingresos Operacionales, Total Activos y Total Pasivos asumen la representación analítica del comportamiento corporativo.

3.6 Análisis de Valores Atípicos (Outliers)

Para complementar el estudio descriptivo y evaluar la presencia de observaciones inusuales en la muestra empresarial colombiana, se applied el criterio del Rango Intercuartílico (\(\text{IQR} = Q_3 - Q_1\)). Este procedimiento delimita las observaciones que distan de la tendencia central y permite entender cómo la escala financiera de cada firma impacta la clasificación entre empresas Rentable y No_Rentable.

# Carga de librerías para tablas elegantes
library(knitr)
library(kableExtra)
library(dplyr)
library(ggplot2)

# Función auxiliar para aplicar el estilo corporativo azul de la imagen
estilo_tabla_azul <- function(kable_input) {
  kable_input %>%
    kable_styling(
      bootstrap_options = c("striped", "hover", "condensed"),
      full_width = FALSE,
      position = "center"
    ) %>%
    row_spec(0, background = "#151E3D", color = "white", bold = TRUE)
}
# 1. Identificación de atípicos según la regla IQR

contar_atipicos <- function(x) {
  x_clean <- x[!is.na(x)]
  q       <- quantile(x_clean, c(0.25, 0.75))
  iqr     <- q[[2]] - q[[1]]
  li      <- q[[1]] - 1.5 * iqr
  ls      <- q[[2]] + 1.5 * iqr
  c(
    n            = length(x_clean),
    Limite_inf   = li,
    Limite_sup   = ls,
    Atipicos_inf = sum(x_clean < li),
    Atipicos_sup = sum(x_clean > ls),
    Pct_atipicos = 100 * mean(x_clean < li | x_clean > ls)
  )
}

# Tabla 1: Escala Original
tabla_atip_orig <- as.data.frame(t(sapply(datos_clasificacion[, vars_cuant], contar_atipicos)))
df_orig <- data.frame(
  Variable = rownames(tabla_atip_orig),
  N = format(round(tabla_atip_orig$n), big.mark = ","),
  `Atípicos Inf.` = format(round(tabla_atip_orig$Atipicos_inf), big.mark = ","),
  `Atípicos Sup.` = format(round(tabla_atip_orig$Atipicos_sup), big.mark = ","),
  `Total Atípicos` = format(round(tabla_atip_orig$Atipicos_inf + tabla_atip_orig$Atipicos_sup), big.mark = ","),
  `% Atípicos` = paste0(round(tabla_atip_orig$Pct_atipicos, 2), "%"),
  check.names = FALSE
)

kable(df_orig, caption = "Tabla 6: Identificación de Valores Atípicos en Escala Monetaria Original (IQR)", align = c("l", "c", "c", "c", "c", "c")) %>%
  estilo_tabla_azul()
Tabla 6: Identificación de Valores Atípicos en Escala Monetaria Original (IQR)
Variable N Atípicos Inf. Atípicos Sup. Total Atípicos % Atípicos
Ingresos 50,000 0 6,361 6,361 12.72%
Activos 50,000 0 6,930 6,930 13.86%
Pasivos 50,000 0 6,172 6,172 12.34%
Patrimonio 50,000 271 6,837 7,108 14.22%

Los resultados consolidados en la Tabla 6 muestran un panorama marcadamente diferenciado en la masa financiera del conjunto de datos. La variable Total Pasivos se posiciona como una de las métricas con menor nivel de atipicidad relativa, registrando \(6,172\) observaciones atípicas que representan el \(12.34\%\) de la muestra total (\(N = 50,000\)). Este resultado confirma que el endeudamiento se encuentra ajustado de forma proporcional al tamaño operativo de las unidades productivas, evidenciando un acceso al crédito comercial y bancario regularizado.

Por su parte, la estructura de capital reflejada en Total Patrimonio y la infraestructura operativa representada por Total Activos exhiben concentraciones de \(7,108\) casos (\(14.22\%\)) y \(6,930\) casos (\(13.86\%\)) respectivamente. En el caso específico de los activos, estos valores extremos se ubican exclusivamente en la cola derecha de la distribución, respondiendo a la presencia de grandes corporaciones y conglomerados industriales cuyas inversiones en maquinaria, propiedad y planta superan ampliamente la media del sector.

Lejos de constituir un error de reporte ante la Superintendencia de Sociedades, estas observaciones representan la cúspide de la capacidad instalada en Colombia, por lo que su eliminación menoscabaría la representatividad del análisis. Finalmente, la variable Ingresos Operacionales registra \(6,361\) valores atípicos (\(12.72\%\)). Esta marcada dispersión en las ventas refleja una asimetría estructural en los mercados colombianos, donde una fracción reducida de corporaciones logra concentrar volúmenes de facturación masivos frente a la masa dominante de pymes.

3.6.2 Desagregación por Grupo de Rentabilidad e Impacto Investigativo

library(ggplot2)

atipicos_por_grupo <- do.call(rbind, lapply(vars_cuant, function(v) {
  x   <- datos_clasificacion[[v]]
  g   <- datos_clasificacion$Rentable
  pos <- !is.na(x) & x > 0
  lx  <- log10(x[pos])
  gg  <- g[pos]
  
  q   <- quantile(lx, c(0.25, 0.75))
  iqr <- q[[2]] - q[[1]]
  es_atipico <- lx < (q[[1]] - 1.5 * iqr) | lx > (q[[2]] + 1.5 * iqr)
  
  data.frame(
    Variable = v,
    Grupo    = levels(gg),
    Empresas = as.numeric(table(gg)),
    Atipicos = as.numeric(tapply(es_atipico, gg, sum)),
    stringsAsFactors = FALSE
  )
}))

atipicos_por_grupo$Pct_atipicos <- round(
  100 * atipicos_por_grupo$Atipicos / atipicos_por_grupo$Empresas, 2
)

g_atip <- ggplot(atipicos_por_grupo, aes(x = Variable, y = Pct_atipicos, fill = Grupo)) +
  geom_col(position = "dodge", width = 0.6) +
  scale_fill_manual(values = c("No_Rentable" = "#8B2252", "Rentable" = "#2F4F4F")) +
  theme_minimal(base_size = 13) +
  theme(
    plot.title      = element_text(face = "bold", color = "#151E3D", size = 14, hjust = 0.5),
    axis.title      = element_text(face = "bold", color = "#151E3D"),
    axis.text       = element_text(color = "#151E3D", fontface = "bold"),
    legend.position = "top",
    legend.title    = element_blank(),
    panel.grid.major.x = element_blank()
  ) +
  labs(
    title = "Figura 4: Porcentaje de Valores Atípicos por Variable y Grupo de Rentabilidad",
    x     = "Variable Financiera",
    y     = "% de Empresas con Valor Atípico"
  )

print(g_atip)

Al desglosar la frecuencia de observaciones atípicas según la condición de rentabilidad en la Figura 4, se evidencia una asimetría crítica para los objetivos del estudio. En el grupo de empresas clasificado como No_Rentable (clase mayoritaria), la proporción de atípicos en escala logarítmica resulta reducida, oscilando en niveles moderados a lo largo de los cuatro rubros analizados. Por el contrario, en la categoría Rentable (clase minoritaria), la prevalencia de casos extremos experimenta un incremento sustancial en el porcentaje relativo sobre su categoría.

Para la investigación, este contraste cuantitativo demuestra que los valores atípicos no representan ruido estocástico aleatorio, sino que están directamente asociados a la capacidad de generar utilidad neta positiva. El marcado aumento en el porcentaje de atípicos dentro de las firmas viables indica que la escala de operación actúa como un facilitador de rentabilidad: las empresas que logran consolidar masas altas de activos y facturación aprovechan economías de escala y posiciones dominantes en el mercado para absorber sus costos fijos y asegurar márgenes positivos. En consecuencia, estos registros atípicos constituyen información contable altamente discriminativa que debe ser preservada dentro del espacio de entrenamiento de los modelos predictivos.

3.6.3 Evaluación Profunda de la Transformación Logarítmica (\(\text{log1p}\))

vars_modelos <- c("Ingresos", "Activos", "Pasivos")

efecto_log <- do.call(rbind, lapply(vars_modelos, function(v) {
  x  <- datos_clasificacion[[v]]
  xl <- log1p(pmax(0, x, na.rm = TRUE))
  data.frame(
    Variable              = v,
    Asimetria_original    = round(asimetria(x), 2),
    Asimetria_log1p       = round(asimetria(xl), 2),
    Pct_atipicos_original = paste0(round(contar_atipicos(x)[["Pct_atipicos"]], 2), "%"),
    Pct_atipicos_log1p    = paste0(round(contar_atipicos(xl)[["Pct_atipicos"]], 2), "%")
  )
}))

kable(efecto_log, col.names = c("Variable", "Asimetría Orig.", "Asimetría Log1p", "% Atípicos Orig.", "% Atípicos Log1p"), 
      caption = "Tabla 7: Evaluación Comparativa del Impacto de la Transformación Log1p", align = c("l", "c", "c", "c", "c")) %>%
  estilo_tabla_azul()
Tabla 7: Evaluación Comparativa del Impacto de la Transformación Log1p
Variable Asimetría Orig. Asimetría Log1p % Atípicos Orig. % Atípicos Log1p
Ingresos 67.97 6.69 12.72% 12.18%
Activos 62.55 6.70 13.86% 13.32%
Pasivos 68.71 8.61 12.34% 12.34%

La evaluación cuantitativa documentada en la Tabla 7 demuestra la efectividad técnica de la transformación de suavizado \(\log(1+x)\) (\(\text{log1p}\)) sobre las tres variables cuantitativas seleccionadas para la especificación final de los clasificadores (Ingresos, Activos y Pasivos). En la escala monetaria original (COP), los coeficientes de asimetría registran valores marcadamente elevados —alcanzando \(67.97\) en Ingresos, \(62.55\) en Activos y \(68.71\) en Pasivos—, lo que ratifica la presencia de colas hiper-extendidas hacia la derecha provocadas por las grandes corporaciones. Al aplicar la función \(\text{log1p}\), la asimetría experimenta un colapso drástico de casi un orden de magnitud, contrayéndose a \(6.69\), \(6.70\) y \(8.61\) respectivamente. Paralelamente, la proporción de valores atípicos bajo la regla IQR en escala transformada se estabiliza alrededor del \(12.18\%\) en Ingresos, \(13.32\%\) en Activos y \(12.34\%\) en Pasivos.

Desde la perspectiva metodológica y práctica del proyecto, estos resultados justifican plenamente la adopción del tratamiento \(\text{log1p}\). En primer lugar, la contracción de la asimetría comprime las colas pesadas de la distribución sin alterar el orden de magnitud relativo ni la jerarquía contable de las empresas. En segundo lugar, al aplicar \(\log(1+x)\) en lugar del logaritmo estándar \(\log_{10}(x)\), se soluciona la restricción del dominio numérico sobre observaciones con valores nulos (\(0\)), asegurando la conservación intacta del tamaño muestral total (\(N = 50,000\)) sin recurrir a la eliminación arbitraria de registros. Finalmente, este suavizado prepara adecuadamente la estructura de datos para la posterior estandarización Z-score, garantizando que en el algoritmo KNN las distancias euclidianas no queden dominadas por la varianza de las grandes empresas, y que en la Regresión Logística se reduzca el apalancamiento sobre los coeficientes de la función logit.

MODELOS

4.1.1 Entrenamiento del Modelo KNN y Selección del Hiperparámetro \(k\) Óptimo

Para evaluar la capacidad predictiva del algoritmo K-Nearest Neighbors (KNN) en la identificación de empresas rentables dentro del mercado colombiano, se ejecutó un proceso de validación cruzada sobre el conjunto de entrenamiento (\(N_{train} = 35,000\)). El objetivo central de esta fase consiste en determinar el número óptimo de vecinos (\(k\)) que maximice la exactitud del clasificador (Accuracy) y el coeficiente Kappa de Cohen, equilibrando la sensibilidad del modelo sin caer en sesgos hacia la clase mayoritaria.

# Carga de librerías para modelación supervisada y evaluación
library(dplyr)
library(ggplot2)
library(caret)
library(class)
library(knitr)
library(kableExtra)

# 1. Definición estricta de variables de modelación (excluyendo Patrimonio)
vars_modelos <- c("Ingresos", "Activos", "Pasivos")

# 2. División estratificada de datos (Train 70% / Test 30%)
set.seed(123)
index <- createDataPartition(datos_clasificacion$Rentable, p = 0.70, list = FALSE)

train_raw <- datos_clasificacion[index, ]
test_raw  <- datos_clasificacion[-index, ]

# Alineación estricta de niveles categóricos de Macrosector
test_raw$Macrosector <- factor(test_raw$Macrosector, levels = levels(train_raw$Macrosector))

# 3. Transformación y estandarización Z-score para el espacio métrico de KNN
train_log <- train_raw
test_log  <- test_raw


train_log[, vars_modelos] <- log1p(pmax(0, train_raw[, vars_modelos], na.rm = TRUE))
test_log[, vars_modelos]  <- log1p(pmax(0, test_raw[, vars_modelos], na.rm = TRUE))

train_logit <- train_log
test_logit  <- test_log

pp_knn <- preProcess(train_log[, vars_modelos], method = c("center", "scale"))

train_knn <- predict(pp_knn, train_log[, vars_modelos])
test_knn  <- predict(pp_knn, test_log[, vars_modelos])

train_knn[is.na(train_knn)] <- 0
test_knn[is.na(test_knn)]   <- 0

set.seed(123)
train_knn_jitter <- jitter(as.matrix(train_knn), factor = 0.001)

train_cl <- factor(train_log$Rentable, levels = c("No_Rentable", "Rentable"))
real_knn <- factor(test_log$Rentable,  levels = c("No_Rentable", "Rentable"))

# 4. Evaluación del Hiperparámetro k (Validación Cruzada 10-fold)
set.seed(123)
control_knn <- trainControl(method = "cv", number = 10)
grid_knn    <- data.frame(k = seq(1, 25, by = 2))

modelo_knn_tune <- train(
  x         = train_knn_jitter,
  y         = train_cl,
  method    = "knn",
  trControl = control_knn,
  tuneGrid  = grid_knn,
  metric    = "Accuracy"
)

# Visualización del proceso de optimización de k
g_k_opt <- ggplot(modelo_knn_tune$results, aes(x = k, y = Accuracy)) +
  geom_line(color = "#377EB8", size = 1.2) +
  geom_point(color = "#151E3D", size = 3) +
  geom_vline(xintercept = modelo_knn_tune$bestTune$k, linetype = "dashed", color = "#8B2252", size = 1) +
  theme_minimal(base_size = 13) +
  theme(
    plot.title      = element_text(face = "bold", color = "#151E3D", size = 14, hjust = 0.5),
    axis.title      = element_text(face = "bold", color = "#151E3D"),
    axis.text       = element_text(color = "#151E3D", fontface = "bold"),
    panel.grid.major.x = element_blank()
  ) +
  labs(
    title = "Figura 5: Optimización del Hiperparámetro k mediante Validación Cruzada",
    x     = "Número de Vecinos (k)",
    y     = "Exactitud Global (Accuracy)"
  )

print(g_k_opt)

# 5. Ajuste del modelo final con k óptimo
pred_knn <- knn(
  train   = train_knn_jitter,
  test    = test_knn,
  cl      = train_cl,
  k       = modelo_knn_tune$bestTune$k,
  prob    = TRUE,
  use.all = FALSE
)

# Tabla resumen del particionamiento muestral
resumen_particion <- data.frame(
  Conjunto             = c("Entrenamiento (Train 70%)", "Evaluación (Test 30%)", "Muestra Total (N)"),
  Observaciones        = c(nrow(train_raw), nrow(test_raw), nrow(datos_clasificacion)),
  Proporcion           = c("70.00%", "30.00%", "100.00%"),
  `Pct. Rentables`     = c(
    paste0(round(100 * mean(train_raw$Rentable == "Rentable"), 2), "%"),
    paste0(round(100 * mean(test_raw$Rentable == "Rentable"), 2), "%"),
    paste0(round(100 * mean(datos_clasificacion$Rentable == "Rentable"), 2), "%")
  ),
  `Pct. No Rentables`  = c(
    paste0(round(100 * mean(train_raw$Rentable == "No_Rentable"), 2), "%"),
    paste0(round(100 * mean(test_raw$Rentable == "No_Rentable"), 2), "%"),
    paste0(round(100 * mean(datos_clasificacion$Rentable == "No_Rentable"), 2), "%")
  ),
  check.names = FALSE
)

kable(
  resumen_particion, 
  caption = "Tabla 8: Estructura del Particionamiento Muestral Estratificado y Mantenimiento del Balance de Clases",
  align   = c("l", "c", "c", "c", "c")
) %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed"), full_width = FALSE, position = "center") %>%
  row_spec(0, background = "#151E3D", color = "white", bold = TRUE) 
Tabla 8: Estructura del Particionamiento Muestral Estratificado y Mantenimiento del Balance de Clases
Conjunto Observaciones Proporcion Pct. Rentables Pct. No Rentables
Entrenamiento (Train 70%) 35001 70.00% 25.37% 74.63%
Evaluación (Test 30%) 14999 30.00% 25.36% 74.64%
Muestra Total (N) 50000 100.00% 25.37% 74.63%

Durante el proceso de entrenamiento se evaluaron \(35,000\) observaciones a través de una validación cruzada de 10 pliegues (10-fold CV) sobre el subconjunto de entrenamiento (\(70\%\) de la muestra) para determinar el número óptimo de vecinos (\(k\)) en la grilla \(k \in \{1, 3, 5, \dots, 25\}\). Como se ilustra en la Figura 5, la función de búsqueda algorítmica identificó que la exactitud global (Accuracy) alcanza su máximo absoluto en \(k = 17\) (marcado por la línea vertical discontinua), registrando un desempeño superior al \(82.7\%\).

La trayectoria de la curva muestra una mejora rápida y continua en la capacidad de clasificación desde \(k = 1\) hasta \(k = 17\). En el contexto de los datos financieros empresariales, un \(k = 1\) o valores excesivamente bajos provocan una alta sensibilidad al ruido individual de los datos (sobreajuste local). A medida que \(k\) se incrementa hacia \(17\), la votación por vecindad logra promediar y estabilizar el espacio métrico de ingresos, activos y pasivos, capturando los patrones generales de comportamiento de las firmas sin saturarse. Adicionalmente, el hecho de que la curva alcance su meseta en \(k = 17\) y comience a estabilizarse suavemente hacia \(k = 25\) confirma que se alcanzó un equilibrio óptimo entre el sesgo y la varianza, evitando tanto el sobreajuste de vecindades demasiado reducidas como la dilución de la señal en vecindades hiper-extendidas.

4.1.2 Evaluación del Modelo

Para determinar la capacidad de generalización del algoritmo K-Nearest Neighbors (\(k = 17\)) sobre registros no observados en el entrenamiento, se evaluó la matriz de confusión sobre el conjunto de validación independiente (\(N_{test} = 14,999\)).

# Carga de librerías necesarias
library(caret)
library(knitr)
library(kableExtra)

# 1. Matriz de confusión sobre el conjunto de evaluación (Test)
cm_knn <- confusionMatrix(pred_knn, real_knn, positive = "Rentable")

# 2. Generación de la Tabla de Matriz de Confusión (Estilo Azul Corporativo)
df_cm_knn <- data.frame(
  `Matriz de Confusión` = c("Predice No_Rentable", "Predice Rentable"),
  `Real No_Rentable`     = c(cm_knn$table["No_Rentable", "No_Rentable"], cm_knn$table["Rentable", "No_Rentable"]),
  `Real Rentable`        = c(cm_knn$table["No_Rentable", "Rentable"], cm_knn$table["Rentable", "Rentable"]),
  check.names            = FALSE
)

kable(
  df_cm_knn,
  caption = "Tabla 10: Matriz de Confusión del Clasificador KNN (k = 17) sobre la Muestra de Validación",
  align   = c("l", "c", "c")
) %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed"), full_width = FALSE, position = "center") %>%
  row_spec(0, background = "#151E3D", color = "white", bold = TRUE)
Tabla 10: Matriz de Confusión del Clasificador KNN (k = 17) sobre la Muestra de Validación
Matriz de Confusión Real No_Rentable Real Rentable
Predice No_Rentable 10176 1495
Predice Rentable 1019 2309

Como se presenta en la Tabla 10, el modelo KNN (k = 17) clasificó correctamente 10.176 empresas no rentables y 2.309 rentables. Los errores fueron 1.495 falsos negativos (empresas rentables clasificadas como no rentables) y 1.019 falsos positivos (empresas no rentables clasificadas como rentables). Los falsos positivos exponen a una entidad de crédito al impago, y los falsos negativos implican oportunidades de financiamiento perdidas. Con KNN hay más falsos negativos que falsos positivos.

# 3. Generación de la Tabla de Métricas de Evaluación
metricas_knn <- data.frame(
  Métrica = c(
    "Accuracy (Exactitud Global)",
    "Intervalo de Confianza 95%",
    "P-Value (Acc > NIR)",
    "Kappa de Cohen",
    "P-valor Test de McNemar",
    "Sensibilidad (Sensitivity)",
    "Especificidad (Specificity)",
    "Valor Predictivo Positivo (Pos Pred Value)",
    "Valor Predictivo Negativo (Neg Pred Value)",
    "Prevalencia (Prevalence)",
    "Tasa de Detección (Detection Rate)",
    "Prevalencia de Detección (Detection Prevalence)",
    "Exactitud Balanceada (Balanced Accuracy)"
  ),
  Valor = c(
    format(round(cm_knn$overall["Accuracy"], 4), nsmall = 4),
    paste0("(", round(cm_knn$overall["AccuracyLower"], 4), ", ", round(cm_knn$overall["AccuracyUpper"], 4), ")"),
    "< 2.2e-16",
    format(round(cm_knn$overall["Kappa"], 4), nsmall = 4),
    "< 2.2e-16",
    format(round(cm_knn$byClass["Sensitivity"], 4), nsmall = 4),
    format(round(cm_knn$byClass["Specificity"], 4), nsmall = 4),
    format(round(cm_knn$byClass["Pos Pred Value"], 4), nsmall = 4),
    format(round(cm_knn$byClass["Neg Pred Value"], 4), nsmall = 4),
    format(round(cm_knn$byClass["Prevalence"], 4), nsmall = 4),
    format(round(cm_knn$byClass["Detection Rate"], 4), nsmall = 4),
    format(round(cm_knn$byClass["Detection Prevalence"], 4), nsmall = 4),
    format(round(cm_knn$byClass["Balanced Accuracy"], 4), nsmall = 4)
  ),
  check.names = FALSE
)

kable(
  metricas_knn,
  caption = "Tabla 11: Métricas de Desempeño Diagnóstico del Modelo KNN sobre Datos Out-of-Sample",
  align   = c("l", "c")
) %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed"), full_width = FALSE, position = "center") %>%
  row_spec(0, background = "#151E3D", color = "white", bold = TRUE)
Tabla 11: Métricas de Desempeño Diagnóstico del Modelo KNN sobre Datos Out-of-Sample
Métrica Valor
Accuracy (Exactitud Global) 0.8324
Intervalo de Confianza 95% (0.8263, 0.8383)
P-Value (Acc > NIR) < 2.2e-16
Kappa de Cohen 0.5382
P-valor Test de McNemar < 2.2e-16
Sensibilidad (Sensitivity) 0.6070
Especificidad (Specificity) 0.9090
Valor Predictivo Positivo (Pos Pred Value) 0.6938
Valor Predictivo Negativo (Neg Pred Value) 0.8719
Prevalencia (Prevalence) 0.2536
Tasa de Detección (Detection Rate) 0.1539
Prevalencia de Detección (Detection Prevalence) 0.2219
Exactitud Balanceada (Balanced Accuracy) 0.7580

Como se detalla en la Tabla 11, el clasificador KNN alcanzó una exactitud global del 83,24 % (12.485 aciertos sobre 14.999 empresas de prueba), con un intervalo de confianza del 95 % de 82,63 % a 83,83 %. Esta exactitud supera de forma significativa la tasa de no información, es decir, clasificar todo como no rentable (74,64 %; p < 2,2×10⁻¹⁶). El Kappa de Cohen es de 0,5382, una concordancia moderada una vez descontado el azar. La prueba de McNemar (p < 2,2×10⁻¹⁶) indica que los errores no se reparten de forma simétrica: hay más falsos negativos (1.495) que falsos positivos (1.019).

Por clase, la sensibilidad es de 60,70 % (2.309 de las 3.804 empresas rentables de la prueba) y la especificidad de 90,90 % (10.176 de las 11.195 no rentables). Cuando KNN predice “Rentable” acierta el 69,38 % de las veces (valor predictivo positivo), y cuando predice “No_Rentable” acierta el 87,19 % (valor predictivo negativo). La exactitud balanceada es de 75,80 %.

La combinación de alta especificidad y sensibilidad moderada indica un clasificador conservador: reconoce bien a las empresas no rentables, pero deja pasar cerca de 4 de cada 10 empresas rentables. Estas métricas describen la muestra de prueba y no garantizan el mismo desempeño en otros periodos.

4.2 Modelo de Regresión Logística (LOGIT)

Como segunda alternativa metodológica, se implementó un modelo de Regresión Logística (LOGIT) para estimar la probabilidad de que una firma sea Rentable en función de sus magnitudes financieras clave. A diferencia del enfoque no paramétrico de KNN —basado exclusivamente en la cercanía de observaciones—, el modelo LOGIT calcula una relación funcional explícita mediante la función logit \(\ln\left(\frac{p}{1-p}\right)\). Esto permite cuantificar el efecto marginal y la dirección de influencia que ejercen los activos, pasivos e ingresos sobre la viabilidad económica de la organización.

Para garantizar un marco estricto de comparabilidad entre ambos algoritmos, el ajuste del modelo logístico se realizó utilizando exactamente la misma partición de datos (\(70\%\) entrenamiento y \(30\%\) prueba) y las variables explicativas transformadas mediante \(\text{log1p}\).

# Carga de librerías
library(knitr)
library(kableExtra)
library(broom)

# 1. Ajuste del modelo de Regresión Logística sobre el subconjunto de entrenamiento
modelo_logit <- glm(
  Rentable ~ Ingresos + Activos + Pasivos + Macrosector,
  data   = train_logit,
  family = binomial(link = "logit")
)

# 2. Extracción de coeficientes, errores estándar y cálculo de Odds Ratios
resumen_logit <- tidy(modelo_logit, exponentiate = FALSE)
or_logit      <- tidy(modelo_logit, exponentiate = TRUE)

tabla_coef_logit <- data.frame(
  Término      = resumen_logit$term,
  Estimación   = round(resumen_logit$estimate, 4),
  `Error Est.` = round(resumen_logit$std.error, 4),
  `Estadístico z` = round(resumen_logit$statistic, 4),
  `p-valor`    = ifelse(resumen_logit$p.value < 0.0001, "< 0.0001", round(resumen_logit$p.value, 4)),
  `Odds Ratio` = round(or_logit$estimate, 4),
  check.names  = FALSE
)

kable(
  tabla_coef_logit,
  caption = "Tabla 12: Coeficientes Estimados y Odds Ratios del Modelo de Regresión Logística (LOGIT)",
  align   = c("l", "c", "c", "c", "c", "c")
) %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed"), full_width = FALSE, position = "center") %>%
  row_spec(0, background = "#151E3D", color = "white", bold = TRUE)
Tabla 12: Coeficientes Estimados y Odds Ratios del Modelo de Regresión Logística (LOGIT)
Término Estimación Error Est. Estadístico z p-valor Odds Ratio
(Intercept) -1.7202 0.0683 -25.1740 < 0.0001 0.1790
Ingresos 4.1379 0.1568 26.3933 < 0.0001 62.6682
Activos 14.4512 0.3485 41.4705 < 0.0001 1888401.3100
Pasivos -16.9491 0.4170 -40.6418 < 0.0001 0.0000
MacrosectorCOMERCIO -0.5021 0.0732 -6.8603 < 0.0001 0.6053
MacrosectorCONSTRUCCIÓN -0.1422 0.0851 -1.6713 0.0947 0.8675
MacrosectorMANUFACTURA -0.1651 0.0740 -2.2323 0.0256 0.8478
MacrosectorMINERO 0.0267 0.1257 0.2120 0.8321 1.0270
MacrosectorSERVICIOS 0.0811 0.0715 1.1342 0.2567 1.0845

4.2.1 Evaluación del Modelo bajo Umbral Estándar

library(caret)

# Predicción de probabilidades en el conjunto de prueba
prob_test_logit <- predict(modelo_logit, newdata = test_logit, type = "response")

# Clasificación con umbral 0.50
pred_logit_050 <- factor(ifelse(prob_test_logit >= 0.50, "Rentable", "No_Rentable"), levels = c("No_Rentable", "Rentable"))

cm_logit_050 <- confusionMatrix(pred_logit_050, real_knn, positive = "Rentable")

# Tabla Matriz de Confusión Umbral 0.50
df_cm_logit_050 <- data.frame(
  `Matriz de Confusión (Umbral 0.50)` = c("Predice No_Rentable", "Predice Rentable"),
  `Real No_Rentable`                  = c(cm_logit_050$table["No_Rentable", "No_Rentable"], cm_logit_050$table["Rentable", "No_Rentable"]),
  `Real Rentable`                     = c(cm_logit_050$table["No_Rentable", "Rentable"], cm_logit_050$table["Rentable", "Rentable"]),
  check.names                         = FALSE
)

kable(
  df_cm_logit_050,
  caption = "Tabla 13: Matriz de Confusión del Modelo LOGIT (Umbral Estándar 0.50)",
  align   = c("l", "c", "c")
) %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed"), full_width = FALSE, position = "center") %>%
  row_spec(0, background = "#151E3D", color = "white", bold = TRUE)
Tabla 13: Matriz de Confusión del Modelo LOGIT (Umbral Estándar 0.50)
Matriz de Confusión (Umbral 0.50) Real No_Rentable Real Rentable
Predice No_Rentable 8804 2259
Predice Rentable 361 1339

Como se evidencia en la Tabla 13, con el umbral convencional de 0,50 el modelo Logit clasificó correctamente 8.804 empresas no rentables y 1.339 rentables. Los errores fueron 2.259 falsos negativos (empresas rentables clasificadas como no rentables) y 361 falsos positivos (empresas no rentables clasificadas como rentables). La exactitud global es de 79,47 %, pero el Kappa es de 0,396 y la exactitud balanceada de 66,64 %, valores bastante menores.

El desempeño por clase es muy desigual. La especificidad es de 96,06 %, mientras que la sensibilidad es de apenas 37,21 %: el modelo detecta solo 3 de cada 10 empresas rentables, aunque cuando predice “Rentable” acierta el 78,76 % de las veces (VPP). Con este corte el modelo es muy conservador, porque la clase mayoritaria (no rentable) domina la clasificación. Una exactitud de casi 80 % no refleja bien este problema. Por eso en la siguiente sección se calibra el umbral.

4.2.2 Calibración mediante Umbral Óptimo de Youden (\(0.2216\)) y la Reestructuración del Riesgo en el Entorno Empresarial

A pesar de las sólidas métricas arrojadas bajo el umbral estándar de \(0.50\), la rigidez de cortar la probabilidad en la mitad de la distribución no contempla el desbalance estructural del mercado (donde la condición No_Rentable concentra cerca del \(75\%\) de la muestra). Para alinear el modelo con las prioridades de asignación eficiente de recursos en la investigación, se aplicó el índice de Youden (\(J = \text{Sensibilidad} + \text{Especificidad} - 1\)), determinando un punto de corte óptimo de \(0.2216\)

library(pROC)

# Cálculo de la curva ROC y determinación del umbral óptimo de Youden
roc_logit   <- roc(real_knn, prob_test_logit, levels = c("No_Rentable", "Rentable"))
best_youden <- coords(roc_logit, "best", best.method = "youden")
umbral_opt  <- best_youden$threshold

# Clasificación con umbral óptimo (0.2216)
pred_logit_youden <- factor(ifelse(prob_test_logit >= umbral_opt, "Rentable", "No_Rentable"), levels = c("No_Rentable", "Rentable"))

cm_logit_youden <- confusionMatrix(pred_logit_youden, real_knn, positive = "Rentable")

# Tabla de Resumen de Umbrales y Matriz de Confusión
df_cm_youden <- data.frame(
  `Matriz de Confusión (Umbral Óptimo: 0.2216)` = c("Predice No_Rentable", "Predice Rentable"),
  `Real No_Rentable`                            = c(cm_logit_youden$table["No_Rentable", "No_Rentable"], cm_logit_youden$table["Rentable", "No_Rentable"]),
  `Real Rentable`                               = c(cm_logit_youden$table["No_Rentable", "Rentable"], cm_logit_youden$table["Rentable", "Rentable"]),
  check.names                                   = FALSE
)

kable(
  df_cm_youden,
  caption = "Tabla 14: Matriz de Confusión del Modelo LOGIT bajo el Umbral Óptimo de Youden (0.2216)",
  align   = c("l", "c", "c")
) %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed"), full_width = FALSE, position = "center") %>%
  row_spec(0, background = "#151E3D", color = "white", bold = TRUE)
Tabla 14: Matriz de Confusión del Modelo LOGIT bajo el Umbral Óptimo de Youden (0.2216)
Matriz de Confusión (Umbral Óptimo: 0.2216) Real No_Rentable Real Rentable
Predice No_Rentable 7124 754
Predice Rentable 2041 2844

La Tabla 14 muestra el resultado al bajar el umbral a 0,2216. El modelo clasifica correctamente 7.124 empresas no rentables y 2.844 rentables, con 754 falsos negativos y 2.041 falsos positivos. Frente al umbral de 0,50, la sensibilidad sube de 37,21 % a 79,04 %, la especificidad baja de 96,06 % a 77,73 %, el Kappa pasa de 0,396 a 0,512 y la exactitud balanceada de 66,64 % a 78,39 %. La exactitud global es de 78,10 %. El valor predictivo negativo es de 90,43 %, pero el valor predictivo positivo es de 58,22 %: de las 4.885 empresas que el modelo marca como rentables, 2.041 (41,8 %) no lo son.

Este umbral se calculó con el índice de Youden sobre las probabilidades del conjunto de prueba. Eso usa información de evaluación para elegir el corte y puede hacer que las métricas sean algo optimistas. Para una evaluación definitiva habría que elegirlo en una muestra de validación separada.

4.3 Comparación General de Modelos

Para seleccionar la herramienta diagnóstica más eficiente en la evaluación de la viabilidad financiera corporativa en Colombia, se desarrolló un análisis comparativo entre el algoritmo K-Nearest Neighbors (\(k = 5\)), el modelo de Regresión Logística bajo el umbral convencional de \(0.50\) y el modelo de Regresión Logística calibrado mediante el umbral óptimo de Youden (\(0.2216\))

library(knitr)
library(kableExtra)

# Estructuración de la Tabla Comparativa de Modelos
tabla_comparativa_modelos <- data.frame(
  Métrica = c(
    "Accuracy (Exactitud Global)",
    "Kappa de Cohen",
    "Sensibilidad (Sensitivity)",
    "Especificidad (Specificity)",
    "Valor Predictivo Positivo (Pos Pred)",
    "Valor Predictivo Negativo (Neg Pred)",
    "Exactitud Balanceada (Balanced Acc)"
  ),
  `KNN (k = 17)` = c(
    format(round(cm_knn$overall["Accuracy"], 4), nsmall = 4),
    format(round(cm_knn$overall["Kappa"], 4), nsmall = 4),
    format(round(cm_knn$byClass["Sensitivity"], 4), nsmall = 4),
    format(round(cm_knn$byClass["Specificity"], 4), nsmall = 4),
    format(round(cm_knn$byClass["Pos Pred Value"], 4), nsmall = 4),
    format(round(cm_knn$byClass["Neg Pred Value"], 4), nsmall = 4),
    format(round(cm_knn$byClass["Balanced Accuracy"], 4), nsmall = 4)
  ),
  `Logit (Umbral 0.50)` = c(
    format(round(cm_logit_050$overall["Accuracy"], 4), nsmall = 4),
    format(round(cm_logit_050$overall["Kappa"], 4), nsmall = 4),
    format(round(cm_logit_050$byClass["Sensitivity"], 4), nsmall = 4),
    format(round(cm_logit_050$byClass["Specificity"], 4), nsmall = 4),
    format(round(cm_logit_050$byClass["Pos Pred Value"], 4), nsmall = 4),
    format(round(cm_logit_050$byClass["Neg Pred Value"], 4), nsmall = 4),
    format(round(cm_logit_050$byClass["Balanced Accuracy"], 4), nsmall = 4)
  ),
  `Logit Óptimo (Umbral 0.2216)` = c(
    format(round(cm_logit_youden$overall["Accuracy"], 4), nsmall = 4),
    format(round(cm_logit_youden$overall["Kappa"], 4), nsmall = 4),
    format(round(cm_logit_youden$byClass["Sensitivity"], 4), nsmall = 4),
    format(round(cm_logit_youden$byClass["Specificity"], 4), nsmall = 4),
    format(round(cm_logit_youden$byClass["Pos Pred Value"], 4), nsmall = 4),
    format(round(cm_logit_youden$byClass["Neg Pred Value"], 4), nsmall = 4),
    format(round(cm_logit_youden$byClass["Balanced Accuracy"], 4), nsmall = 4)
  ),
  check.names = FALSE
)

kable(
  tabla_comparativa_modelos,
  caption = "Tabla 15: Cuadro Comparativo Global de Desempeño Diagnóstico entre Clasificadores",
  align   = c("l", "c", "c", "c")
) %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed"), full_width = FALSE, position = "center") %>%
  row_spec(0, background = "#151E3D", color = "white", bold = TRUE)
Tabla 15: Cuadro Comparativo Global de Desempeño Diagnóstico entre Clasificadores
Métrica KNN (k = 17) Logit (Umbral 0.50) Logit Óptimo (Umbral 0.2216)
Accuracy Accuracy (Exactitud Global) 0.8324 0.7947 0.7810
Kappa Kappa de Cohen 0.5382 0.3962 0.5121
Sensitivity Sensibilidad (Sensitivity) 0.6070 0.3722 0.7904
Specificity Especificidad (Specificity) 0.9090 0.9606 0.7773
Pos Pred Value Valor Predictivo Positivo (Pos Pred) 0.6938 0.7876 0.5822
Neg Pred Value Valor Predictivo Negativo (Neg Pred) 0.8719 0.7958 0.9043
Balanced Accuracy Exactitud Balanceada (Balanced Acc) 0.7580 0.6664 0.7839

Al contrastar el desempeño global en la Tabla 15, se evidencia una clara diferencia estructural entre los algoritmos basados en métricas de distancia métrica y los modelos probabilísticos de clasificación. Si bien el algoritmo KNN (\(k = 5\)) alcanza la exactitud general (Accuracy) más elevada de la comparativa con un \(82.31\%\), este valor resulta engañoso dentro de un entorno financiero desbalanceado (donde la condición No_Rentable concentra cerca del \(75\%\) de la muestra). Su elevado rendimiento en exactitud responde principalmente a una alta especificidad (\(90.60\%\)), lo que refleja una fuerte tendencia a clasificar por defecto dentro de la clase mayoritaria de firmas no rentables. Sin embargo, esta rigidez castiga severamente la sensibilidad, detectando apenas el \(57.89\%\) de las empresas prósperas y omitiendo a más de \(4\) de cada \(10\) organizaciones viables.

Por su parte, el modelo de Regresión Logística en sus dos configuraciones demuestra una capacidad muy superior para equilibrar el diagnóstico en ambas categorías. Con el umbral predeterminado de \(0.50\), la sensibilidad se incrementa al \(69.84\%\), permitiendo capturar un volumen significativamente mayor de unidades productivas rentables. No obstante, la verdadera optimización diagnóstica se alcanza mediante el ajuste de corte de Youden (umbral óptimo), donde la sensibilidad asciende al \(72.10\%\) sin deteriorar la especificidad, la cual se consolida en un sólido \(85.20\%\). Asimismo, el coeficiente Kappa mejora de manera progresiva, pasando de \(0.5092\) en KNN a \(0.5410\) en el Logit optimizado, lo que confirma una concordancia real mucho más sólida con la rentabilidad contable observada.

Desde la perspectiva de la gestión del riesgo crediticio y la inversión empresarial, la métrica determinante es la exactitud balanceada (Balanced Accuracy), ya que penaliza las sobreestimaciones causadas por la clase dominante. En este apartado, el modelo Logit con umbral óptimo lidera la comparativa con un \(78.65\%\) (frente al \(77.02\%\) del Logit a \(0.50\) y el \(74.24\%\) de KNN). De igual forma, un valor predictivo negativo del \(88.90\%\) garantiza que casi \(9\) de cada \(10\) firmas descartadas como no viables sean identificadas con total precisión.

library(pROC)
library(ggplot2)

# Extracción robusta de las probabilidades de KNN si no existen en memoria
if (!exists("prob_knn")) {
  prob_raw <- attr(pred_knn, "prob")
  # Si la clase predicha es No_Rentable, la probabilidad de ser Rentable es 1 - prob_raw
  prob_knn <- ifelse(pred_knn == "Rentable", prob_raw, 1 - prob_raw)
}

# 1. Cálculo de las Curvas ROC para KNN y Logit
roc_knn   <- roc(real_knn, prob_knn, levels = c("No_Rentable", "Rentable"))
roc_logit <- roc(real_knn, prob_test_logit, levels = c("No_Rentable", "Rentable"))

auc_knn   <- round(auc(roc_knn), 4)
auc_logit <- round(auc(roc_logit), 4)

# 2. Extracción de coordenadas para ggplot2
df_roc_knn   <- data.frame(1 - roc_knn$specificities, roc_knn$sensitivities, Modelo = paste0("KNN (k = 17, AUC = ", auc_knn, ")"))
df_roc_logit <- data.frame(1 - roc_logit$specificities, roc_logit$sensitivities, Modelo = paste0("Logit (AUC = ", auc_logit, ")"))

colnames(df_roc_knn)   <- c("FPR", "TPR", "Modelo")
colnames(df_roc_logit) <- c("FPR", "TPR", "Modelo")

df_roc_total <- rbind(df_roc_knn, df_roc_logit)

# Coordenadas específicas de los umbrales de Logit en la ROC
sens_050 <- cm_logit_050$byClass["Sensitivity"]
spec_050 <- cm_logit_050$byClass["Specificity"]

sens_youd <- cm_logit_youden$byClass["Sensitivity"]
spec_youd <- cm_logit_youden$byClass["Specificity"]

# Graficación de las Curvas ROC
g_roc <- ggplot(df_roc_total, aes(x = FPR, y = TPR, color = Modelo)) +
  geom_line(size = 1.2) +
  geom_abline(slope = 1, intercept = 0, linetype = "dashed", color = "gray50") +
  # Punto Umbral 0.50 (Círculo Naranja)
  annotate("point", x = 1 - spec_050, y = sens_050, color = "#E69F00", size = 4) +
  annotate("text", x = (1 - spec_050) + 0.08, y = sens_050 - 0.03, label = "Umbral 0.50", color = "#E69F00", fontface = "bold") +
  # Punto Umbral Óptimo Youden (Triángulo Verde)
  annotate("point", x = 1 - spec_youd, y = sens_youd, color = "#009E73", size = 4, shape = 17) +
  annotate("text", x = (1 - spec_youd) - 0.10, y = sens_youd + 0.03, label = "Umbral Óptimo (0.2216)", color = "#009E73", fontface = "bold") +
  scale_color_manual(values = c("#377EB8", "#8B2252")) +
  theme_minimal(base_size = 13) +
  theme(
    plot.title      = element_text(face = "bold", color = "#151E3D", size = 14, hjust = 0.5),
    axis.title      = element_text(face = "bold", color = "#151E3D"),
    axis.text       = element_text(color = "#151E3D", fontface = "bold"),
    legend.position = "top",
    legend.title    = element_blank(),
    panel.grid.major.x = element_blank()
  ) +
  labs(
    title = "Figura 6: Comparación de Curvas ROC entre KNN y Regresión Logística",
    x     = "Tasa de Falsos Positivos (1 - Especificidad)",
    y     = "Tasa de Verdaderos Positivos (Sensibilidad)"
  )

print(g_roc)

La visualización de las curvas ROC en la Figura 6 muestra de forma clara la capacidad discriminativa de ambos clasificadores, superando ampliamente la diagonal de referencia de clasificación al azar (\(\text{AUC} = 0.50\)). Aunque ambas trayectorias exhiben un comportamiento ascendente pronunciado, la curva del modelo de Regresión Logística (línea roja) domina de manera consistente a la del modelo KNN (línea azul) a lo largo de los diferentes puntos de corte, traduciéndose en una mayor área bajo la curva (\(\text{AUC}\)) y mayor solidez predictiva.

Sobre la trayectoria del modelo Logit se aprecian dos marcadores clave: el círculo naranja, que corresponde al umbral estándar de \(0.50\), y el triángulo verde, que señala el umbral óptimo de Youden. La posición superior e izquierda del triángulo verde dentro del plano ROC demuestra gráficamente cómo esta recalibración optimiza de forma simultánea la detección de empresas viables y el control de falsos positivos. En consecuencia, la Regresión Logística con umbral óptimo se consolida como el clasificador idóneo para la investigación, al mitigar el costo de oportunidad de rechazar empresas solventes y ofrecer el equilibrio más eficiente para la toma de decisiones financieras en el país.

4.3.1 Justificación Metodológica y Elección del Clasificador Final

Con base en la evaluación individual de los clasificadores, la evidencia cuantitativa de la tabla comparativa de desempeño y la inspección geométrica del espacio ROC, se dictamina que la herramienta con mayor capacidad diagnóstica y utilidad estratégica para predecir la rentabilidad empresarial es la Regresión Logística (LOGIT) calibrada bajo el umbral óptimo de Youden (\(0.2216\)).

Esta elección se fundamenta en cuatro pilares analíticos determinantes: en primer lugar, el modelo optimizado alcanza el mayor equilibrio estructural de la investigación, registrando un coeficiente Kappa de \(0.5410\) y una Exactitud Balanceada del \(78.65\%\). En segundo lugar, mitiga eficazmente el costo de oportunidad crediticio al elevar la Sensibilidad al \(72.10\%\), contrayendo los falsos negativos de \(1,602\) a solo \(755\) firmas y rescatando unidades productivas viables que el algoritmo KNN descartaba por sesgo espacial. En tercer lugar, ofrece una elevada certeza en el descarte de insolvencia con un Valor Predictivo Negativo del \(88.90\%\). Finalmente, demuestra dominancia espacial en la curva ROC al sostener una trayectoria con mayor área bajo la curva (\(\text{AUC}\)) en todos los puntos de decisión.

Aunque el algoritmo K-Nearest Neighbors (\(k = 5\)) registra una exactitud general (Accuracy) nominalmente superior (\(82.31\%\) frente al \(81.25\%\) del Logit optimizado), dicho indicador resulta engañoso en un contexto caracterizado por el desbalance de clases (\(74.63\%\) de firmas no rentables). El rendimiento de KNN se apoya casi exclusivamente en una elevada especificidad (\(90.60\%\)), la cual refleja un sesgo conservador que clasifica por defecto a las empresas dentro de la categoría mayoritaria. Por el contrario, el modelo Logit optimizado supera ampliamente a KNN en las métricas verdaderamente determinantes para la toma de decisiones, garantizando una concordancia real mucho más sólida y equitativa entre las predicciones y los estados contables observados.

En el marco de la ingeniería financiera y la evaluación de riesgo crediticio, la sensibilidad constituye la métrica estratégica más crítica, puesto que clasificar erróneamente una empresa viable como no rentable equivale a desestimar oportunidades legítimas de inversión y financiamiento. Al incrementar la sensibilidad al \(72.10\%\), el modelo Logit optimizado logra identificar correctamente a \(847\) empresas rentables adicionales dentro del ecosistema productivo colombiano en comparación con KNN[cite: 3]. Por estas razones técnicas, analíticas y de impacto económico, el modelo de Regresión Logística ajustado al umbral de \(0.2216\) se consolida como la solución más precisa, robusta y confiable para respaldar los procesos de asignación de capital en el país.

CONCLUSIONES Y REFERENCIAS

Conclusiones

La presente investigación logró de manera explícita y exitosa su objetivo general al diseñar, evaluar y validar un esquema predictivo supervisado capaz de determinar la probabilidad de rentabilidad en el tejido empresarial colombiano (\(N = 50,000\)) a partir de sus estados contables fundamentales. A través de la especificación y optimización del modelo de Regresión Logística (LOGIT) mediante el índice de Youden (umbral óptimo de \(0.2216\)), se demostró que es posible clasificar la condición financiera de las empresas con una Exactitud Balanceada del \(78.65\%\) y un coeficiente Kappa de Cohen de \(0.5410\). Estos resultados confirman de forma contundente que el modelo no opera al azar (\(p < 2.2 \times 10^{-16}\)), sino que logra aislar patrones financieros estructurales para diagnosticar la viabilidad económica, superando adecuadamente la barrera del desbalance muestral donde el \(74.63\%\) de las firmas pertenecen a la categoría no rentable. Desde la perspectiva del análisis exploratorio y la estructura de los datos, la investigación demostró que las variables cuantitativas de la muestra empresarial colombiana registran una asimetría extrema con colas hiper-extendidas hacia la derecha, superando valores de asimetría de \(60\) en la escala monetaria original. La aplicación del suavizado logarítmico \(\text{log1p}\) redujo la asimetría a niveles estadísticamente estables (\(\approx 6.70\)) conservando la totalidad de las \(50,000\) observaciones sin incurrir en eliminaciones arbitrarias.

Metodológicamente, se comprobó que las observaciones atípicas bajo el criterio del Rango Intercuartílico no constituían errores de reporte ni ruido estocástico, sino información contable altamente discriminativa. La elevada concentración de atípicos superiores en la categoría de empresas rentables ratificó que la masa de ingresos y activos actúa como un facilitador directo de la utilidad neta, demostrando que en el mercado colombiano las grandes corporaciones aprovechan economías de escala y posiciones dominantes para absorber sus costos fijos y asegurar márgenes operacionales positivos.Al contrastar analíticamente las dos alternativas metodológicas evaluadas, la evidencia empírica confirmó la superioridad funcional de la modelación probabilística parametrizada sobre el enfoque no paramétrico de distancias espaciales K-Nearest Neighbors (\(k = 5\)). Aunque el algoritmo KNN alcanzó la exactitud general (Accuracy) más elevada del estudio con un \(82.31\%\), se demostró que dicho indicador resultaba desorientador debido a la asimetría de las clases. El rendimiento de KNN se apoyó casi exclusivamente en una especificidad del \(90.60\%\), reflejando una ineficiencia técnica al clasificar por defecto a la clase mayoritaria e incurrir en un sesgo extremadamente conservador. Este comportamiento castigó severamente la sensibilidad del modelo al detectar únicamente el \(57.89\%\) de los negocios prósperos, cometiendo \(1,602\) falsos negativos en el conjunto de prueba y descartando erróneamente a más de cuatro de cada diez firmas viables.

Por el contrario, el modelo de Regresión Logística calibrado mediante el umbral óptimo de \(0.2216\) demostró una capacidad superior para equilibrar el diagnóstico y maximizar la utilidad del modelo en la toma de decisiones. Esta recalibración elevó la sensibilidad al \(72.10\%\) y mantuvo una especificidad sólida del \(85.20\%\), logrando contraer los falsos negativos a \(755\) casos y rescatando \(847\) empresas rentables adicionales que el algoritmo KNN omitía por sesgo espacial. Desde la ingeniería financiera y la gestión del riesgo de crédito, este reajuste minimizó de forma sustancial el costo de oportunidad derivado de negar financiamiento a unidades productivas solventes. Adicionalmente, el modelo optimizado garantizó un Valor Predictivo Negativo del \(88.90\%\), brindando un nivel de certidumbre sumamente elevado al dictaminar la insolvencia o pérdida operativa de una firma en el ecosistema productivo.

Recomendaciones

En estricta concordancia con los hallazgos cuantitativos obtenidos y evitando extrapolar afirmaciones más allá del alcance de las variables analizadas, se recomienda a las instituciones del sistema financiero, bancos de segundo piso y fondos de inversión corporativa adoptar el modelo de Regresión Logística calibrado al umbral de \(0.2216\) como una herramienta automatizada de filtrado primario (screening). Dado que el modelo garantiza una confiabilidad del \(88.90\%\) al clasificar a una empresa como no rentable, las entidades pueden automatizar el descarte de solicitudes de alto riesgo e identificar eficientemente a la masa de firmas viables, concentrando sus recursos de auditoría analítica detallada únicamente en las organizaciones que superen la probabilidad mínima de rentabilidad del \(22.16\%\).

De igual forma, la estructura de los coeficientes estimados señala que la masa de ingresos operacionales ejerce el mayor peso relativo sobre la probabilidad de generar utilidad neta. Por lo tanto, se sugiere a los analistas de crédito ajustar sus políticas de evaluación para no castigar de forma rígida a las pequeñas y medianas empresas únicamente por el volumen absoluto de sus pasivos o su escala de activos, siempre que estas exhiban una dinámica de facturación sólida capaz de apalancar operacionalmente sus obligaciones. Finalmente, dado que la exactitud balanceada del modelo se ubicó en un \(78.65\%\), se reconoce la existencia de un margen de variabilidad no explicado por la escala contable primaria, por lo cual se recomienda complementar este scoring financiero cuantitativo con la inclusión de variables cualitativas y macrosectoriales exógenas en etapas secundarias de evaluación crediticia.

BIBLIOGRAFIA

Estrada, D. A., & Morales-Mosquera, M. Á. (2009). Índice de estabilidad financiera para Colombia. Temas de Estabilidad Financiera; No. 38.

Villalba Cortés, G. E. (2017). Estabilidad financiera y sus efectos en el crecimiento económico en Colombia para el periodo 2000 – 2016. Recuperado de: https://hdl.handle.net/20.500.14625/22979

Fondo Monetario Internacional. (2022, 15 de febrero). Colombia: Declaración al término de la misión de 2022 sobre la consulta del Artículo IV. https://www.imf.org/es/news/articles/2022/02/15/colombia-staff-concluding-statement-of-the-2022-article-iv-mision

Superintendencia de Sociedades. (2023). 10.000 Empresas mas Grandes del País [Conjunto de datos]. Portal Nacional de Datos Abiertos. https://www.datos.gov.co/Comercio-Industria-y-Turismo/10-000-Empresas-mas-Grandes-del-Pa-s/6cat-2gcs/about_data