Analítica de Personas · Semestre otoño 2026 · Semana 14 · Prof. René Gempp
Durante trece semanas has aprendido técnicas una por una. Es hora de ordenarlas con una sola pregunta: ¿hay una variable respuesta (Y) que quieras predecir o explicar?
| Dimensión | Supervisado | No supervisado |
|---|---|---|
| ¿Hay variable respuesta Y? | Sí (conocida) | No |
| Objetivo | Predecir / explicar Y | Descubrir estructura |
| ¿Cómo se evalúa? | Predicción vs. Y real (AUC, error de prueba) | Interpretabilidad, estabilidad, validación externa |
| Ejemplos en el curso | Logística, Cox, árbol, random forest | EFA, clustering |
El problema de hoy en InnovaCo es supervisado: el CEO quiere predecir la rotación (la Y), pero con dos exigencias nuevas —reglas que sus gerentes entiendan y mayor poder predictivo que la regresión logística de la Clase 3.
Un árbol de decisión (algoritmo CART; Breiman, Friedman, Olshen & Stone, 1984) predice la respuesta dividiendo el conjunto de empleados en grupos cada vez más homogéneos. En cada paso busca la variable y el punto de corte que mejor separan a quienes rotan de quienes no.
"Mejor separar" significa reducir la impureza del nodo. La medida más común es el índice de Gini:
donde p̂k es la proporción de la clase k en el nodo. Gini vale 0 cuando el nodo es puro (todos rotan o nadie rota) y es máximo cuando las clases están mitad y mitad. El árbol elige, en cada división, el corte que produce los nodos hijos más puros.
El resultado es un conjunto de reglas legibles: "Si antigüedad < 2 años Y satisfacción ≤ 2, entonces riesgo alto de rotación." Esto es exactamente lo que pidió el CEO: comunicable, sin odds ratios, accionable por un jefe de línea.
| Virtud del árbol | Limitación del árbol |
|---|---|
| Reglas interpretables por no técnicos | Inestable: pequeños cambios en los datos cambian el árbol (alta varianza) |
| No asume linealidad ni distribución | Tiende a sobreajustar si no se poda |
| Captura interacciones automáticamente | Predice menos que los métodos de ensemble |
| No necesita estandarizar variables | Sesgo hacia variables con muchos cortes posibles |
library(rpart)
library(rpart.plot)
set.seed(2026)
arbol <- rpart(
rotacion ~ ., # Y ~ todos los predictores
data = train,
method = "class", # clasificación (no regresión)
control = rpart.control(cp = 0.005, minbucket = 20)
)
# Visualizar: el árbol como reglas
rpart.plot(arbol, type = 2, extra = 104,
box.palette = list("#A7BEAE", "#B85042"),
main = "¿Quién está en riesgo de rotar?")
# Las reglas en texto
rpart.rules(arbol, cover = TRUE)
Cómo leer el gráfico: cada nodo muestra la clase mayoritaria, la probabilidad de rotación y el porcentaje de empleados que caen ahí. Sigues las ramas según se cumplan o no las condiciones, y llegas a una hoja con una predicción. extra = 104 muestra la proporción de cada clase y el porcentaje del total en cada nodo.
Un árbol sin restricciones puede crecer hasta clasificar perfectamente los datos con los que se entrenó —memorizando incluso el ruido. Eso es sobreajuste (overfitting): el modelo se ajusta tan bien a la muestra que falla con datos nuevos.
Detrás está el compromiso sesgo–varianza:
El punto óptimo está en el medio (James, Witten, Hastie & Tibshirani, 2021, cap. 2). La pregunta es: ¿cómo lo encontramos sin engañarnos? La respuesta es la sección siguiente.
El estándar mínimo para evaluar honestamente cualquier modelo predictivo es separar los datos en dos:
set.seed(2026)
idx_train <- sample(seq_len(nrow(datos)), size = 0.8 * nrow(datos))
train <- datos[idx_train, ]
test <- datos[-idx_train, ]
En los árboles, el control del sobreajuste se hace podando: se deja crecer el árbol y luego se recorta con el parámetro de complejidad (cp). Se elige el cp que minimiza el error de validación cruzada (xerror).
printcp(arbol) # tabla de complejidad: buscar el menor xerror
plotcp(arbol)
cp_opt <- arbol$cptable[which.min(arbol$cptable[, "xerror"]), "CP"]
arbol_podado <- prune(arbol, cp = cp_opt)
Si el problema del árbol es la alta varianza, la solución de Breiman (2001) es elegante: construir cientos de árboles y promediarlos. Un random forest combina dos ideas:
La predicción final es el voto mayoritario (o el promedio de probabilidades) de todos los árboles. Como cada empleado queda fuera de la muestra de aproximadamente un tercio de los árboles, el bosque estima su propio error sin necesidad de un test separado: el error out-of-bag (OOB).
library(ranger)
set.seed(2026)
rf <- ranger(
rotacion ~ .,
data = train,
num.trees = 500,
importance = "permutation", # menos sesgada que "impurity"
probability = TRUE # devuelve probabilidades
)
rf$prediction.error # error out-of-bag
ranger y no randomForest? ranger (Wright & Ziegler, 2017) es una implementación en C++ mucho más rápida, ideal para datasets grandes, con la misma lógica. Para 1.200 empleados la diferencia es trivial, pero es la herramienta estándar hoy.
El bosque no entrega un árbol legible, pero sí ordena las variables por importancia:
importancia <- tibble(
variable = names(rf$variable.importance),
importancia = rf$variable.importance
) |>
arrange(desc(importancia))
ggplot(importancia, aes(reorder(variable, importancia), importancia)) +
geom_col(fill = col_teal) +
coord_flip()
ingreso_mensual está casi determinado por nivel_jerarquico (la colinealidad que diagnosticamos con VIF en la Clase 5): el ingreso "se lleva" la importancia y la jerarquía aparece baja, aunque ambos midan casi lo mismo.
Para comparar modelos necesitamos métricas calculadas sobre el test. La matriz de confusión cruza lo real con lo predicho:
| Predicho: No rota | Predicho: Rota | |
|---|---|---|
| Real: No rota | Verdadero negativo | Falso positivo |
| Real: Rota | Falso negativo | Verdadero positivo |
De ahí salen la sensibilidad (proporción de quienes rotan que el modelo detecta) y la especificidad (proporción de quienes se quedan que el modelo identifica). El AUC (área bajo la curva ROC) resume el desempeño en un solo número entre 0,5 (azar) y 1 (perfecto), y es insensible al punto de corte y al desbalance.
library(pROC)
p_logit <- predict(logit, newdata = test, type = "response")
p_arbol <- predict(arbol_podado, newdata = test, type = "prob")[, "Sí"]
p_rf <- predict(rf, data = test)$predictions[, "Sí"]
auc(test$rotacion, p_rf) # AUC del random forest
El corazón de la clase es comparar la logística, el árbol y el random forest sobre el mismo problema y el mismo test:
| Modelo | Fortaleza | Salida | Cuándo usarlo |
|---|---|---|---|
| Logística | Explicar | Odds ratios, IC, p-value | Cuantificar el efecto ajustado de cada predictor |
| Árbol | Comunicar | Reglas "si–entonces" | Audiencia no técnica; protocolo de acción simple |
| Random forest | Predecir | Probabilidad + importancia | Máxima precisión predictiva |
De aquí se decanta la regla que guía la elección:
No existe el "mejor modelo" en abstracto; existe el modelo correcto para el propósito. Si el directorio necesita entender por qué, la logística gana aunque prediga un poco menos. Si un jefe necesita un protocolo, el árbol gana aunque sea inestable. Si lo único que importa es anticipar, el random forest gana aunque sea una caja negra.
xgboost, lightgbm), que suele superar al random forest; validación cruzada k-fold en vez de una sola partición train/test; flujos reproducibles con tidymodels; e interpretabilidad de modelos de caja negra con valores de Shapley (fastshap) o LIME, que explican predicciones individuales. La postura del curso es la de siempre: enseñar bien lo estándar, declarar la frontera y dar las referencias.
Una nota ética que prepara la Clase 17: un modelo que predice quién va a renunciar es también un modelo que puede usarse para etiquetar personas. Predecir no obliga a actuar, y actuar sobre una predicción (no promover a alguien "porque el modelo dice que se irá") puede volverse una profecía autocumplida. La técnica es poderosa; el juicio sobre cómo usarla es responsabilidad del analista.
Los árboles y el random forest amplían tu repertorio supervisado más allá de la regresión: los árboles aportan comunicabilidad (reglas legibles) y el random forest aporta poder predictivo (a costa de la interpretabilidad). Pero el aprendizaje más importante del apunte no es técnico: es la disciplina de evaluar la predicción sobre datos no vistos y la humildad de reconocer que más complejidad no garantiza mejor predicción. En el Apunte 32 cruzamos la frontera hacia el aprendizaje no supervisado, donde el problema deja de tener etiqueta.
rpart(), rpart.plot(), rpart.rules(), printcp(), prune(), sample() (train/test), ranger(), rf$variable.importance, pROC::auc(), predict(type = "prob").
Breiman, L. (2001). Random forests. Machine Learning, 45(1), 5–32. https://doi.org/10.1023/A:1010933404324
Breiman, L., Friedman, J. H., Olshen, R. A., & Stone, C. J. (1984). Classification and regression trees. Wadsworth.
James, G., Witten, D., Hastie, T., & Tibshirani, R. (2021). An introduction to statistical learning with applications in R (2.ª ed.). Springer. https://www.statlearning.com
Kuhn, M., & Johnson, K. (2013). Applied predictive modeling. Springer.
Putka, D. J., Beatty, A. S., & Reeder, M. C. (2018). Modern prediction methods: New perspectives on a common problem. Organizational Research Methods, 21(3), 689–732. https://doi.org/10.1177/1094428117697041
Strobl, C., Boulesteix, A.-L., Zeileis, A., & Hothorn, T. (2007). Bias in random forest variable importance measures: Illustrations, sources and a solution. BMC Bioinformatics, 8, 25. https://doi.org/10.1186/1471-2105-8-25
Wright, M. N., & Ziegler, A. (2017). ranger: A fast implementation of random forests for high dimensional data in C++ and R. Journal of Statistical Software, 77(1), 1–17. https://doi.org/10.18637/jss.v077.i01