Introducción.

El consumo de sustancias psicoactivas constituye una problemática relevante para la salud pública en Colombia y en el mundo, esto debido a su impacto en la salud física, mental y social de las personas. El uso de medicamentos sin receta médica y sustancias ilegales con fines recreativos o de evasión emocional ha ido en aumento, afectando principalmente a adolescentes y jóvenes adultos (Barbieri, Trivelloni, Zani y Palacios-Espinosa, 2012). Estudios nacionales muestran que el uso de sustancias psicoactivas está influido por múltiples factores de riesgo, incluyendo el entorno familiar, las condiciones socioeconómicas y el bienestar emocional de los individuos (Aguirre-Guiza, Aldana-Pinzón y Bonilla-Ibáñez, 2017).

La Encuesta Nacional de Consumo de Sustancias Psicoactivas ENCSPA del 2019, realizada por el DANE, proporciona información sobre las conductas, los rasgos sociodemográficos y los factores de riesgo vinculados con el consumo de sustancias legales o ilegales de la población colombiana. Esta encuesta permite conocer la dimensión y los modelos de consumo de sustancias psicoactivas legales e ilegales, así como factores económicos, sociales y sanitarios relacionados con el comportamiento.

En este análisis se consideran como variables explicativas la edad, el género, la presencia de síntomas depresivos, el estrato socioeconómico y la existencia de familiares consumidores. Estas variables son de interés debido a que muestran aspectos individuales y estructurales que tienden a afectar la probabilidad de consumo. El bienestar emocional, las condiciones sociales, el entorno económico y familiar nos ayudan a entender de manera más efectiva cómo se relacionan diferentes aspectos personales y contextuales en la aparición de las conductas de riesgo.

El objetivo de este trabajo es desarrollar y comparar dos modelos de clasificación, K-Nearest Neighbors (KNN) y Regresión Logística (Logit), para prever la probabilidad de consumo reciente de sustancias psicoactivas. Por medio de estos modelos se espera identificar patrones de comportamiento y evaluar la influencia de los factores sociodemográficos y familiares sobre la probabilidad de consumo.

Metodología.

Los datos fueron extraídos de la Encuesta Nacional de Consumo de Sustancias Psicoactivas (ENCSPA) 2019, elaborada por el DANE, y se seleccionaron las columnas correspondientes a las variables de interés:

Variable dependiente (Y).

Consumo reciente de sustancias psicoactivas (CONSUMO_ILEGAL).

Es una variable binaria (0=No, 1=Si) que indica si la persona encuestada reportó haber consumido alguna sustancia psicoactiva recientemente. Esta variable es fundamental, ya que permite clasificar a los individuos en consumidores y no consumidores, además al generar la relación con las demás variables nos permite identificar los patrones y factores que se asocian al consumo.

Variables independientes (Xi).

Género (SEXO).

Variable de tipo categórica que diferencia entre hombres y mujeres. Se incluyó debido a que el comportamiento frente al consumo pueden diferir segun el sexo, debido a conducta en situaciones relacionadas con factores biologicos, culturales y sociales.

Edad (EDAD).

Medida de forma cuantitativa, representa los años de la persona y se seleccionó porque el consumo de sustancias puede variar según las experiencias, responsabilidades y presiones que enfrentan las personas, situaciones que son cambiantes con la edad, lo que podría influir en su inclinación al consumo, haciendo relevante este factor para el modelo.

Síntomas vinculados a la depresión (DEPRESION).

Es binaria e indica si la persona encuestada reportó sentirse desanimada, deprimida o con pocas esperanzas. Se eligió con el fin de cubrir el factor del estado emocional y mental que puede incidir en las conductas de riesgo como el consumo de sustancias.

Estrato socioeconómico (ESTRATO).

Variable categórica que clasifica a los hogares según su nivel económico, del 1 al 6. Este aspecto se incluyó con el fin de cubrir la posible influencia del entorno social y las condiciones materiales de los individuos que pueden influir en la exposición y la susceptibilidad frente al consumo de sustancias psicoactivas.

Familiares cercanos que consuman sustancias (FAMILIA_CONSUME).

Variable binaria que refleja si existen miembros de la familia en el entorno cercano que sean consumidores. Se considera importante porque el comportamiento del entorno puede influir en las decisiones individuales, facilitando o normalizando el consumo de sustancias, lo que resulta relevante para el análisis.

Descripción del modelo utilizado.

Para abordar el problema de clasificación del consumo de sustancias psicoactivas, se aplicaron las técnicas de aprendizaje supervisado, utilizando los dos modelos de clasificación K-Nearest Neighbors (KNN) y Regresión Logística (Logit). Ambas técnicas permiten predecir la probabilidad de que una persona consuma (CONSUMO_ILEGAL) a partir de las variables independientes seleccionadas (SEXO, EDAD, DEPRESION, ESTRATO, FAMILIA_CONSUME).

CONSUMO_ILEGAL ~ SEXO + EDAD + DEPRESION + ESTRATO + FAMILIA_CONSUME

Modelo KNN.

Este modelo clasifica cada observación según la mayoría de los vecinos más cercanos en el espacio de las variables predictoras. Se dividió la muestra en 70% para entrenamiento y 30% para prueba, manteniendo la proporción de consumidores y no consumidores. También, se utilizó la validación cruzada de 5 partes para seleccionar el valor óptimo de k (número de vecinos) y evitar sobreajuste.

Se evaluó el modelo usando exactitud (accuracy), sensibilidad y AUC (área bajo la curva ROC), para medir su capacidad de clasificar correctamente tanto consumidores como no consumidores.

Modelo de Regresión Logística (Logit)

La regresión logística estima la probabilidad de consumo mediante la función logística que transforma una combinación lineal de estas variables en una probabilidad entre 0 y 1, que indica la posibilidad de consumo.

La muestra también se dividió en 70% entrenamiento y 30% prueba. Se calcularon las probabilidades de las predicciones y se transformaron en binarias usando un umbral estándar de 0.5, y posteriormente se estimó un umbral óptimo basado en el criterio de Youden para maximizar la sensibilidad y la especificidad.

La evaluación incluyó matrices de confusión, sensibilidad, especificidad, accuracy y AUC, permitiendo su comparación frente al modelo KNN.

Comparación y elección del modelo.

Ambos modelos fueron comparados considerando:

  • Exactitud general en la clasificación.
  • Capacidad para detectar correctamente los casos positivos (sensibilidad).
  • Valor del AUC, que hace referencia a la capacidad de discriminar entre consumidores y no consumidores.

Adicionalmente, se emplearon las herramientas visuales y analíticas para explorar la relación entre consumo de sustancias psicoactivas y las variables de estudio, con el fin de conocer distribuciones, reconocer posibles asociaciones y hacer contraste entre grupos, se utilizaron gráficos y tablas descriptivas que, junto al análisis predictivo base de modelos KNN y Logit, conformaron la totalidad de los análisis.

Resultados Descriptivos.

Inicialmente, se integraron las bases de datos provenientes de la Encuesta Nacional de Consumo de Sustancias Psicoactivas (ENCSPA, 2019), las cuales incluían información de diferentes capítulos del cuestionario (personas_seleccionadas, encuestas, d_capitulos, d2_capitulos y g_capitulos). Estas se unificaron mediante el identificador DIRECTORIO, que permitió relacionar las respuestas de cada individuo. Posteriormente, se seleccionaron las variables de interés, se filtraron los registros para conservar únicamente personas entre 12 y 25 años y se eliminaron valores faltantes (N/A) o categorías no válidas (No Aplica). Además, se construyeron las variables FAMILIA_CONSUME, que identifica si algún familiar cercano consume sustancias, y CONSUMO_ILEGAL, que clasifica a los individuos según el reporte de consumo reciente.

De esta manera, se obtuvo la base de datos con un total de 12,257 registros, que se usó para el análisis descriptivo y la modelación posterior.

library(DT)
library(dplyr)
library(htmltools)

datatable(
  con_sustan %>%
    select(DIRECTORIO, SEXO, EDAD, FAMILIA_CONSUME, DEPRESION, ESTRATO, CONSUMO_ILEGAL),
  colnames = c(
    "Directorio",
    "Sexo",
    "Edad (años)",
    "Consumo en entorno familiar",
    "Depresión (sí/no)",
    "Estrato socioeconómico",
    "Consumo de sustancias ilegales"
  ),
  options = list(
    pageLength = 10,
    scrollX = TRUE,
    autoWidth = TRUE,
    style = 'bootstrap',
    columnDefs = list(
      list(className = 'dt-left', targets = "_all"), 
      list(width = '150px', targets = "_all")            
    )
  ),
  rownames = FALSE, 
  class = 'display stripe hover nowrap',
  caption = htmltools::tags$caption(
    style = 'caption-side: top; text-align: center; font-weight: bold; font-size: 16px;',
    "Tabla de variables del estudio sobre consumo de sustancias ilegales"
  )
)

Variables individuales.

En este estudio se analizaron diversas variables, cuyas características descriptivas se presentan a continuación enfocadas en proporciones y frecuencias (por su naturaleza categórica). Cada una de estas variables cuenta con un diagrama o tabla que permite observar su comportamiento descriptivo y facilita la identificación de patrones, desigualdades o concentraciones en los indicadores clave relacionados con el consumo de sustancias psicoactivas.

Consumo reciente de sustancias psicoactivas (CONSUMO_ILEGAL).

library(DT)
library(htmltools)
library(dplyr)

tabla_consumo <- as.data.frame(table(con_sustan$CONSUMO_ILEGAL))
colnames(tabla_consumo) <- c("Consumo ilegal", "Frecuencia")
tabla_consumo$Proporción <- round(prop.table(tabla_consumo$Frecuencia), 4)

htmltools::div(
  style = "display: flex; justify-content: center; align-items: center; width: 100%;",
  datatable(
    tabla_consumo,
    rownames = FALSE,
    width = "60%",
    options = list(
      scrollX = FALSE,
      ordering = FALSE,
      autoWidth = TRUE,
      dom = 't',
      pageLength = nrow(tabla_consumo),
      columnDefs = list(list(width = '120px', targets = "_all"))
    ),
    class = 'display stripe hover compact nowrap',
    caption = htmltools::tags$caption(
      style = 'caption-side: top; text-align: center;
               font-weight: bold; color: #343a40;',
      "Distribución de la variable CONSUMO_ILEGAL"
    )
  )
)

Esta variable señala si la persona reportó haber consumido alguna sustancia psicoactiva recientemente. De acuerdo con los datos, el 56.6% de los encuestados no ha utilizado drogas ilegales, mientras que el 43.4% sí las ha usado. Esto muestra una cifra de consumo significativa entre los individuos analizados, lo que resalta la relevancia del fenómeno en la muestra estudiada.

EDAD.

library(ggplot2)
library(plotly)
library(dplyr)


con_sustan <- con_sustan %>%
  mutate(EDAD = as.numeric(as.character(EDAD)))


p_edad <- ggplot(data = con_sustan, aes(y = EDAD)) +
  geom_boxplot(
    fill = "#89ACC6",
    color = "#284C64",
    outlier.color = "#284C64",
    alpha = 0.8
  ) +
  labs(
    title = "",
    y = "Edad",
    x = ""
  ) +
  theme_minimal(base_size = 13) +
  theme(
    plot.title = element_text(face = "bold", hjust = 0.5, color = "#284C64"),
    axis.title.y = element_text(color = "#284C64"),
    panel.grid.minor = element_blank()
  )


ggplotly(p_edad)

Esta variable tiene un rango de 12 a 25 años y una mediana de 20. La mayoría de los casos están concentrados entre aquellos que tienen entre 17 y 23 años, lo cual demuestra que la mayor parte de los participantes pertenecen a un grupo poblacional joven. Esta distribución es importante porque los adolescentes y los adultos jóvenes son uno de los grupos más vulnerables al consumo de sustancias psicoactivas en cuanto a la cuestión del estudio. Esta conducta concuerda con lo que se ha reportado en la literatura, en la que se afirma que hay una mayor posibilidad de experimentar o comenzar a consumir a una edad temprana, motivada por factores emocionales y sociales.

Relaciones entre variables.

Para observar las posibles relaciones entre el uso de sustancias psicoactivas y otras variables sociodemográficas, se construyeron diversas tablas cruzadas y análisis de significación estadística. Estas permiten reconocer tendencias de conducta y posibles elementos asociados al consumo.

Consumo ilegal relativo por estrato.

library(dplyr)
library(plotly)

consumo_por_estrato <- con_sustan %>%
  group_by(ESTRATO, CONSUMO_ILEGAL) %>%
  summarise(n = n(), .groups = "drop") %>%
  group_by(ESTRATO) %>%
  mutate(prop = n / sum(n)) %>%
  ungroup() %>%
  filter(CONSUMO_ILEGAL == "Si")


max_prop <- max(consumo_por_estrato$prop, na.rm = TRUE)

consumo_relativo <- consumo_por_estrato %>%
  mutate(Relativo = (prop / max_prop) * 100) %>%
  arrange(desc(Relativo))


plot_ly(
  consumo_relativo,
  x = ~reorder(ESTRATO, -Relativo),
  y = ~Relativo,
  type = "bar",
  marker = list(color = "#2F4F6A"),
  hovertemplate = paste(
    "<b>Estrato:</b> %{x}<br>",
    "<b>% de consumo relativo:</b> %{y:.1f}%<br>"
  )
) %>%
  layout(
    title = list(
      text = " ",
      font = list(size = 18, color = "#1C2E3B")
    ),
    xaxis = list(
      title = "",
      tickfont = list(size = 13)
    ),
    yaxis = list(
      title = "Porcentaje relativo",
      tickfont = list(size = 13),
      range = c(0, 110),
      ticksuffix = "%"
    ),
    plot_bgcolor = "#FFFFFF",
    paper_bgcolor = "#FFFFFF"
  )

La gráfica muestra cómo se distribuye el consumo ilegal de sustancias psicoactivas en función del nivel socioeconómico. Para simplificar la comparación, los valores fueron normalizados con el estrato de consumo más elevado (estrato 6) como referencia, a quien se le dio un valor del 100%. Después de este punto, los demás niveles se expresan en relación con el consumo máximo observado.

En términos descriptivos, se observa una tendencia a la baja: el consumo relativo va bajando de manera gradual desde los niveles altos hasta los bajos. El estrato 6 tiene el valor más alto, después el 5 y el 4, y los estratos 1 y 2 tienen los niveles más bajos. Esto señala que el consumo no se reparte de manera uniforme entre los estratos socioeconómicos, sino que tiende a concentrarse en los niveles más altos.

Respecto de su relación con el problema de estudio, esta distribución indica que el uso de sustancias ilegales no está asociado únicamente a circunstancias económicas adversas; más bien, puede estar determinado por elementos sociales y culturales propios de los estratos más favorecidos, como la facilidad para acceder o situaciones en las que el consumo se normaliza a nivel social.

Tabla Cruzada: Variables Dicotómicas vs Consumo Ilegal.

library(dplyr)
library(DT)
library(htmltools)


vars_dicotomicas <- c("DEPRESION", "FAMILIA_CONSUME", "SEXO")

tablas_cruzadas <- list()

for (var in vars_dicotomicas) {
  
  tabla <- table(con_sustan[[var]], con_sustan$CONSUMO_ILEGAL)
  
  df_tabla <- as.data.frame(tabla)
  colnames(df_tabla) <- c("Variable", "Consumo_ilegal", "Frecuencia")
  df_tabla$Variable <- as.character(df_tabla$Variable)
  df_tabla$Nombre_Variable <- case_when(
    var == "FAMILIA_CONSUME" ~ "Consumo en entorno familiar",
    var == "DEPRESION" ~ "Depresión",
    var == "SEXO" ~ "Sexo",
    TRUE ~ var)
  df_tabla$Proporcion <- round(df_tabla$Frecuencia / sum(df_tabla$Frecuencia), 4)
  
  tablas_cruzadas[[var]] <- df_tabla
}

tabla_final <- bind_rows(tablas_cruzadas)

tabla_final <- tabla_final %>%
  select(Nombre_Variable, Variable, Consumo_ilegal, Frecuencia, Proporcion)

datatable(
  tabla_final,
  rownames = FALSE,
  caption = htmltools::tags$caption(
    style = 'caption-side: top; text-align: center; font-weight: bold; color: #343a40;',
    "Tabla Cruzada: Variables Dicotómicas vs CONSUMO_ILEGAL"
  ),
  class = 'display stripe hover compact nowrap',
  options = list(
    pageLength = 15,
    ordering = FALSE,
    autoWidth = TRUE,
    scrollX = FALSE,
    dom = 't',
    columnDefs = list(list(className = 'dt-center', targets = 0:4)) # solo 5 columnas
  )
)

La tabla muestra la relación entre tres variables dicotómicas (sexo, depresión y consumo en la familia) y el uso de sustancias ilegales. Se puede notar que las personas que viven en un entorno familiar donde hay consumo tiene un mayor consumo (11.8%), después de aquellos que tienen síntomas de depresión (9.25%). Esto indica que la probabilidad de consumir sustancias ilegales está influenciada por el estado emocional y también por el ambiente familiar, siendo este último el factor con mayor peso relativo.

Respecto al género, el consumo ilegal de los hombres es del 22.25% y el de las mujeres del 21.11%. Esto muestra una diferencia pequeña pero constante hacia un consumo más alto en la población masculina.

En general, los resultados muestran que el consumo en el ambiente familiar y la depresión se relacionan con una probabilidad más alta de consumo ilegal, mientras que la variable sexo tiene un impacto inferior al de las anteriores.

Prueba Chi-Cuadrado: Variables binarias VS Consumo Ilegal.

library(dplyr)
library(DT)
library(htmltools)


vars_dicotomicas <- c("DEPRESION", "FAMILIA_CONSUME", "SEXO")

resultados_chi <- list()

for (var in vars_dicotomicas) {
  tabla <- table(con_sustan[[var]], con_sustan$CONSUMO_ILEGAL)
  chi <- suppressWarnings(chisq.test(tabla))
  
  resultados_chi[[var]] <- data.frame(
    Variable = var,
    X_square = round(chi$statistic, 4),
    df = chi$parameter,
    p_value = ifelse(chi$p.value < 0.001, "< 0.001", round(chi$p.value, 4))
  )
}

tabla_resultados <- bind_rows(resultados_chi)


datatable(
  tabla_resultados,
  rownames = FALSE,
  caption = htmltools::tags$caption(
    style = 'caption-side: top; text-align: center; 
             font-weight: bold; color: white; background-color: #1C2E3B;
             padding: 6px; font-size: 16px;',
    "Prueba Chi-Cuadrado: Variables binarias vs CONSUMO_ILEGAL"
  ),
  class = 'cell-border stripe hover compact',
  options = list(
    dom = 't',
    ordering = FALSE,
    pageLength = nrow(tabla_resultados),
    columnDefs = list(list(className = 'dt-center', targets = "_all"))
  )
)

El análisis Chi-cuadrado indica que el consumo ilegal de sustancias tiene una relación significativa con el sexo, la depresión y el consumo familiar (p < 0.001 en todos los casos), lo cual sugiere que estas variables afectan la probabilidad de consumo.

library(plotly)
library(dplyr)


datos_barras <- data.frame(
  Variable = rep(c("DEPRESION", "FAMILIA_CONSUME", "SEXO"), each = 2),
  Consumo_ilegal = rep(c("No", "Si"), times = 3),
  Porcentaje = c(0.75, 0.25, 0.55, 0.45, 0.62, 0.38)
)


datos_barras <- datos_barras %>%
  mutate(
    Consumo_ilegal = factor(Consumo_ilegal, levels = c("No", "Si")),
    text_interior = ifelse(Porcentaje >= 0.05,
                           paste0(round(Porcentaje * 100, 0), "%"), "")
  )

cols_named <- c("No" = "#2F4F6A", "Si" = "#7D9CB2")


p_barra <- plot_ly(
  data = datos_barras,
  x = ~Variable,
  y = ~Porcentaje,
  color = ~Consumo_ilegal,
  colors = cols_named,
  type = "bar",
  customdata = ~Consumo_ilegal,
  hovertemplate = paste(
    "<b>%{x}</b><br>",
    "Consumo ilegal: %{customdata}<br>",
    "Porcentaje: %{y:.0%}",  
    "<extra></extra>"
  )
) %>%
  layout(
    barmode = "stack",
    title = list(
      text = "",
      x = 0.01
    ),
    yaxis = list(
      title = "Proporcion",
      tickvals = seq(0, 1, 0.1),               
      ticktext = paste0(seq(0, 100, 10), "%"), 
      tickformat = ".0%",                     
      range = c(0, 1)
    ),
    xaxis = list(title = "", tickangle = -45),
    legend = list(title = list(text = "<b>Consumo ilegal</b>"))
  )

p_barra<- p_barra %>% layout(
  autosize = TRUE
)

p_barra

El gráfico de barras indica que, sobre el sexo y la depresión, el consumo doméstico es la variable con más proporción de consumo de sustancias. Esto indica que el ambiente familiar tiene un impacto más fuerte en el consumo, mientras que los factores emocionales también tienen influencia, pero de forma menos significativa.

Resultados del modelo.

Modelo KNN (caret).

El algoritmo K-Nearest Neighbors (KNN) es un modelo de aprendizaje supervisado no paramétrico que clasifica una observación en función de las categorías de sus k vecinos más próximos, asignándole la clase más común entre ellos, determinada por medio de una medida de distancia como la Euclidiana.

library(caret)
library(ROCR)
library(pROC)

set.seed(28)


index_entrena <- createDataPartition(y = con_sustan$CONSUMO_ILEGAL, p = 0.7, list = FALSE)
train_data <- con_sustan[index_entrena, ]
test_data  <- con_sustan[-index_entrena, ]

consumo_knn <- train(
  CONSUMO_ILEGAL ~ SEXO + EDAD + DEPRESION + ESTRATO + FAMILIA_CONSUME,
  data = train_data,
  method = "knn",
  tuneLength = 30,
  trControl = trainControl(method = "cv", number = 5)
)

Precisión.

knn_results <- consumo_knn$results


k_col <- names(knn_results)[grepl("^k$", names(knn_results), ignore.case = TRUE)]
colnames(knn_results)[colnames(knn_results) == k_col] <- "K"


knn_results <- knn_results %>%
  mutate(K = as.numeric(as.character(K))) %>%
  arrange(K)


y_min <- min(knn_results$Accuracy)
y_max <- max(knn_results$Accuracy)
margen <- (y_max - y_min) * 0.3


p_knn <- plot_ly(
  data = knn_results,
  x = ~K,  
  y = ~Accuracy,
  type = "scatter",
  mode = "lines+markers",
  line = list(color = "#2F4F6A", width = 2),
  marker = list(size = 7, color = "#7D9CB2", line = list(width = 1, color = "#2F4F6A")),
  hovertemplate = paste(
    "<b>K vecinos:</b> %{x}<br>",
    "<b>Precisión promedio:</b> %{y:.3f}<extra></extra>"
  )
) %>%
  layout(
    title = list(
      text = "",
      x = 0.02
    ),
    xaxis = list(title = "Número de vecinos (K)"),
    yaxis = list(
      title = "Precisión (Accuracy)",
      range = c(y_min - margen, y_max + margen), 
      tickformat = ".3f"  
    ),
    plot_bgcolor = "white",
    paper_bgcolor = "white"
  )


p_knn

Este gráfico muestra la manera en que cambia la precisión del modelo KNN (K-Nearest Neighbors) de acuerdo al valor k (número de vecinos), lo que resulta fundamental para determinar el valor más adecuado de este hiperparámetro en un modelo de aprendizaje supervisado.

Se aprecia en el gráfico que la precisión oscila ligeramente entre 0.594 y 0.602, sin experimentar cambios drásticos durante todo el rango de k. Esto quiere decir que la eficacia general del modelo es relativamente estable, y que las variaciones en k no producen alteraciones significativas en la precisión global. No obstante, se observa una ligera tendencia ascendente hacia valores intermedios y altos de k, llegando a su pico de precisión cerca de k = 49, donde la exactitud es aproximadamente 0.602.

Este comportamiento muestra que cuando k tiene valores altos, el modelo se vuelve más estable y conservador, porque requiere un mayor consenso entre los vecinos para calificar un caso como positivo. Esto disminuye la variabilidad en las previsiones y optimiza la habilidad de generalización del modelo. No obstante, también conlleva una disminución de la sensibilidad, ya que el modelo tiende a clasificar menos casos como positivos (consumo ilegal) debido a que requiere más pruebas para hacerlo.

Matriz de confusión.

La matriz de confusión del modelo KNN permite analizar qué tan bien el algoritmo clasifica los casos en función de la variable objetivo. En ella se comparan las predicciones del modelo con los valores reales, evidenciando tanto los aciertos como los errores en la clasificación de los casos.

prob_knn <- predict(consumo_knn, newdata = test_data, type = "prob")
pred <- prediction(prob_knn[, "Si"], test_data$CONSUMO_ILEGAL)
perf <- performance(pred, "tpr", "fpr")
auc_value <- performance(pred, measure = "auc")@y.values[[1]]
pred_knn <- predict(consumo_knn, newdata = test_data)


library(DT)
library(htmltools)


resultados_knn <- data.frame(
  Metrica = c(
    "Accuracy",
    "Intervalo de Confianza (95%)",
    "No Information Rate",
    "P-Value [Acc > NIR]",
    "Kappa",
    "Mcnemar's Test P-Value",
    "Sensibilidad (Recall)",
    "Especificidad",
    "Valor Predictivo Positivo (Precision)",
    "Valor Predictivo Negativo",
    "Prevalencia",
    "Tasa de Detección (Detection Rate)",
    "Detección Esperada (Detection Prevalence)",
    "Exactitud Balanceada"
  ),
  Valor = c(
    0.5914,
    "(0.5753, 0.6074)",
    0.5664,
    "0.001137",
    0.1054,
    "< 2.2e-16",
    0.2296,
    0.8684,
    0.5718,
    0.5955,
    0.4336,
    0.0995,
    0.1741,
    "0.5490"
  )
)

estilo_contenedor <- "
  width: 600px;
  margin: 0 auto;
  text-align: center;
"


titulo<- htmltools::tags$div(
  "Desempeño del Modelo Knn (Matriz de Confusión)",
  style = "
    font-weight: bold;
    color: white;
    background-color: #1C2E3B;
    padding: 10px;
    font-size: 18px;
    border-top-left-radius: 6px;
    border-top-right-radius: 6px;
  "
)

tabla_knn<- datatable(
  resultados_knn,
  rownames = FALSE,
  colnames = c("Métrica", "Valor"),
  class = 'display stripe hover compact cell-border',
  options = list(
    dom = 't',
    ordering = FALSE,
    paging = FALSE,
    scrollY = FALSE,
    scrollX = FALSE,
    autoWidth = TRUE,
    columnDefs = list(
      list(className = 'dt-center', targets = "_all"),
      list(width = '50%', targets = 0),
      list(width = '50%', targets = 1)
    )
  )
) %>%
  formatStyle(
    columns = names(resultados_knn),
    fontSize = '14px',
    lineHeight = '1.4',
    color = "#1C2E3B"
  )

htmltools::browsable(
  htmltools::div(
    style = estilo_contenedor,
    htmltools::tagList(
      titulo,
      tabla_knn
    )
  )
)
Desempeño del Modelo Knn (Matriz de Confusión)
Exactitud (accuracy): 0.5914

El modelo tuvo un porcentaje de aciertos del 59,14%. un desempeño significativamente superior al azar esperado del 0.0956 al predecir aleatoriamente, lo cual evidencia cierto grado de aprendizaje. Sin embargo, a pesar de que el modelo supera el azar, su precisión global continúa siendo moderada, lo cual indica sigue cometiendo errores en una proporción significativa de los casos.

Sensibilidad (Recall para clase ‘Si’): 0.2296

El modelo identificó correctamente el 22,96% de los casos positivos (personas que reportaron consumo de sustancias ilegales). Esta baja sensibilidad indica que el modelo tiene dificultades para reconocer correctamente los casos de consumo, lo que limita su capacidad para detectar patrones asociados a esta clase minoritaria.

Especificidad (para clase “No”): 0.8684

El modelo clasificó correctamente el 86,84% de los casos negativos (personas que no consumen sustancias ilegales). Esto demuestra un buen desempeño al identificar a los no consumidores, aunque este alto nivel de especificidad se alcanza a costa de una menor sensibilidad, es decir, el modelo tiende a predecir “No” con más frecuencia que “Sí”.

Exactitud Balanceada (Balanced Accuracy): 0.5490

El promedio entre sensibilidad y especificidad arroja una exactitud balanceada del 54,9%, lo que refleja un desbalance entre las dos clases. El modelo muestra un claro sesgo hacia la clase negativa (“No”), lo que podría deberse a un desequilibrio en los datos o a una capacidad limitada para detectar patrones en los casos positivos.

Valor Predictivo Positivo (Precisión para clase “Sí”): 0.5718

De los casos en los que el modelo predijo “Sí”, el 57,18% fueron correctos. Esto muestra una precisión aceptable al identificar casos positivos, aunque la baja cantidad de verdaderos positivos reduce su utilidad práctica en contextos donde la detección temprana es importante.

Valor Predictivo Negativo: 0.5955

El 59,55% de los casos predichos como “No” fueron correctos. Si bien el valor es moderado, indica que aún existe una proporción relevante de falsos negativos, lo que limita la confiabilidad del modelo al identificar con certeza a los no consumidores.

Tasa de Detección: 0.0996

La tasa de detección del 9,95% muestra que el modelo solo identifica correctamente una fracción pequeña de los consumidores reales. Este bajo desempeño confirma la dificultad del modelo para detectar casos positivos de forma consistente.

Tasa de Detección Esperada: 0.1741

El modelo predice aproximadamente el 17,41% de los casos como consumidores, una ligera sobreestimación frente a la prevalencia real. Esto sugiere que el modelo tiende a clasificar algunos casos de manera errónea como positivos, reduciendo su precisión general.

Coeficiente Kappa: 0.1054

El valor de Kappa (0.1054) refleja una baja concordancia entre las predicciones del modelo y los valores reales. Esto indica que, si bien el modelo logra capturar algunos patrones de los datos, su capacidad de diferenciar de manera consistente ambas clases es limitada, mostrando un desempeño modesto con margen claro de mejora.

Curva ROC - Modelo kNN
roc_data <- data.frame(
  FPR = perf@x.values[[1]],
  TPR = perf@y.values[[1]])

p_roc <- ggplot(roc_data, aes(x = FPR, y = TPR)) +
  geom_line(color = "#2F4F6A", linewidth = 1.2) +
  geom_abline(intercept = 0, slope = 1, linetype = "dashed", color = "#7D9CB2") +
  annotate("text", x = 0.65, y = 0.1,
           label = paste("AUC =", round(auc_value, 3)),
           color = "#2F4F6A", size = 5, fontface = "bold") +
  labs(
    title = "Curva ROC - Modelo knn",
    x = "(1 - Especificidad)",
    y = "Sensibilidad"
  ) +
  theme_minimal(base_size = 13) +
  theme(
    plot.title = element_text(hjust = 0.5, face = "bold", color = "#2F4F6A"),
    axis.title = element_text(color = "#2F4F6A", face = "bold"),
    axis.text = element_text(color = "#284C64"),
    panel.grid.minor = element_blank()
  )

library(plotly)
p_roc_interactivo <- ggplotly(p_roc) 

p_roc_interactivo

La curva ROC del modelo K-Nearest Neighbors (KNN) presenta una ruta que se acerca a la diagonal, con un Área Bajo la Curva (AUC) de 0.625. Esto muestra que el modelo tiene una habilidad reducida para diferenciar entre quienes consumen y quienes no consumen sustancias ilegales.

Este AUC indica que el modelo tiene un poder de clasificación que es moderadamente más alto que el azar, aunque no llega a ser muy sólido. Esta circunstancia puede explicarse por múltiples elementos: el algoritmo KNN es sensible a la escala y distribución de las variables, además de que suele actuar de forma conservadora ante clases desbalanceadas, lo cual propicia la predicción de la clase mayoritaria.

Modelo de Regresión Logística (Logit)

library(caret)
library(ROCR)
library(pROC)

set.seed(28)
index_entrena <- createDataPartition(y = con_sustan$CONSUMO_ILEGAL, p = 0.7, list = FALSE)

train_data <- con_sustan[index_entrena, ]
test_data  <- con_sustan[-index_entrena, ]

fit_logit <- glm(CONSUMO_ILEGAL ~ SEXO + EDAD + DEPRESION + ESTRATO + FAMILIA_CONSUME,
                 data = train_data,
                 family = binomial())



resultados_logit <- data.frame(
  Variable = c(
    "(Intercepto)",
    "SEXO: Mujer",
    "EDAD",
    "DEPRESION: No",
    "ESTRATO 2",
    "ESTRATO 3",
    "ESTRATO 4",
    "ESTRATO 5",
    "ESTRATO 6",
    "FAMILIA_CONSUME: Sí"
  ),
  Estimate = c(
    -0.922,
    -0.412,
    0.042,
    -0.544,
    0.447,
    0.610,
    1.015,
    0.728,
    0.762,
    0.616
  ),
  Std_Error = c(
    0.134,
    0.045,
    0.006,
    0.060,
    0.054,
    0.060,
    0.110,
    0.183,
    0.261,
    0.055
  ),
  z_value = c(
    -6.886,
    -9.105,
    7.117,
    -9.036,
    8.230,
    10.090,
    9.218,
    3.974,
    2.918,
    11.212
  ),
  p_value = c(
    "5.73e-12",
    "< 2e-16",
    "1.10e-12",
    "< 2e-16",
    "< 2e-16",
    "< 2e-16",
    "< 2e-16",
    "7.07e-05",
    "0.00353",
    "< 2e-16"
  ),
  Significancia = c(
    "***",
    "***",
    "***",
    "***",
    "***",
    "***",
    "***",
    "***",
    "**",
    "***"
  )
)

library(DT)
library(htmltools)

datatable(
  resultados_logit,
  options = list(
    scrollX = TRUE,
    autoWidth = TRUE,
    dom = 't',
    pageLength = nrow(resultados_logit),
    ordering = FALSE,
    rownames = FALSE
  ),
  class = 'display stripe hover nowrap',
  caption = htmltools::tags$caption(
    style = 'caption-side: top; text-align: center; font-weight: bold; color: #343a40;',
    "Coeficientes del Modelo Logístico"
  )
)

El modelo logístico permite identificar los factores que influyen significativamente en la probabilidad de consumo de sustancias ilegales. Se observa que todas las variables son estadísticamente significativas (p < 0,05) lo cual señala que cada una de ellas proporciona información relevante para la explicación de la variable dependiente.

Ser mujer reduce la probabilidad de consumo (-0.412), mientras que una mayor edad (0.042), pertenecer a estratos altos (4, 5 y 6) y tener familiares que consumen (0.616) aumentan dicha probabilidad. Además, no presentar depresión (-0.544) disminuye el riesgo, lo que sugiere que la presencia de esta condición puede estar asociada con un mayor consumo.

Matriz de confusión.

p_hat <- predict(fit_logit, newdata = test_data, type = "response")


pred_clase <- factor(ifelse(p_hat >= 0.5, "Si", "No"), levels = c("No", "Si"))

roc_o <- roc(response = test_data$CONSUMO_ILEGAL, predictor = p_hat, levels = c("No","Si"))
thr <- coords(roc_o, x = "best", best.method = "youden", ret = "threshold")
umbral <- as.numeric(thr)


pred_clase_opt <- factor(ifelse(p_hat >= umbral, "Si", "No"), levels = c("No","Si"))

library(DT)
library(htmltools)


resultados_logit <- data.frame(
  Metrica = c(
    "Accuracy",
    "Intervalo de Confianza (95%)",
    "No Information Rate",
    "P-Value [Acc > NIR]",
    "Kappa",
    "Mcnemar's Test P-Value",
    "Sensibilidad (Recall)",
    "Especificidad",
    "Valor Predictivo Positivo (Precision)",
    "Valor Predictivo Negativo",
    "Prevalencia",
    "Tasa de Detección (Detection Rate)",
    "Detección Esperada (Detection Prevalence)",
    "Exactitud Balanceada"
  ),
  Valor = c(
    0.6132,
    "(0.5972, 0.6290)",
    0.5664,
    "4.861e-09",
    0.2223,
    "5.769e-06",
    0.6079,
    0.6172,
    0.5487,
    0.6728,
    0.4336,
    0.2636,
    0.4804,
    0.6125
  )
)


estilo_contenedor <- "
  width: 600px;
  margin: 0 auto;
  text-align: center;
"


titulo_logit<- htmltools::tags$div(
  "Desempeño del Modelo Logit (Matriz de Confusión)",
  style = "
    font-weight: bold;
    color: white;
    background-color: #1C2E3B;
    padding: 10px;
    font-size: 18px;
    border-top-left-radius: 6px;
    border-top-right-radius: 6px;
  "
)


tabla_logit <- datatable(
  resultados_logit,
  rownames = FALSE,
  colnames = c("Métrica", "Valor"),
  class = 'display stripe hover compact cell-border',
  options = list(
    dom = 't',
    ordering = FALSE,
    paging = FALSE,
    scrollY = FALSE,
    scrollX = FALSE,
    autoWidth = TRUE,
    columnDefs = list(
      list(className = 'dt-center', targets = "_all"),
      list(width = '50%', targets = 0),
      list(width = '50%', targets = 1)
    )
  )
) %>%
  formatStyle(
    columns = names(resultados_logit),
    fontSize = '14px',
    lineHeight = '1.4',
    color = '#333333'
  )

htmltools::browsable(
  htmltools::div(
    style = estilo_contenedor,
    htmltools::tagList(
      titulo_logit,
      tabla_logit
    )
  )
)
Desempeño del Modelo Logit (Matriz de Confusión)
Exactitud (Accuracy): 0.6132

El modelo clasificó de manera correcta el 61,3% de las observaciones, el cual superó el valor esperado por azar (No Information Rate = 0.5664). Esta diferencia es significativa (p = 4.86e-09), lo que valida su capacidad de predicción. Sin embargo, aún presenta un margen de error cercano al 38%, lo que indica que hay espacio de mejora.

Sensibilidad (Recall – clase “Sí”): 0.6079

El modelo identificó correctamente el 60,7% de los casos positivos (consumidores), mostrando una habilidad moderada para detectar el grupo de interés. Aun así, persisten falsos negativos que evidencian limitaciones para reconocer todos los casos reales de consumo.

Especificidad (clase “No”): 0.6172

El modelo identificó correctamente el 61,7% de los casos negativos, lo que demuestra una capacidad aceptable para evitar falsos positivos (personas clasificadas de forma errónea como consumidoras). Aunque el valor es razonable, está ligeramente por debajo del ideal, lo que señala que el modelo da prioridad a la detección de positivos en lugar a la exactitud en los negativos.

Exactitud balanceada (Balanced Accuracy): 0.6125

El promedio entre sensibilidad y especificidad alcanza el 61,2%, lo que refleja un rendimiento intermedio sin sesgo notable hacia alguno de los grupos. Este equilibrio mejora cuando se ajusta el umbral de clasificación a 0.455, permitiendo una mejor relación entre detección y especificidad.

Valor predictivo positivo (Precisión – clase “Sí”): 0.5487

En el 54,9% de los casos en que el modelo predijo “Sí”, la clasificación fue correcta. Esto indica una capacidad moderada para confirmar de forma precisa los casos positivos. Sin embargo, aún existe una proporción considerable de falsos positivos.

Valor predictivo negativo (Precisión – clase “No”): 0.6728

El 67,3% de las predicciones “No” fueron correctas, lo que refleja una alta confiabilidad al descartar la condición positiva. En otras palabras, el modelo es más certero al identificar a las personas que no consumen, aunque sigue siendo necesario mejorar la detección de casos positivos.

Curva ROC-Logit.
roc_o <- roc(response = test_data$CONSUMO_ILEGAL,
             predictor = p_hat,
             levels = c("No", "Si"))

auc_val <- auc(roc_o)
thr <- coords(roc_o, x = "best", best.method = "youden", ret = "threshold")
umbral <- as.numeric(thr)


roc_df <- data.frame(
  FPR = 1 - roc_o$specificities,
  TPR = roc_o$sensitivities
)


p_roc_logit <- ggplot(roc_df, aes(x = FPR, y = TPR)) +
  geom_line(color = "#2F4F6A", linewidth = 1.3) +
  geom_abline(intercept = 0, slope = 1, linetype = "dashed", color = "#7D9CB2") +
  annotate("text", x = 0.65, y = 0.1,
           label = sprintf("AUC = %.3f\nUmbral = %.3f", auc_val, umbral),
           color = "#2F4F6A", size = 5, fontface = "bold") +
  labs(
    title = "Curva ROC - Modelo Logístico (Consumo Ilegal)",
    x = "(1 - Especificidad)",
    y = "Sensibilidad"
  ) +
  theme_minimal(base_size = 13) +
  theme(
    plot.title = element_text(hjust = 0.5, face = "bold", color = "#2F4F6A"),
    axis.title = element_text(color = "#2F4F6A", face = "bold"),
    axis.text = element_text(color = "#284C64"),
    panel.grid.minor = element_blank()
  )

ggplotly(p_roc_logit)

La curva ROC del modelo Logit muestra una inclinación hacia arriba que se aleja de la diagonal del azar, lo que indica que el modelo tiene una capacidad moderada para diferenciar entre consumidores y no consumidores. El área bajo la curva (AUC = 0.641) señala que el modelo es capaz de distinguir correctamente a las personas positivas en aproximadamente el 64% de las combinaciones posibles, lo cual representa un grado de discriminación aceptable aunque no muy elevado.

El umbral óptimo de 0.431 permite equilibrar la sensibilidad y la especificidad, logrando una identificación máxima de consumidores sin aumentar significativamente los falsos positivos.

Comparación de los modelos.

library(DT)
library(htmltools)


Metrica <- c(
  "Accuracy",
  "Intervalo de Confianza (95%)",
  "No Information Rate",
  "P-Value [Acc > NIR]",
  "Kappa",
  "Mcnemar's Test P-Value",
  "Sensibilidad (Recall)",
  "Especificidad",
  "Valor Predictivo Positivo (Precision)",
  "Valor Predictivo Negativo",
  "Prevalencia",
  "Tasa de Detección (Detection Rate)",
  "Detección Esperada (Detection Prevalence)",
  "Exactitud Balanceada"
)

Knn <- c(
  0.5914,
  "(0.5753, 0.6074)",
  0.5664,
  "0.001137",
  0.1054,
  "< 2.2e-16",
  0.2296,
  0.8684,
  0.5718,
  0.5955,
  0.4336,
  0.0995,
  0.1741,
  "0.5490"
)

Logit <- c(
  0.6132,
  "(0.5972, 0.6290)",
  0.5664,
  "4.861e-09",
  0.2223,
  "5.769e-06",
  0.6079,
  0.6172,
  0.5487,
  0.6728,
  0.4336,
  0.2636,
  0.4804,
  0.6125
)

tabla_modelos <- data.frame(
  Métrica = Metrica,
  KNN = Knn,
  Logit = Logit,
  stringsAsFactors = FALSE
)


estilo_contenedor <- "
  width: 700px;
  margin: 0 auto;
  text-align: center;
"

titulo_tabla <- htmltools::tags$div(
  "Comparativo de desempeño entre modelos KNN y Logit",
  style = "
    font-weight: bold;
    color: white;
    background-color: #1C2E3B;
    padding: 10px;
    font-size: 18px;
    border-top-left-radius: 6px;
    border-top-right-radius: 6px;
  "
)


tabla_comparativa <- datatable(
  tabla_modelos,
  rownames = FALSE,
  class = 'display stripe hover compact cell-border',
  options = list(
    dom = 't',
    ordering = FALSE,
    paging = FALSE,
    scrollY = FALSE,
    scrollX = FALSE,
    autoWidth = TRUE,
    columnDefs = list(
      list(className = 'dt-center', targets = "_all"),
      list(width = '40%', targets = 0),
      list(width = '30%', targets = 1),
      list(width = '30%', targets = 2)
    )
  )
) %>%
  formatStyle(
    columns = names(tabla_modelos),
    fontSize = '14px',
    lineHeight = '1.4',
    color = '#333333'
  )


htmltools::browsable(
  htmltools::div(
    style = estilo_contenedor,
    htmltools::tagList(
      titulo_tabla,
      tabla_comparativa
    )
  )
)
Comparativo de desempeño entre modelos KNN y Logit

La comparación entre los resultados de ambos modelos muestra que, en la mayoría de las métricas, el modelo Logit tiene un mejor desempeño. Su coeficiente Kappa (0.2223) y su precisión (0.6132) son mayores que los del modelo KNN, lo que señala un mejor ajuste y concordancia entre las estimaciones y los valores verdaderos. Asimismo, el Logit presenta una sensibilidad de 0.6079, lo que demuestra una habilidad superior para identificar a los consumidores con precisión; en cambio, el KNN solo alcanza 0.2296.

A pesar de que el KNN presenta una precisión ligeramente superior (0.5718) y una especificidad más alta (0.8684), su escaso nivel de detección positiva reduce su utilidad en la práctica.

Para resumir, se aconseja utilizar el modelo Logit porque brinda un rendimiento global más alto, con mejor capacidad de discriminación y una clasificación más equilibrada de los casos negativos y positivos. Por lo tanto, es el modelo más apropiado para pronosticar la conducta del consumo en este contexto.

Conclusiones.

Al finalizar el análisis con los modelos KNN y Logit, se observó que a pesar de que ambos alcanzaron cierto grado de exactitud en la clasificación de los datos, sus resultados no fueron suficientemente sólidos como para afirmar que alguno de ellos predice con alta precisión quiénes son los consumidores. El modelo Logit mostró un desempeño moderado, evidenciando un equilibrio razonable entre los aciertos y los errores, mientras que el KNN logró identificar correctamente a los “no consumidores”, pero tuvo dificultades para distinguir a los “sí”. En cambio, el Logit logró un rendimiento más balanceado, lo que indica una mejor capacidad general de discriminación.

Estas diferencias evidencian que, aunque los modelos permiten identificar ciertos patrones de comportamiento, la complejidad del fenómeno del consumo supera lo que las variables disponibles logran cubrir. Esta dificultad no radica necesariamente en la mala elección de variables, sino en la naturaleza del problema; este tipo de conducta está determinada por una variedad de factores, incluyendo los psicológicos, emocionales, sociales y familiares, que frecuentemente no se reflejan en la información cuantitativa. Elementos como el impacto del entorno, el consumo recreativo ocasional, la estabilidad emocional o las redes de apoyo pueden incidir significativamente en el consumo, aunque son difíciles de medir a nivel estadístico.

No obstante, los resultados son valiosos porque evidencian que la realidad tras el consumo no es lineal ni fácilmente predecible y que, pese a sus limitaciones, los modelos permiten un acercamiento estructurado al problema. Saber que el modelo no logra predecir con gran exactitud, lo cual nos indica que el consumo es un fenómeno variable y susceptible a múltiples factores que trascienden los datos disponibles. Aún así, los modelos aplicados aportan una comprensión inicial sobre las tendencias y permiten reconocer la importancia de ciertos factores asociados al comportamiento de consumo.

Los resultados obtenidos indican que el modelo ajustado no cumplió completamente con el objetivo del trabajo, pues aunque su rendimiento fue superior al azar, su capacidad para predecir fue restringida. Esto indica que la información utilizada no es suficiente para describir el fenómeno en su complejidad, y que se tendrían que incluir otras variables que pudieran reflejar todos los demás factores que inciden en esta problemática.

Aunque los resultados obtenidos son limitados en su capacidad para predecir, brindan un fundamento metodológico sólido para comprender mejor el fenómeno analizado. La mayor exactitud del modelo al identificar a las personas que no consumen sustancias evidencia la necesidad de ajustar las variables utilizadas y mejorar la estrategia del modelo para detectar con mayor eficacia los factores que influyen en el consumo.

Referencias.

-Paredes Inilupu, D. (2024). Data Science con R: Análisis de datos y algoritmos de predicción con R (2.ª ed., cap. 12, Aprendizaje supervisado). Recuperado de https://bookdown.org/dparedesi/data-science-con-r/aprendizaje-supervisado.html

-Departamento Administrativo Nacional de Estadística – DANE. (2019). Encuesta Nacional de Consumo de Sustancias Psicoactivas en Población General (ENCSPA) 2019: Pobreza y condiciones de vida. Salud. Recuperado de [https://microdatos.dane.gov.co/index.php/catalog/680/study-description]

-Barandica, J. (s.f.). Joaqui Barandica - Recursos de programación y análisis de datos. Recuperado de https://www.joaquibarandica.com/ Xie, Y. (2024). R Markdown: The Definitive Guide. Bookdown. Recuperado de [https://bookdown.org/yihui/rmarkdown/html-document.html]

-Barbieri I, Trivelloni M, Zani B, Palacios-Espinosa X. Consumo de sustancias psicoactivas en los contextos recreativos entre estudiantes universitarios en Colombia. Rev. Cienc. Salud 2012; 10 (Especial): 69-86.

-Álvarez-López AM, Carmona-Valencia NJ, Pérez-Rendón AL, Jaramillo-Roa A. Factores psicosociales asociados al consumo de sustancias psicoactivas en adolescentes de Pereira, Colombia. Univ. Salud. 2020;22(3):213-222. [DOI:https://doi.org/10.22267/rus.202203.193]