Presentado por:
Erik Tombe-2376283
Samuel Santander-2451045
Ana Sofía Ramos-2463326
Fecha de entrega: 11 de junio de 2026
Los algoritmos de clasificación son métodos de aprendizaje automático supervisado que permiten asignar una categoría o etiqueta a nuevas observaciones, aprendiendo patrones a partir de datos históricos etiquetados. Son ampliamente utilizados en diagnóstico médico, detección de fraude, análisis de riesgo crediticio y muchos otros campos de la ingeniería industrial.
El algoritmo «Naive Bayes» es un clasificador probabilístico basado en el «Teorema de Bayes», el modelo fue creado por el matemático inglés, Thomas Bayes (1701 – 1761).
Naive Bayes es un algoritmo con aplicaciones muy versátiles, debiendo ser utilizado en los casos en que las variables sean condicionalmente independientes. También es un algoritmo que presenta un óptimo desempeño clasificando categorías muy bien separadas y para datos con dimensiones altas, donde la complejidad del modelo es menos importante.
El algoritmo se basa en el Teorema de Bayes:
\[\color{#BA4A00}{\Large P(A|B) = (P(B|A) \times P(A)) \div P(B)}\]
Dónde:
Veamos un ejemplo del Teorema de Bayes en el diagnóstico de enfermedades:
El algoritmo Naive Bayes puede predecir con una exactitud superior al 75% si un paciente tiene o no diabetes, utilizando variables clínicas como glucosa, presión arterial, índice de masa corporal y edad.
Para verificar esta hipótesis, se aplicó el algoritmo sobre el dataset Pima Indians Diabetes Database, el cual fue obtenido de la plataforma otorgada por el profesor (Kaggle). Este conjunto de datos contiene registros clínicos de pacientes de sexo femenino mayores de 21 años, pertenecientes a la comunidad Pima, permitiendo comparar las predicciones generadas por el modelo con los diagnósticos reales de cada paciente.
La base de datos contiene información clínica de 768 pacientes mujeres de origen indígena Pima. Las variables son:
datos_diabetes <- read.csv("diabetes_traducido.csv")
datos_diabetes <- na.omit(datos_diabetes)
head(datos_diabetes, 5) %>%
kbl(
align = "c",
caption = "Primeros registros de salud"
) %>%
kable_styling(
bootstrap_options = c(
"striped",
"hover",
"condensed"
),
full_width = FALSE
) %>%
row_spec(
0,
bold = TRUE,
color = "white",
background = "#BA4A00"
)
| Embarazos | Glucosa | Presion_Arterial | Grosor_Pliegue_Cutaneo | Insulina | IMC | Funcion_Hereditaria_Diabetes | Edad | Resultado |
|---|---|---|---|---|---|---|---|---|
| 6 | 148 | 72 | 35 | 0 | 33.6 | 0.627 | 50 | 1 |
| 1 | 85 | 66 | 29 | 0 | 26.6 | 0.351 | 31 | 0 |
| 8 | 183 | 64 | 0 | 0 | 23.3 | 0.672 | 32 | 1 |
| 1 | 89 | 66 | 23 | 94 | 28.1 | 0.167 | 21 | 0 |
| 0 | 137 | 40 | 35 | 168 | 43.1 | 2.288 | 33 | 1 |
ggplot(
datos_diabetes,
aes(
x = Glucosa,
y = Insulina,
color = as.factor(Resultado)
)
) +
geom_point(alpha = 0.5) +
geom_smooth(
method = "lm",
color = "red"
) +
labs(
title = "Relación Glucosa vs Insulina",
x = "Glucosa",
y = "Insulina",
color = "Resultado"
) +
theme_minimal()
## `geom_smooth()` using formula = 'y ~ x'
ggplot(datos_diabetes, aes(x = Glucosa)) +
geom_density(
fill = "#BA4A00",
alpha = 0.3
) +
scale_x_log10() +
labs(
title = "Distribución Lognormal: Glucosa",
x = "Log(Glucosa)",
y = "Densidad"
) +
theme_minimal()
## Warning in scale_x_log10(): log-10 transformation introduced infinite values.
## Warning: Removed 5 rows containing non-finite outside the scale range
## (`stat_density()`).
media_d <- mean(datos_diabetes$Edad)
sd_d <- sd(datos_diabetes$Edad)
ggplot(datos_diabetes, aes(x = Edad)) +
geom_histogram(
aes(y = after_stat(density)),
bins = 20,
fill = "skyblue",
color = "white"
) +
stat_function(
fun = dnorm,
args = list(
mean = media_d,
sd = sd_d
),
color = "darkred",
linewidth = 1
) +
labs(
title = "Distribución Gaussiana: Edad",
x = "Edad",
y = "Densidad"
) +
theme_minimal()
frec_d <- table(datos_diabetes$Embarazos)
prob_d <- as.numeric(frec_d) /
length(datos_diabetes$Embarazos)
plot(
as.numeric(names(frec_d)),
prob_d,
type = "b",
pch = 19,
col = "orange",
main = "Poisson: Número de Embarazos",
xlab = "Frecuencia",
ylab = "Probabilidad"
)
El modelo Naive Bayes aprende la probabilidad de cada valor de las variables clínicas dado el diagnóstico (con o sin diabetes). Luego, para un nuevo paciente, multiplica esas probabilidades y predice la clase más probable. Los pasos son:
# 1. usa los datos para saber quien tiene diabetes y quien no
datos_diabetes$Resultado <- as.factor(datos_diabetes$Resultado)
# 2. Dividir datos: 70% entrenamiento - 30% prueba
set.seed(42)
indice_muesta <- createDataPartition(datos_diabetes$Resultado, p = 0.7, list = FALSE)
datos_entrenamiento <- datos_diabetes[indice_muesta, ]
datos_prueba <- datos_diabetes[-indice_muesta, ]
# 3. Entrenar el modelo Naive Bayes
modelo_bayes <- naiveBayes(Resultado ~ Glucosa + Presion_Arterial + IMC + Edad + Embarazos,
data = datos_entrenamiento)
# 4. Predecir sobre datos de prueba y evaluar
prediciones_diabetes <- predict(modelo_bayes, datos_prueba)
matrix_diabetes <- confusionMatrix(prediciones_diabetes, datos_prueba$Resultado)
metricas <- c(
Exactitud = as.numeric(matrix_diabetes$overall["Accuracy"]),
Sensibilidad = as.numeric(matrix_diabetes$byClass["Sensitivity"]),
Especificidad = as.numeric(matrix_diabetes$byClass["Specificity"])
) * 100
barplot(metricas,
col = "#BA4A00",
ylim = c(0, 110),
main = "Métricas del Modelo Naive Bayes",
ylab = "Porcentaje (%)",
border = "white",
las = 1)
abline(h = 75, col = "red", lty = 2, lwd = 2)
text(x = c(0.7, 1.9, 3.1),
y = metricas + 4,
labels = paste0(round(metricas, 1), "%"),
cex = 1, font = 2)
El modelo Naive Bayes fue evaluado sobre 230 pacientes del conjunto de prueba, obteniendo una exactitud del 77.39%, una sensibilidad del 86% y una especificidad del 61.25%.
La sensibilidad indica la capacidad del modelo para detectar correctamente a los pacientes diabéticos, mientras que la especificidad refleja su capacidad para identificar a los pacientes sanos. En un contexto clínico, ambas métricas son igualmente importantes para garantizar un diagnóstico confiable.
Con base en estos resultados, la hipótesis H SE VERIFICA, ya que el modelo superó el umbral del 75% con una exactitud de 77.39%..
Las barras de color naranja superan el umbral del 75% marcado por la línea roja, mientras que las grises no lo alcanzan. Una sensibilidad alta significa que el modelo detecta bien a los pacientes diabéticos; una especificidad alta significa que no confunde a los pacientes sanos.
Un Árbol de Decisión es un algoritmo de aprendizaje supervisado que representa las decisiones de clasificación en forma de árbol jerárquico. Cada nodo interno representa una pregunta sobre una variable, cada rama representa una posible respuesta, y cada hoja (nodo terminal) representa la clase predicha.
El árbol se construye dividiendo recursivamente el conjunto de datos en subconjuntos más homogéneos usando criterios matemáticos de impureza. Los más comunes son el Índice de Gini y la Entropía de Información.
Índice de Gini — Mide qué tan mezcladas están las clases en un nodo. Un valor de 0 significa nodo puro (todos de la misma clase):
\[\color{#BA4A00}{\Large Gini(t) = 1 - \sum_{k=1}^{K} p_k^2}\]
Entropía — mide el desorden o incertidumbre dentro de un nodo. A mayor entropía, más mezcladas están las clases:
\[\color{#BA4A00}{\Large H(t) = -\sum_{k=1}^{K} p_k \log_2(p_k)}\]
Ganancia de Información — mide cuánto mejora la pureza al dividir un nodo por una variable. El árbol elige siempre la variable con mayor ganancia:
\[\color{#BA4A00}{\Large IG(t, a) = H(t) - \sum_{v \in vals(a)} \frac{|t_v|}{|t|} H(t_v)}\]
Donde:
El algoritmo Árbol de Decisión puede clasificar correctamente si un préstamo será pagado o incumplido (estado del préstamo: 0 = pagado, 1 = incumplido) con una exactitud superior al 80%, utilizando variables financieras como los ingresos de la persona, la edad, y la tasa de interés del préstamo.
Para verificar esta hipótesis, se construyó un Árbol de Decisión sobre el Credit Risk Dataset, obtenido de la plataforma otorgada por el profesor (Kaggle), permitiendo comparar las clasificaciones generadas por el modelo con el estado real de cada préstamo.
Se utiliza un dataset de riesgo crediticio bancario, las variables empleadas son:
datos_credito <- read.csv("credit_risk_dataset_traducido.csv")
datos_credito <- na.omit(datos_credito)
head(datos_credito, 5) %>%
kbl(
align = "c",
caption = "Primeros registros financieros"
) %>%
kable_styling(
bootstrap_options = c(
"striped",
"hover",
"condensed"
),
full_width = FALSE
) %>%
row_spec(
0,
bold = TRUE,
color = "white",
background = "#BA4A00"
)
| edad_persona | ingresos_persona | vivienda_persona | antiguedad_empleo | intencion_prestamo | grado_prestamo | monto_prestamo | tasa_interes | estado_prestamo | porcentaje_ingreso | incumplimiento_previo | longitud_historial. |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 24 | 54400 | ARRIENDO | 8 | MÉDICO | C | 35000 | 14.27 | 1 | 0.55 | SÍ | 4 |
| 21 | 9900 | PROPIA | 2 | EMPRENDIMIENTO | A | 2500 | 7.14 | 1 | 0.25 | NO | 2 |
| 26 | 77100 | ARRIENDO | 8 | EDUCACIÓN | B | 35000 | 12.42 | 1 | 0.45 | NO | 3 |
| 24 | 78956 | ARRIENDO | 5 | MÉDICO | B | 35000 | 11.11 | 1 | 0.44 | NO | 4 |
| 24 | 83000 | ARRIENDO | 8 | PERSONAL | A | 35000 | 8.90 | 1 | 0.42 | NO | 2 |
ggplot(
datos_credito,
aes(
x = ingresos_persona,
y = monto_prestamo,
color = as.factor(estado_prestamo)
)
) +
geom_point(alpha = 0.4) +
geom_smooth(
method = "lm",
color = "red"
) +
labs(
title = "Relación Ingresos vs Monto Préstamo",
x = "Ingresos",
y = "Monto",
color = "Estado del Préstamo\n(0=Pagado, 1=Incumplido)"
) +
theme_minimal()
## `geom_smooth()` using formula = 'y ~ x'
El Árbol de Decisión aprende reglas de división a partir de los datos de entrenamiento. Para clasificar un préstamo nuevo, recorre el árbol respondiendo preguntas sobre las variables financieras hasta llegar a una hoja que indica si el préstamo será pagado o incumplido. Los pasos son:
# 1. Convertir la variable objetivo a factor
datos_credito$estado_prestamo <- as.factor(datos_credito$estado_prestamo)
# 2. Dividir datos: 70% entrenamiento - 30% prueba
set.seed(42)
indice_credito <- createDataPartition(datos_credito$estado_prestamo, p = 0.7, list = FALSE)
datos_entre <- datos_credito[indice_credito, ]
datos_prueb <- datos_credito[-indice_credito, ]
# 3. Construir el Árbol de Decisión
modelo_tree <- rpart(
estado_prestamo ~ ingresos_persona + edad_persona + tasa_interes,
data = datos_entre,
method = "class"
)
# 4. Visualizar el árbol
rpart.plot(
modelo_tree,
main = "Árbol de Decisión: Estado del Préstamo"
)
# 5. Predecir y evaluar
pred_tree <- predict(modelo_tree, datos_prueb, type = "class")
cm_tree <- confusionMatrix(pred_tree, datos_prueb$estado_prestamo)
# 6. Calcular métricas para el texto
exactitud_tree <- round(as.numeric(cm_tree$overall["Accuracy"]) * 100, 2)
total_tree <- sum(cm_tree$table)
imp_sorted <- sort(modelo_tree$variable.importance, decreasing = TRUE)
var_top <- names(imp_sorted)[1]
imp_top <- round(imp_sorted[1] / sum(imp_sorted) * 100, 1)
imp <- modelo_tree$variable.importance
imp_norm <- sort(imp / sum(imp) * 100, decreasing = FALSE)
par(mar = c(5, 16, 4, 4))
barplot(imp_norm,
horiz = TRUE,
col = "#BA4A00",
main = "Variables más importantes para el árbol de decisión",
xlab = "Importancia relativa (%)",
border = "white",
las = 1,
xlim = c(0, max(imp_norm) + 10))
text(x = imp_norm + 1.5,
y = seq(0.7, length(imp_norm) * 1.2, by = 1.2),
labels = paste0(round(imp_norm, 1), "%"),
cex = 0.9, font = 2)
El modelo Árbol de Decisión fue evaluado sobre 8590 clientes del conjunto de prueba, alcanzando una exactitud del 82.43%.
La variable más determinante en las decisiones del árbol fue tasa_interes, con una importancia relativa del 65.5%, lo que indica que esta característica es la que mejor separa los préstamos pagados de los incumplidos.
Con base en estos resultados, la hipótesis H SE VERIFICA, ya que el modelo superó el umbral del 80% con una exactitud de 82.43%..
La gráfica muestra qué tan importante fue cada variable para las decisiones del árbol. Las variables con mayor porcentaje fueron las más utilizadas en los nodos superiores, es decir, los factores que más influyen en el estado del préstamo de un cliente.