
Proyecto Laennec — Sesión 5: validación cruzada, con muy pocos ejemplos de la clase más pequeña
Desde la Sesión 2 hemos trabajado siempre con el mismo reparto: el train_test_split de aquella sesión decidió, de una vez, qué sonidos iban a entrenamiento y qué sonidos iban a prueba (unos 368 y 93, según pudisteis comprobar vosotros mismos con datos.shape y el support de la Sesión 3). Con ese único reparto hemos entrenado un árbol, leído su matriz de confusión y comparado árbol contra Random Forest. Cerramos esta parte del proyecto con la misma herramienta que ya usamos para cerrarla en CUTLER, Javierre y Taussig: la validación cruzada.
La pregunta de siempre, con un matiz nuevo aquí
Ya conocéis la pregunta de fondo: ¿y si el reparto concreto que nos tocó en la Sesión 2 fue, por pura suerte, más fácil (o más difícil) de lo normal? En Taussig teníamos más de 100.000 latidos, así que el riesgo era sobre todo de qué paciente concreto caía en cada partición. Aquí el riesgo es distinto y más directo: solo tenemos 461 sonidos etiquetados en total, y de esos, apenas 46 son extrasístoles. Repartidos entre entrenamiento y prueba, eso deja menos de 40 para entrenar y menos de 10 para examinar — pocos números con los que sacar conclusiones firmes de una sola vez.
Validación cruzada en 5 particiones (k-fold)
El procedimiento es idéntico al de proyectos anteriores: se divide X_entrenamiento en 5 partes, se entrena con 4 y se examina con la que queda fuera, y se repite 5 veces cambiando la parte de examen.
from sklearn.model_selection import cross_val_score
# Validación cruzada de 5 particiones, con el árbol de la Sesión 2
puntuaciones_arbol = cross_val_score(arbol, X_entrenamiento, y_entrenamiento, cv=5)
print("Exactitudes del árbol en cada partición:", puntuaciones_arbol)
print(f"Exactitud media del árbol: {puntuaciones_arbol.mean():.2%}")
# Lo mismo con el Random Forest de la Sesión 4
puntuaciones_bosque = cross_val_score(bosque, X_entrenamiento, y_entrenamiento, cv=5)
print("Exactitudes del bosque en cada partición:", puntuaciones_bosque)
print(f"Exactitud media del bosque: {puntuaciones_bosque.mean():.2%}")
A diferencia de Taussig, aquí la celda tarda segundos, no minutos — con poco más de 300 sonidos de entrenamiento y 13 características por cada uno, no hay nada parecido al volumen de datos de aquel proyecto.
[COMPLETAR CON VUESTROS DATOS REALES: exactitudes del árbol en las 5 particiones = ___ | media = ___. Exactitudes del bosque = ___ | media = ___]

Un detalle técnico que ya preparasteis vosotros mismos, sin saberlo
Cuando cross_val_score reparte los datos para un problema de clasificación como este, no lo hace completamente al azar: por defecto usa el mismo principio que aplicasteis a mano en la Sesión 2 con stratify=y, manteniendo en cada una de las 5 particiones una proporción parecida de normal, murmullo y extrasístole. Es una buena noticia — sin ese cuidado, con solo 46 extrasístoles en total, alguna partición podría quedarse con casi ninguna, y esa puntuación concreta no significaría gran cosa.
Cómo leer estos cinco números, con la clase pequeña en mente
Miradlos igual que en proyectos anteriores: la media os da una exactitud más fiable que la de un único examen, y comparar las 5 puntuaciones entre sí os dice si el modelo se comporta de forma estable o si alguna partición se aleja bastante de las demás. Pero aquí conviene un cuidado extra: con una clase de apenas 46 ejemplos repartida en 5 particiones, cada una se examina con muy pocos casos de extrasístole —unos 7 u 8—, así que no es raro que la puntuación de alguna partición concreta se mueva bastante más que en Taussig, donde cada partición tenía miles de latidos de sobra. Una diferencia grande entre particiones aquí no es necesariamente un modelo inestable: puede ser, sencillamente, el ruido normal de examinar con pocos datos.
[COMPLETAR EN CLASE: ¿cuánto se separan entre sí las 5 exactitudes del bosque? ¿Diríais que el modelo es estable, o que el número pequeño de extrasístoles introduce bastante variación de una partición a otra?]
Una honestidad que ya aprendisteis en Taussig, aplicada aquí de otra forma
En Taussig no podíamos saber si latidos del mismo paciente habían caído repartidos entre entrenamiento y examen, y eso podía hacer que la exactitud pareciera mejor de lo que sería con un paciente nuevo. Aquí el dataset no nos da tampoco esa información sobre los sonidos —no sabemos con certeza si dos grabaciones distintas pueden venir de la misma persona—, así que no podemos descartar del todo un problema parecido. Lo que sí sabemos con seguridad, y es motivo suficiente de cautela por sí solo, es lo pequeña que es la clase extrasístole: cualquier número bueno que saquemos con solo 46 ejemplos merece leerse con más cuidado que uno sacado con miles.
Próximo paso
Con esto sabemos si podemos fiarnos de los números que hemos visto hasta ahora. En la última sesión del proyecto vamos a poner a los modelos a prueba de la forma más directa posible: coger sonidos concretos —incluida, si es posible, alguna extrasístole real— y comprobar, uno a uno, si el modelo los reconoce, cerrando el proyecto con un repaso completo de todo el camino recorrido.



