Misión 7. Enseña a predecir
▶ Abrir en Colab ▶ Ejecutar en Binder
Colab abre en segundos. Binder, la primera vez, construye el entorno en la nube (10-20 min) y luego queda en caché.
Misión 7. Encargo: «que el ordenador adivine el género de una canción por su sonido».
Victoria: un acierto que puedes comprobar.
Insignia en juego: domador de modelos.
El encargo
Hasta aquí la máquina ha mirado el pasado. Le pediste que contara canciones, que limpiara datos sucios, que dibujara el mapa sonoro de un catálogo —y lo hizo, obediente, con números que ya existían—. Pero hoy el encargo cambia de tarea. Hoy vas a pedirle algo que ninguna casilla del fichero contiene: que adivine el género de una canción escuchando solo su sonido. Que le des lo bailable que es, cuánta energía tiene, su tono alegre o triste, su tempo y su duración, y te conteste con una etiqueta —«esto es reggaetón», «esto es música clásica»— sin haber leído nunca el título ni el nombre del artista. Un juicio. Una etiqueta sobre algo que la máquina no tiene delante.
Suena a oído mágico, y por eso conviene decir enseguida dónde está el truco —porque no lo hay—. La máquina no «oye» nada; lo que hace es mucho más terrenal y mucho más útil: aprende de cientos de canciones ya etiquetadas qué combinación de rasgos suele acompañar a cada género, y cuando le das una canción nueva, responde con aquello que aprendió. Es lo mismo que haces tú cuando, al oír una guitarra distorsionada, una voz que grita y un ritmo a mil, dices «esto es heavy metal» sin ser crítico musical: no adivinas, reconoces un patrón que has oído muchas veces. Enseñar a la máquina a hacer eso —a reconocer patrones y usarlos para clasificar— se llama aprendizaje automático, y es de aquello que va esta misión.
Y no es un juguete de laboratorio: es, probablemente, la tecnología que más está cambiando el mundo mientras lees esto. La misma idea que vas a usar con la música —aprender un patrón de cientos de ejemplos y aplicarlo a un caso nuevo— es la que hay detrás de la app que te recomienda canciones, del corrector que adivina la palabra que ibas a escribir, del sistema que ayuda a un médico a leer una radiografía o del coche que se conduce solo. Cambia el dato (canciones, palabras, radiografías, carreteras) y cambia el modelo, pero el motor es este, el que vas a montar tú hoy con un puñado de géneros. Aprenderlo con cinco rasgos y unas canciones es aprenderlo para todo lo demás.
La trampa que hay que evitar.
Un juicio es fácil de soltar y difícil de defender. Cualquiera puede decir «esto es jazz»; lo honesto —y aquello que separa a un analista de un charlatán— es poder contestar a la pregunta siguiente: ¿y cómo sé que tu modelo acierta de verdad?. Toda esta misión gira alrededor de esa pregunta. No te vas a conformar con que el ordenador clasifique: le vas a medir el acierto, con honestidad, sobre canciones que no ha oído nunca. Tu victoria no será una etiqueta bonita; será un acierto que puedes comprobar, con su porcentaje puesto encima de la mesa. Cuando lo logres, te habrás ganado la insignia domador de modelos: porque un modelo que no sabes medir es un caballo salvaje, y tú vas a aprender a domarlo.
El mapa de la misión.
Como siempre, no saltamos a la victoria: la construimos pieza a pieza, y cada pieza es una micro-victoria que puedes enseñar. Este es el recorrido:
Entender qué es aprender de ejemplos: la idea entera del aprendizaje automático, sin una sola fórmula.
Partir los datos en entrenamiento y prueba: la regla de oro para no hacerte trampas mirándote el examen.
Entrenar tu primer modelo con scikit-learn: las dos palabras mágicas,
fitypredict.Medir el acierto de las clasificaciones: qué porcentaje de canciones colocas en su género.
Descubrir el sobreajuste: el modelo que empolla sin entender y se estrella en cuanto le cambias las canciones.
Comparar dos modelos y quedarte, con pruebas, con el que más acierta.
La victoria: adivinar el género de canciones que el modelo no oyó jamás, y comprobar cuánto acierta.
Cada paso desbloquea el siguiente. Y esta misión tiene su propia regla de oro, hermana de la que ya conoces (predice antes de ejecutar): el examen no se toca hasta el final. Ya verás por qué es sagrada. Vamos allá.
La herramienta
Aprender de ejemplos
Para de leer un segundo y contesta: ¿cómo distingues un perro de un gato? No hay una regla que te sepas de memoria —nadie te dio una lista de «si las orejas son así y el hocico asá»—. Lo aprendiste de otra manera: viste muchísimos perros y muchísimos gatos, cada uno con la etiqueta puesta («eso es un perro», «eso es un gato»), y tu cerebro fue sacando solo el patrón. Ahora reconoces un perro que no has visto nunca, de una raza rara, en una foto borrosa. Aprendiste de ejemplos, no de reglas.
El aprendizaje automático es exactamente eso, hecho por una máquina. Le das muchos ejemplos, cada uno con dos partes:
Las pistas (los profesionales las llaman características o, en inglés, features): aquello que sabes de cada caso. En nuestra música serán cinco rasgos de audio —lo bailable (
danceability), laenergy, el tono alegre (valence), eltempoy la duración (duration_ms)—.La respuesta (el objetivo): la etiqueta que quieres adivinar. Aquí, el
track_genre, el género de esa canción.
La máquina mira cientos de ejemplos con las dos partes puestas —rasgos y género, rasgos y género— y busca sola la relación que las une: qué sonido suele acompañar a cada género. A esa relación aprendida la llamamos modelo. Una vez que la tiene, le puedes dar unos rasgos sin la etiqueta —una canción nueva— y el modelo la completa: clasifica. Eso es todo. No hay magia, hay ejemplos.
Los datos: canciones con rasgos
Necesitamos ejemplos, y con la etiqueta puesta. Vamos a usar musica.csv, el catálogo de Spotify que ya conoces: cada fila es una canción real, con sus rasgos de audio medidos y su género anotado. Para que la lección sea clara, empezamos con un puñado de géneros bien distintos y reconocibles —música clásica, reggaetón, heavy metal, hip-hop y jazz—. Cárgalo con pandas, que ya conoces, y quédate solo con esos cinco:
import pandas as pd
musica = pd.read_csv("musica.csv")
generos = ["classical", "reggaeton", "heavy-metal", "hip-hop", "jazz"]
canciones = musica[musica["track_genre"].isin(generos)].copy()
print("Canciones:", len(canciones))
print(canciones["track_genre"].value_counts())Canciones: 148
track_genre
classical 30
heavy-metal 30
reggaeton 30
hip-hop 29
jazz 29
Ciento cuarenta y ocho canciones, unas treinta de cada género: un reparto equilibrado, que nos vendrá muy bien para no engañarnos al medir. Échale un vistazo a los rasgos con los que trabajará el modelo —mirar los datos antes de modelarlos no es opcional, es la primera regla del oficio—:
pistas = ["danceability", "energy", "valence", "tempo", "duration_ms"]
print(canciones[["track_genre"] + pistas].head(4)) track_genre danceability energy valence tempo duration_ms
469 classical 0.447 0.4490 0.0360 92.468 315426
470 classical 0.191 0.0582 0.0454 132.614 357706
471 classical 0.315 0.2200 0.1160 145.195 188786
472 classical 0.468 0.0127 0.3560 72.776 205866
Cada fila es una canción, y en ella tienes las cinco pistas —danceability, energy, valence, tempo, duration_ms— y la respuesta que la máquina deberá aprender a adivinar, el track_genre. Fíjate en esas cuatro piezas de clásica: poco bailables (todas por debajo de 0,5) y con energía muy baja en varias (0,06, 0,01) —piano y cuerdas, nada de percusión—. Cientos de filas como esas son el material de estudio de tu modelo.
Un apunte honesto, porque en esta edición no escondemos nada: estos datos son reales, medidos por Spotify sobre canciones de verdad. Los rasgos como danceability o energy no los inventamos nosotros; los calcula un sistema a partir del audio. Eso los hace más interesantes —son música que existe— y también más difíciles: el mundo real es ruidoso, y ya verás que ni el mejor modelo acierta siempre. La técnica que vas a aprender es idéntica para estos datos y para cualquier otro.
Mira el patrón con tus propios ojos
Antes de pedirle a ninguna máquina que aprenda un patrón, comprueba tú mismo que el patrón existe. Sería absurdo entrenar un modelo para adivinar algo que no depende de nada. Así que hagamos lo que ya sabes hacer desde la Misión 4: agrupar con pandas y mirar medias. Cada género tiene una firma acústica; vamos a verla en dos rasgos, la energía y lo bailable.
firma = canciones.groupby("track_genre")[pistas].mean()
print(firma[["energy", "danceability"]].round(2)) energy danceability
track_genre
classical 0.14 0.32
heavy-metal 0.89 0.48
hip-hop 0.66 0.75
jazz 0.45 0.56
reggaeton 0.68 0.77
¡Ahí están las firmas, clarísimas! La clásica es un mundo aparte: energía 0,14, la más baja con diferencia, y poco baile —piano y cuerdas, nada de percusión—. El heavy metal está en el otro extremo de energía (0,89, casi el tope), pero no es bailable (0,48): pura potencia. Y el reggaetón y el hip-hop comparten techo de danceability (0,77 y 0,75): están hechos para moverse. Los rasgos contienen información sobre el género. No son adorno; llevan dentro la señal que tu modelo va a exprimir.
Fíjate también en una pista de por dónde vendrán los problemas: reggaetón y hip-hop se parecen mucho (ambos bailables, energías cercanas). Si el modelo confunde algún género con otro, apuesta a que serán esos dos. Con el patrón confirmado a ojo, ya tiene sentido pedirle a la máquina que lo aprenda entero, combinando los cinco rasgos a la vez —algo que, con tantas canciones, a ojo sería imposible—.
El truco de todo: no te mires el examen
Aquí viene la idea más importante de la misión, y no es de programación sino de honestidad. Presta atención.
Imagina que tu profesor te da veinte problemas para practicar y te avisa: «el examen serán estos mismos veinte». Estudias, te los aprendes de memoria, y sacas un diez. ¿Ese diez demuestra que entiendes la materia? No. Demuestra que tienes buena memoria. En cuanto te pongan un problema distinto, se verá la verdad. Para saber si de verdad aprendiste, el examen tiene que traer preguntas que no has visto antes.
Con un modelo pasa exactamente igual. Si lo entrenas con unas canciones y luego le mides el acierto con esas mismas canciones, no estás midiendo si aprendió el patrón: estás midiendo su memoria. Y un modelo con buena memoria te engaña —y te engañas tú— con una nota inflada que se derrumba con canciones nuevas. Por eso, desde el primer minuto, los datos se parten en dos montones:
El entrenamiento (train): el material de estudio. Es lo único que el modelo llega a ver; con esto aprende.
La prueba o examen (test): se aparta en un cajón y no se toca. Hace de «canciones del futuro»: temas que el modelo no verá al aprender, y solo sirven para juzgarlo al final, una vez.
Partir es una línea. scikit-learn —la caja de herramientas del aprendizaje automático en Python— trae una función, train_test_split, que baraja los ejemplos y los reparte:
from sklearn.model_selection import train_test_split
X = canciones[pistas].to_numpy(float) # los 5 rasgos de cada cancion
y = canciones["track_genre"].to_numpy() # la etiqueta a adivinar
X_tr, X_te, y_tr, y_te = train_test_split(
X, y, test_size=0.2, random_state=2026, stratify=y)
print("Canciones para estudiar:", len(X_tr))
print("Canciones para el examen:", len(X_te))Canciones para estudiar: 118
Canciones para el examen: 30
Guardamos el 20 % para el examen —30 canciones— y dejamos las 118 restantes para estudiar. La X mayúscula es la tabla de rasgos (una fila por canción, una columna por rasgo); la y minúscula es la columna de géneros. Es la convención universal en aprendizaje automático: X aquello que sabes, y aquello que quieres adivinar.
¿Y ese stratify=y? Le pide al reparto que mantenga los géneros equilibrados en los dos montones —más o menos las mismas clásicas en el estudio que en el examen—, para que ninguno se quede fuera por mala suerte del barajado. El random_state=2026 es la semilla, y cumple la misma promesa de reproducibilidad de la Misión 1: fija el azar para que el reparto salga idéntico cada vez que ejecutes: hoy, mañana y en la máquina de tu compañero. Un resultado que no puedes repetir no es un resultado.
Una regla boba para empezar: adivinar el género de moda
Antes de sacar la artillería, un truco de analista listo: fija una vara de medir. ¿Cuál es la clasificación más tonta posible, la que haría alguien sin ninguna idea? Contestar siempre lo mismo: el género más común. Como en nuestro estudio hay parecidas cantidades de cada uno, da igual cuál elijas: siempre acertarás más o menos una de cada cinco. Vamos a medir cuánto acierta esa regla boba, porque será el listón que cualquier modelo de verdad tiene que superar.
import numpy as np
from sklearn.metrics import accuracy_score
comun = pd.Series(y_tr).value_counts().index[0] # el genero mas comun
pred_boba = np.full(len(y_te), comun) # el mismo para todos
print("Adivino siempre:", comun)
print("Aciertos:", round(accuracy_score(y_te, pred_boba) * 100, 1), "%")Adivino siempre: classical
Aciertos: 20.0 %
La regla boba acierta el 20 % de las canciones del examen: exactamente una de cada cinco, como cabía esperar con cinco géneros a partes iguales. Guárdate ese número: es el listón. A partir de ahora, si un modelo con toda su maquinaria no sube del 20 %, es que no ha aprendido nada que no supiéramos ya sin él. En un rato tu primer modelo lo va a batir; luego, un segundo modelo lo dejará muy atrás. Pero sin este listón no sabrías si tu 50 o tu 60 son buenos o malos —un número solo cobra sentido comparado con otro—.
Tu primer modelo: fit y predict
Ha llegado el momento. Vas a entrenar un modelo de verdad, y te va a sorprender lo corto que es. Toda la biblioteca scikit-learn está montada alrededor de dos palabras, dos verbos que se repiten en todos sus modelos:
fit(X, y)—«ajústate»—: aquí el modelo aprende. Le pasas los rasgosXy las etiquetasydel entrenamiento, y él busca el patrón que las une.predict(X)—«clasifica»—: aquí el modelo responde. Le pasas rasgos nuevos y te devuelve su etiqueta para cada uno.
Empezamos por un modelo con una intuición preciosa para clasificar: el árbol de decisión (DecisionTree Classifier). Un árbol no es más que un juego de preguntas encadenadas —«¿la energía es menor que 0,30? Entonces mira si es bailable…»— que va acorralando el género, como el «¿quién es quién?» de toda la vida. Le ponemos un tope de tres preguntas seguidas (max_depth=3) para que empiece sencillo. Mira qué poco código:
from sklearn.tree import DecisionTreeClassifier
arbol = DecisionTreeClassifier(max_depth=3, random_state=2026)
arbol.fit(X_tr, y_tr) # aprende SOLO con el estudio
pred = arbol.predict(X_te) # clasifica el examen
for i in range(6):
marca = "acierta" if pred[i] == y_te[i] else "falla"
print(f"predice {pred[i]:12s} -> real {y_te[i]:12s} {marca}")predice reggaeton -> real hip-hop falla
predice classical -> real classical acierta
predice reggaeton -> real reggaeton acierta
predice reggaeton -> real jazz falla
predice jazz -> real heavy-metal falla
predice classical -> real classical acierta
Ya está: has entrenado tu primer clasificador en tres líneas. Y ha puesto etiqueta a seis canciones del examen —canciones que no oyó al estudiar— acertando tres de las seis. No las clava todas, pero fíjate en cómo falla: llamó reggaetón a un hip-hop (los dos hermanos bailables que ya predijimos) y tropezó con el jazz y el metal. No se equivoca al azar; confunde vecinos acústicos. La pregunta que sigue es la de todo analista: ¿acertar la mitad es suficiente?. Para contestarla hay que medir.
Lo que aprendió: las preguntas del árbol
Antes de medir, asómate a lo que el modelo lleva dentro, porque el árbol de decisión tiene una virtud rara: es transparente. Puedes leer sus preguntas tal cual, como un diagrama de flujo. Aquí están las de un arbolito de dos niveles, para que quepan en la página:
from sklearn.tree import export_text
mini = DecisionTreeClassifier(max_depth=2, random_state=2026)
mini.fit(X_tr, y_tr)
print(export_text(mini, feature_names=pistas))|--- energy <= 0.30
| |--- danceability <= 0.39
| | |--- class: classical
| |--- danceability > 0.39
| | |--- class: classical
|--- energy > 0.30
| |--- danceability <= 0.59
| | |--- class: heavy-metal
| |--- danceability > 0.59
| | |--- class: reggaeton
Y lo bonito es que estas preguntas tienen sentido musical, no son un galimatías. La primera de todas es «¿la energía es menor que 0,30?»: si sí, ya sentencia clásica —da igual el resto, las dos ramas de abajo dicen lo mismo—, porque ningún otro género de los cinco tiene tan poca energía. Si no, se fija en lo bailable: poco bailable y con energía es heavy metal; muy bailable es reggaetón. El modelo, sin que nadie le explicara nada de música, ha redescubierto las firmas acústicas que tú viste a ojo, solo mirando ejemplos. Que sus preguntas cuadren con la realidad es, en sí mismo, una señal de que ha aprendido algo verdadero y no ruido. También puedes preguntarle en qué rasgo se apoya más:
for pista, peso in zip(pistas, arbol.feature_importances_):
print(f"{pista:14s} {peso:.2f}")danceability 0.34
energy 0.56
valence 0.06
tempo 0.00
duration_ms 0.04
Más de la mitad del mérito (0,56) se lo lleva la energy, y casi todo el resto lo bailable (0,34). El tempo y la duración apenas cuentan para este árbol: la energía y el baile ya separan casi todo.
Medir el acierto: el porcentaje de aciertos
Medir en clasificación es facilísimo de decir con palabras: de todas las canciones del examen, ¿en qué fracción acertó el género? Eso es la exactitud (accuracy), el porcentaje de aciertos. Ya lo usaste con la regla boba. Ahora míralo en tu árbol, y —esto es clave— mídelo en los dos montones, el de estudio y el de examen:
acc_est = accuracy_score(y_tr, arbol.predict(X_tr))
acc_exa = accuracy_score(y_te, arbol.predict(X_te))
print("Aciertos en el estudio:", round(acc_est * 100, 1), "%")
print("Aciertos en el examen: ", round(acc_exa * 100, 1), "%")Aciertos en el estudio: 73.7 %
Aciertos en el examen: 50.0 %
Buena noticia primero: 50 % en el examen es mucho mejor que el 20 % de la regla boba. Tu árbol ha aprendido algo real sobre el sonido —acierta dos veces y media más que adivinar a lo tonto—. Pero ahora fíjate en algo que huele raro: acierta el 73,7 % de lo que estudió y solo el 50 % del examen. Esa distancia —estudia mejor de lo que examina— es una pista. ¿Estará empezando a memorizar en vez de entender? Guarda esa pregunta: es, ni más ni menos, el corazón de la misión, y la respondemos ahora mismo.
El sobreajuste: empollar sin entender
Toca conocer al enemigo número uno de todo modelo, el fallo del que hay que protegerse siempre. Tiene nombre técnico —sobreajuste (overfitting)— pero tú ya sabes lo que es, porque lo has visto en clase: es el empollón que memoriza sin entender. Ese que se sabe los veinte problemas de memoria, palabra por palabra, y saca un diez si el examen es igual… y un cero en cuanto le cambian un número. Memorizó el ruido, no aprendió el patrón.
Vamos a verlo aparecer con nuestros propios ojos, que es la única forma de creérselo. Nuestro árbol tiene un «dial de listeza» perfecto para el experimento: max_depth, la profundidad, o sea cuántas preguntas seguidas se permite. Poca profundidad, un árbol simplón; mucha, un árbol que puede llegar a aprenderse cada canción de memoria. Vamos a subir el dial y a vigilar los dos aciertos —estudio y examen— a la vez:
for prof in [1, 2, 3, 5, 10, None]:
a = DecisionTreeClassifier(max_depth=prof, random_state=2026)
a.fit(X_tr, y_tr)
est = accuracy_score(y_tr, a.predict(X_tr))
exa = accuracy_score(y_te, a.predict(X_te))
print(f"profundidad {str(prof):>5}: estudio {est*100:5.1f}"
f" examen {exa*100:5.1f}")profundidad 1: estudio 39.0 examen 40.0
profundidad 2: estudio 59.3 examen 56.7
profundidad 3: estudio 73.7 examen 50.0
profundidad 5: estudio 85.6 examen 46.7
profundidad 10: estudio 100.0 examen 50.0
profundidad None: estudio 100.0 examen 50.0
Lee esta tabla de arriba abajo, porque cuenta una historia perfecta. Con profundidad 1 el árbol es tan simple que acierta poco en ambos montones (39 y 40): ni siquiera aprende lo que hay —eso se llama subajuste, lo contrario del sobreajuste: un modelo demasiado tonto—. Con profundidad 2 llega a su mejor examen (56,7), y estudio y examen van pegados: aprendizaje del bueno.
Pero mira de la 3 hacia abajo, y prepárate: el acierto de estudio sube y sube —73,7… 85,6… hasta 100, ¡el árbol se ha aprendido las 118 canciones de estudio de memoria!— mientras el acierto de examen se queda clavado o baja (50, 46,7, 50). Ahí lo tienes, el empollón en estado puro: espectacular en aquello que memorizó, torpe con lo nuevo. Y aquí está la lección que vale oro: si te hubieras fijado solo en el acierto de estudio, habrías elegido el árbol más profundo (¡100 %, el mejor de todos!) y te habrías llevado a casa uno de los peores. Por eso el examen es sagrado. La distancia que se abre entre 100 y 50 —estudio genial, examen mediocre— es la huella dactilar del sobreajuste. Se llama la brecha.
La figura 7.1 dibuja esa brecha en toda su gloria, subiendo el dial poco a poco. La curva azul (acierto de estudio) sube y sube sin parar: cuanto más listo dejas al árbol, mejor se sabe aquello que ya vio —siempre—. La curva bermellón (acierto de examen), en cambio, toca techo pronto, en un punto dulce, y luego se queda plana o cae. Ese punto es donde el árbol es justo lo bastante listo, y ni una pregunta más. A su izquierda, subajuste; a su derecha, sobreajuste. Elegir bien un modelo es, ni más ni menos, encontrar ese punto. Y ahora una confesión incómoda, de las que hacen falta: para enseñarte la brecha acabamos de mirar la columna del examen seis veces, que es justo la trampa contra la que te avisé. Lo hemos hecho para ver el fenómeno, no para elegir: fíjate en que el árbol que seguimos usando es el de profundidad 3, no el de profundidad 2 que sacó la mejor nota. En un proyecto de verdad, esa elección se hace con el montón de validación del que hablaba la caja de los tres montones, y el examen no se abre hasta el final. Mirar para aprender, sí; mirar para decidir, nunca.
Comparar dos modelos y quedarte con el mejor
Ya sabes entrenar, medir y detectar trampas. Con eso puedes hacer aquello que hace un analista de verdad todos los días: probar varios modelos y quedarse, con pruebas, con el que más acierta en el examen. Tienes el primero, el árbol (50 %). Vamos a por un segundo, más astuto: el bosque aleatorio (RandomForestClassifier).
La idea del bosque es preciosa y muy humana. Un solo árbol se equivoca y tiene manías. Pero ¿y si en lugar de fiarlo todo a un árbol plantas cien árboles, cada uno entrenado con una porción distinta de las canciones y mirando rasgos distintos, y luego les haces votar el género y te quedas con el más votado? Los errores de unos se cancelan con los de otros, las manías se diluyen, y el voto del bosque acierta mucho más que cualquier árbol suelto. Es la sabiduría de la multitud, aplicada a máquinas. Y lo mejor: gracias al mango estándar de scikit-learn, cambiar de modelo es cambiar una línea.
from sklearn.ensemble import RandomForestClassifier
bosque = RandomForestClassifier(
n_estimators=100, random_state=2026, n_jobs=-1)
bosque.fit(X_tr, y_tr)
pred_bosque = bosque.predict(X_te)
print("Aciertos del bosque en el examen:",
round(accuracy_score(y_te, pred_bosque) * 100, 1), "%")Aciertos del bosque en el examen: 60.0 %
n_estimators=100 son los cien árboles; random_state=2026 fija el azar para que el bosque salga idéntico cada vez; n_jobs=-1 le dice «usa todos los núcleos de la máquina» para ir más rápido. Y el resultado: 60 % de aciertos. Ahora ponlos cara a cara —la comparación honesta, los tres medidos en el mismo examen que ninguno vio al entrenar—:
print("Regla boba:", round(accuracy_score(y_te, pred_boba) * 100, 1), "%")
print("Arbol: ", round(accuracy_score(y_te, pred) * 100, 1), "%")
print("Bosque: ", round(accuracy_score(y_te, pred_bosque) * 100, 1), "%")Regla boba: 20.0 %
Arbol: 50.0 %
Bosque: 60.0 %
Veredicto con pruebas: el bosque gana. Sube el acierto del 50 al 60 % —diez puntos sobre el árbol solo, y el triple que la regla boba—. La figura 7.2 lo pone en barras, que entran por los ojos: cuanto más alta la barra, mejor el modelo. La regla boba (20) es un enano; el árbol (50) la dobla; el bosque (60) es la barra más alta de las tres. Esto es comparar modelos: no opinar sobre cuál «suena mejor», sino medirlos a los tres en el examen y dejar que los números decidan.
El bosque por dentro: de un árbol a cien
¿De dónde sale la ventaja del bosque? De la multitud. Subamos el número de árboles poco a poco —de uno solo a trescientos— y miremos su examen:
for n in [1, 100, 300]:
b = RandomForestClassifier(n_estimators=n, random_state=2026, n_jobs=-1)
b.fit(X_tr, y_tr)
acc = accuracy_score(y_te, b.predict(X_te))
print(f"{n:4d} arboles -> examen {acc*100:.1f} %") 1 arboles -> examen 53.3 %
100 arboles -> examen 60.0 %
300 arboles -> examen 63.3 %
Aquí se ve la magia en directo. Un solo árbol del bosque acierta 53,3: es caprichoso, se deja llevar por sus manías. Cien árboles votando suben a 60; trescientos, a 63,3. La sabiduría de la multitud en estado puro: cada árbol se equivoca a su manera, pero al votar muchos, los errores tiran unos para un lado y otros para el otro y se cancelan, y queda aquello que todos aciertan. Un apunte honesto: con solo 30 canciones en el examen, estos porcentajes tiemblan un poco (cada canción vale más de tres puntos), así que no te obsesiones con el último decimal. Lo robusto es la idea: muchos árboles baten a uno solo. Por eso 100 es el número de partida de casi todo el mundo.
La victoria
Tienes todas las piezas: sabes aprender de ejemplos, partir en estudio y examen sin hacerte trampas, entrenar con fit, clasificar con predict, medir el acierto y comparar modelos. Es la hora de juntarlas en la victoria que pedía el encargo —que el ordenador adivine el género y que tú puedas comprobarlo—, y tiene dos mitades.
Antes, míralo todo junto. Este es el flujo entero de un proyecto de aprendizaje automático, de la primera línea a la clasificación, en una sola celda —la que resume la misión—. Léela despacio y reconoce cada paso:
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score
# 1) los datos, los generos y los rasgos
musica = pd.read_csv("musica.csv")
generos = ["classical", "reggaeton", "heavy-metal", "hip-hop", "jazz"]
canciones = musica[musica["track_genre"].isin(generos)].copy()
pistas = ["danceability", "energy", "valence", "tempo", "duration_ms"]
X = canciones[pistas].to_numpy(float)
y = canciones["track_genre"].to_numpy()
# 2) partir honesto (estudio y examen)
X_tr, X_te, y_tr, y_te = train_test_split(
X, y, test_size=0.2, random_state=2026, stratify=y)
# 3) entrenar el mejor modelo
bosque = RandomForestClassifier(n_estimators=100, random_state=2026, n_jobs=-1)
bosque.fit(X_tr, y_tr)
# 4) medir el acierto sobre canciones que NO oyo
acc = accuracy_score(y_te, bosque.predict(X_te))
print("Aciertos en el examen:", round(acc * 100, 1), "%")
# 5) adivinar el genero de una cancion nueva (mucha energia, poco baile)
nueva = [[0.35, 0.95, 0.25, 150, 250000]]
print("Esta cancion es:", bosque.predict(nueva)[0])Aciertos en el examen: 60.0 %
Esta cancion es: heavy-metal
Cinco pasos, y ya está todo: cargar, partir, entrenar, medir, clasificar. Este esqueleto —estas cinco piezas en este orden— es el mismo en cualquier proyecto de aprendizaje automático del mundo. Ahora desmenucemos las dos mitades de la victoria.
La primera mitad ya la tienes hecha: clasificar el examen —30 canciones que el modelo no oyó jamás— y medir el acierto. Tu mejor modelo, el bosque, acierta el género en el 60 % de canciones nuevas: el triple que la regla boba. Eso es un acierto comprobado: no te lo crees porque suene bien, lo sabes porque lo mediste en el examen. Para ver en qué acierta y en qué se lía, nada mejor que una matriz de confusión: una tabla que cruza el género real (filas) con el que predijo el bosque (columnas). La diagonal son los aciertos:
from sklearn.metrics import confusion_matrix
orden = sorted(generos)
matriz = confusion_matrix(y_te, pred_bosque, labels=orden)
print(orden)
print(matriz)['classical', 'heavy-metal', 'hip-hop', 'jazz', 'reggaeton']
[[5 0 0 1 0]
[0 5 0 1 0]
[0 1 1 0 4]
[0 1 1 3 1]
[0 0 2 0 4]]
La figura 7.3 pinta esta misma tabla como un mapa de calor, que se lee de un vistazo. Cada fila es un género real; mira dónde caen sus seis canciones. La primera fila (clásica): cinco en su casilla, una escapada al jazz —casi perfecto—. La tercera (hip-hop): solo una en su sitio y cuatro coladas en reggaetón. ¡Ahí está la confusión que predijiste a ojo! El bosque distingue de maravilla lo que suena distinto (clásica, metal) y se lía con lo que suena parecido (hip-hop y reggaetón, gemelos bailables). No es tonto: se equivoca justo donde tú también dudarías.
La segunda mitad es la que da gustito: poner etiqueta a una canción que el modelo no ha oído en su vida. Le damos unos rasgos —mucha energía (0,95), poco bailable (0,35), tono más bien apagado, tempo rápido: la receta clásica de un temazo de heavy metal— y le pedimos su veredicto:
nueva = [[0.35, 0.95, 0.25, 150, 250000]] # dance, energy, valence, tempo, dur
genero = bosque.predict(nueva)[0]
confianza = bosque.predict_proba(nueva)[0].max()
print(f"El bosque dice: {genero} ({round(confianza*100)} % de confianza)")El bosque dice: heavy-metal (87 % de confianza)
Ahí está tu oído mecánico, que no es magia sino memoria bien ordenada: el modelo dice heavy metal, y con un 87 % de seguridad. Y lo mejor de todo: es un juicio que puedes comprobar. Búscate una canción de la que sepas el género, mira sus rasgos en Spotify, pásaselos al modelo y comprueba si acierta. Eso —clasificar algo nuevo y poder verificarlo después— es la victoria entera de la misión.
¿Lo lograste?
Como en cada misión, no te fías de que «parece que va»: lo compruebas con un guardián assert. Aquí verificamos las dos cosas que definen la victoria: que el bosque de verdad le gana al árbol, y que su acierto en el examen dobla con holgura el listón de la regla boba. Ejecuta la celda tal cual:
acc_bosque = accuracy_score(y_te, pred_bosque)
acc_arbol = accuracy_score(y_te, pred)
assert acc_bosque > acc_arbol, "El bosque deberia ganar al arbol."
assert acc_bosque > 2 * 0.20, "Casi: el bosque deberia doblar a la regla boba."
print("Lo lograste. Insignia desbloqueada: domador de modelos.")Lo lograste. Insignia desbloqueada: domador de modelos.
Si ves ese mensaje, enhorabuena de verdad: has enseñado a una máquina a clasificar música, le has medido el acierto con honestidad sobre canciones que no oyó, has comparado dos modelos y te has quedado con el mejor con pruebas en la mano. Eso es domar un modelo, y por eso te llevas la insignia domador de modelos. Si en cambio salta un aviso, no es un fracaso: es el guardián haciendo su trabajo. Revisa que entrenaste con X_tr/y_tr y mediste con X_te/y_te —nunca al revés— y prueba otra vez.
La bitácora del analista
Abre tu bitácora —la que empezaste en la Misión 1— y añádele la entrada de hoy, que es de las gordas. Anota al menos:
La pregunta que resolviste: «¿de qué género es esta canción, dados su baile, energía, tono, tempo y duración?».
El listón y las notas, con sus números: regla boba 20 %, árbol 50 %, bosque 60 % de aciertos en el examen.
La trampa que aprendiste a evitar: mirarse el examen. Y por qué el árbol de estudio 100 % era, en realidad, uno de los peores modelos.
Tu clasificación de una canción nueva y la promesa de comprobarla: apunta un tema del que sepas el género, pásale sus rasgos al modelo y escribe al lado si acertó.
Una duda que te llevas. Las dudas anotadas son las que luego se resuelven.
Esa penúltima línea —la clasificación con hueco para comprobarla— es la más valiosa de toda tu bitácora: es la prueba, con fecha, de que hiciste ciencia y no adivinación.
Sube de nivel: juega con tu modelo
Un modelo entrenado no es un cuadro para colgar: es un juguete para interrogar. Y la mejor forma de entender lo que aprendió es hacerle preguntas y ver si sus respuestas tienen sentido. Vamos a darle tres canciones inventadas muy distintas y a mirar cómo reacciona.
def clasifica(dance, energy, val, tempo, dur):
return bosque.predict([[dance, energy, val, tempo, dur]])[0]
print("Energia altisima, poco baile:", clasifica(0.35, 0.95, 0.25, 150, 250000))
print("Muy bailable, tempo medio: ", clasifica(0.80, 0.65, 0.60, 95, 205000))
print("Suave, sin energia, larga: ", clasifica(0.25, 0.10, 0.15, 110, 265000))Energia altisima, poco baile: heavy-metal
Muy bailable, tempo medio: reggaeton
Suave, sin energia, larga: classical
Míralo pensar. Energía altísima y poco baile: heavy metal —potencia sin pista de baile—. Muy bailable y tempo medio: reggaetón —hecho para moverse—. Suave, sin energía y larga: clásica —un piano tranquilo—. El modelo no se ha aprendido estas canciones (son inventadas, no estaban en los datos); ha aprendido el patrón de cada género y lo aplica a casos nuevos con una lógica que reconocerías tú mismo. Eso es aprender, no memorizar.
¿De qué rasgo se fía más?
Aquí va un experimento revelador: ¿y si el modelo tuviera que clasificar mirando un solo rasgo? Entrenemos un bosque con cada rasgo por separado y veamos cuánto acierta, comparado con el bosque completo que usa los cinco:
for r in pistas:
Xu = canciones[[r]].to_numpy(float)
Xu_tr, Xu_te, yu_tr, yu_te = train_test_split(
Xu, y, test_size=0.2, random_state=2026, stratify=y)
b = RandomForestClassifier(n_estimators=100, random_state=2026, n_jobs=-1)
b.fit(Xu_tr, yu_tr)
acc = accuracy_score(yu_te, b.predict(Xu_te))
print(f"solo {r:14s} -> {acc*100:5.1f} %")solo danceability -> 43.3 %
solo energy -> 56.7 %
solo valence -> 26.7 %
solo tempo -> 23.3 %
solo duration_ms -> 23.3 %
Ningún rasgo solo es gran cosa, pero hay diferencias enormes: la energy a solas ya acierta 56,7 % (¡casi como el bosque completo!, porque separa la clásica y el metal de un plumazo), mientras que el tempo o la duración a solas (23,3 %) apenas le ganan a la regla boba. Pero acuérdate: los cinco juntos daban 60 %. Esa es una idea profunda del aprendizaje automático —y de la vida—: los rasgos se combinan. Saber solo el tempo te dice poco; saber el tempo y que es poco bailable y con mucha energía, te dice «metal». El modelo brilla juntando pistas que por separado apenas susurran.
El bosque te dice en qué se fija
Hay una forma más directa de saber de qué se fía tu modelo: preguntárselo. El bosque, al entrenarse, lleva la cuenta de cuánto le ayuda cada rasgo, y te lo resume en su atributo feature_importances_ —unos números que reparten el «mérito» entre los rasgos y suman 1 (si los sumas redondeados a dos decimales te puede salir 1,01: es el redondeo, no un error)—.
for r, peso in sorted(zip(pistas, bosque.feature_importances_),
key=lambda par: -par[1]):
print(f"{r:14s} {peso:.2f}")energy 0.31
danceability 0.29
valence 0.17
duration_ms 0.13
tempo 0.11
El bosque se apoya sobre todo en la energy (0,31) y en lo bailable (0,29), justo los dos rasgos donde viste las firmas más claras. El valence ayuda algo (0,17) y el tempo es el que menos aporta (0,11). Esto se llama importancia de las características, y es una ventana preciosa al «cerebro» del modelo: te dice en qué se fija para decidir. Léela con una pizca de cautela —no significa que el tempo no distinga ningún género, solo que a este modelo, con estos cinco rasgos, le resulta el más prescindible—.
Tú contra la máquina: la regla a mano
En la Misión 1 escribías reglas de decisión a mano con if. Ahora que viste las firmas (clásica sin energía, metal con energía y sin baile, reggaetón bailable), quizá piensas: «yo podría escribir esas reglas y clasificar sin ningún modelo». Adelante, inténtalo —y luego mide tu regla en el mismo examen, sin piedad—:
def regla_a_mano(dance, energy, val, tempo, dur):
if energy < 0.30:
return "classical" # sin energia = clasica
elif energy > 0.80 and dance < 0.60:
return "heavy-metal" # mucha energia, poco baile = metal
elif dance > 0.70:
return "reggaeton" # muy bailable = reggaeton
else:
return "jazz" # el resto, a jazz
pred_mano = np.array([regla_a_mano(*fila) for fila in X_te])
acc_mano = accuracy_score(y_te, pred_mano) * 100
acc_bosque = accuracy_score(y_te, pred_bosque) * 100
print("Tu regla a mano:", round(acc_mano, 1), "%")
print("El bosque: ", round(acc_bosque, 1), "%")Tu regla a mano: 63.3 %
El bosque: 60.0 %
¡Sorpresa! Tu regla casera acierta 63,3 % y hasta le saca un pelín al bosque. ¿La máquina no era imbatible? Aquí está la lección honesta, y es de las buenas: cuando el problema es fácil y tú ya viste las firmas, unas reglas a mano rinden estupendamente. Escribir a mano cuatro cortes sobre géneros tan distintos no es difícil. Pero fíjate en la trampa: pudiste escribir esas reglas porque miraste antes los datos y porque solo hay cinco géneros. Con los 114 géneros del catálogo completo, o con rasgos más sutiles, escribir a mano las reglas sería imposible, y ahí la máquina te barrería. Moraleja de analista de verdad: empieza siempre por una regla simple. Si una regla boba ya iguala a tu modelo, tu modelo no se está ganando su complejidad.
Y hay una letra pequeña deliciosa en tu propia regla: fíjate en que nunca devuelve hip-hop. No puede acertar ni uno solo —los manda todos a jazz o a reggaetón—, así que su techo es 24 de 30. Le gana al bosque en parte porque se retira de la categoría más difícil, justo donde el bosque se estrella. Una regla que no compite en lo difícil parte con ventaja en el promedio: otra razón para mirar el acierto género a género y no solo el total.
El modelo también duda: la confianza
El bosque no solo escupe un género: por dentro reparte votos. Con predict_proba puedes ver cuánto se la juega en cada etiqueta —su confianza—. Mira una canción del examen donde el modelo lo tuvo crudo:
probas = bosque.predict_proba(X_te)
for genero, p in zip(bosque.classes_, probas[0].round(2)):
print(f"{genero:12s} {p}")
print("Real:", y_te[0])classical 0.07
heavy-metal 0.01
hip-hop 0.17
jazz 0.36
reggaeton 0.39
Real: hip-hop
Aquí el bosque está hecho un lío: reparte los votos entre reggaetón (0,39), jazz (0,36) y hip-hop (0,17), sin decidirse. Se quedó con reggaetón por un pelo… y falló (era hip-hop). Compáralo con el heavy metal de antes, que clasificó con un 87 % de confianza a la primera. Esa cifra es oro: una clasificación al 39 % es poco más que echarlo a suertes; una al 90 % es sólida. En un sistema de verdad —el que decide si una foto es un tumor, pongamos—, saber cuánto duda el modelo importa tanto como su respuesta.
Sube otra vez: ¿qué géneros se le dan mejor?
Un porcentaje suelto —«acierta el 60 %»— convence a medias. Lo que de verdad impresiona (y enseña) es abrir esa media y ver género por género dónde brilla el modelo y dónde patina. Sacamos el acierto de cada género directamente de la matriz de confusión: los aciertos de su fila (la diagonal) entre el total de esa fila.
for i, g in enumerate(orden):
aciertos = matriz[i, i]
total = matriz[i].sum()
print(f"{g:12s} {aciertos}/{total} = {round(aciertos/total*100)} %")classical 5/6 = 83 %
heavy-metal 5/6 = 83 %
hip-hop 1/6 = 17 %
jazz 3/6 = 50 %
reggaeton 4/6 = 67 %
La figura 7.4 pinta estos porcentajes en barras, una por género, y cuenta una historia clarísima. La clásica y el heavy metal se los sabe de sobra (83 % cada uno): tienen firmas tan propias —energía mínima, energía máxima— que no hay confusión posible. En cambio el hip-hop es su talón de Aquiles (17 %): casi siempre lo manda al reggaetón, porque suenan como gemelos. El acierto global del 60 % no es un número plano: es la mezcla de géneros que el modelo domina y géneros que se le resisten. Y saber cuáles es tan valioso como el total: te dice exactamente dónde tendrías que darle más rasgos o más ejemplos para mejorar.
El peor patinazo: aprende de tus errores
Un analista curtido no huye de sus errores: los examina, porque son la mejor pista sobre los límites de su modelo. Busquemos la canción del examen donde el bosque se equivocó con más aplomo —la que clasificó mal pero con mucha confianza— y miremos sus rasgos a ver si entendemos por qué.
falla = pred_bosque != y_te
confianza = probas.max(axis=1)
i = np.where(falla, confianza, -1).argmax() # el fallo mas seguro de si mismo
print("La cancion que mas confiado fallo:")
for r, v in zip(pistas, X_te[i]):
print(f" {r:14s} {v:.2f}")
print("Real:", y_te[i], "| Predije:", pred_bosque[i],
"| Confianza:", round(confianza[i] * 100), "%")La cancion que mas confiado fallo:
danceability 0.74
energy 0.85
valence 0.55
tempo 87.98
duration_ms 143901.00
Real: hip-hop | Predije: reggaeton | Confianza: 70 %
¡Vaya patinazo con seguridad! El modelo dijo reggaetón al 70 % y era hip-hop. Pero mira sus rasgos y dale la razón al modelo: bailabilísima (0,74), con energía (0,85)… es el retrato robot del reggaetón. Ese hip-hop concreto suena tan a reggaetón que engañaría a mucha gente. El fallo no es de un mal modelo: es el recordatorio de que dos géneros vecinos comparten territorio, y ninguna frontera —ni la del modelo ni la tuya— los separa sin equivocarse alguna vez. El mundo real guarda siempre canciones a caballo entre dos etiquetas.
¿Y si el reparto tuvo suerte?
Queda una duda honesta royéndonos: tu 60 % salió de un reparto concreto, el de la semilla 2026. ¿Y si ese reparto fue afortunado y con otro el modelo lo haría peor? La forma de dormir tranquilo es repetir la partición con varias semillas distintas y ver si el acierto se mantiene:
for semilla in [1, 7, 2026, 99]:
xtr, xte, ytr, yte = train_test_split(
X, y, test_size=0.2, random_state=semilla, stratify=y)
b = RandomForestClassifier(n_estimators=100, random_state=2026, n_jobs=-1)
b.fit(xtr, ytr)
acc = accuracy_score(yte, b.predict(xte))
print(f"semilla {semilla:5d} -> examen {acc*100:.1f} %")semilla 1 -> examen 70.0 %
semilla 7 -> examen 56.7 %
semilla 2026 -> examen 60.0 %
semilla 99 -> examen 70.0 %
Aquí toca honestidad total: el acierto baila entre el 57 y el 70 % según el reparto. ¿Por qué tanto? Por lo de siempre: el examen es diminuto —solo 30 canciones—, así que cada acierto o fallo mueve el porcentaje más de tres puntos. Nuestro 60 % (semilla 2026) es una marca representativa, no una verdad al milímetro. Y sin embargo, la conclusión aguanta: en las cuatro semillas el bosque ronda el 60 % y siempre triplica de largo el 20 % de la regla boba. Cuando un número baila así, la lección no es «desconfía del modelo», sino «desconfía de un único número»: da un rango, no un decimal falso. Este truco —probar varios repartos y mirar si el resultado aguanta— es la semilla (nunca mejor dicho) de una técnica mayor, la validación cruzada, que aprenderás cuando quieras ir en serio.
El jefe de parte: tu detector de géneros
Hora de enfrentarte al jefe de parte, el miniproyecto que cierra la misión juntándolo todo. El encargo: convertir tu modelo en un detector de géneros de verdad —una función que reciba los rasgos de una canción y devuelva, además del género, la confianza y un veredicto en palabras: seguro o dudoso—. Es tu modelo de la Misión 7 dándose la mano con las funciones y los if de la Misión 1.
def detector_generos(dance, energy, val, tempo, dur):
fila = [[dance, energy, val, tempo, dur]]
probas = bosque.predict_proba(fila)[0]
i = probas.argmax()
genero = bosque.classes_[i]
confianza = round(float(probas[i]) * 100)
if confianza >= 60:
veredicto = "seguro"
else:
veredicto = "dudoso"
return genero, confianza, veredicto
print("Metal puro: ", detector_generos(0.35, 0.95, 0.25, 150, 250000))
print("Piano suave: ", detector_generos(0.25, 0.10, 0.15, 110, 265000))
print("Baile alegre: ", detector_generos(0.72, 0.70, 0.85, 120, 200000))Metal puro: ('heavy-metal', 87, 'seguro')
Piano suave: ('classical', 93, 'seguro')
Baile alegre: ('hip-hop', 59, 'dudoso')
Ahí tienes una herramienta de verdad: una sola función que, dada cualquier canción, adivina su género, se moja con un porcentaje y avisa cuándo no las tiene todas consigo. La canción bailable y alegre sale «dudoso» al 59 % —y con razón, porque el reggaetón y el hip-hop se le confunden—. Por dentro llama a bosque.predict_proba (tu modelo entrenado) y decide el veredicto con un if/else (tu Misión 1). Esto ya no es un ejercicio: es el corazón de cualquier app que reconozca música, voz o imágenes.
¿Lo lograste? (nivel jefe)
El jefe también se comprueba. Esta celda verifica que el detector reconoce un caso de manual (un piano suave tiene que ser clásica) y que se moja con confianza alta. Si los guardianes callan, has vencido:
genero, confianza, veredicto = detector_generos(0.25, 0.10, 0.15, 110, 265000)
assert genero == "classical", "Un piano sin energia deberia ser clasica."
assert veredicto == "seguro", "Con 93 % de confianza deberia decir 'seguro'."
print("Detector validado. Eres domador de modelos.")Detector validado. Eres domador de modelos.
Dos guardianes, una victoria. Si los dos callan, tu detector de géneros es sólido: no lo crees porque «parece bien», lo sabes porque lo has comprobado —y esa, misión tras misión, es la diferencia entre un analista y alguien que tuvo suerte una vez—.
Retos: elige tu nivel
Ahora te toca a ti. Los retos suben de dificultad: \(\star\) es imprescindible, \(\star\star\) te reta y \(\star\star\star\) es de jefe. Haz al menos todos los de una estrella; sube hasta donde te apetezca. Y en todos, las dos reglas de oro: predice antes de ejecutar y el examen no se toca hasta el final.
★ Cambia la semilla. Repite la partición con
random_state=7en vez de 2026, reentrena el bosque y mira su acierto en el examen. ¿Cambia mucho? Antes de ejecutar, apuesta: ¿seguirá cerca del 60 % o se irá lejos?★ Tu propia canción. Inventa los cinco rasgos de una canción (un temazo de metal, una nana tranquila…) y pásaselos a
detector_generos. ¿El género y la confianza tienen sentido para esa canción?★ Bate a la regla boba. Escribe en una línea cuánto mejora el bosque (60 %) frente a adivinar el género de moda (20 %): la resta, y también cuántas veces más acierta. Enséñaselo a alguien.
★ Lee la matriz. Mira la figura de la confusión y contesta por escrito: ¿con qué género confunde más el modelo al hip-hop? ¿Y por qué crees que pasa, mirando sus firmas acústicas?
★★ El árbol justo. Prueba el
DecisionTreeClassifierconmax_depthigual a 2, 3 y 4. ¿Cuál da el mejor examen? Acabas de buscar a mano el punto dulce de la figura del sobreajuste.★★ Más árboles. Entrena bosques con
n_estimatorsigual a 10, 100 y 300. Apunta el acierto y el tiempo de cada uno (puedes cronometrar a ojo). ¿Compensan los 300?★★ Quita un rasgo. Reentrena el bosque usando solo cuatro rasgos (quita
energy). ¿Cuánto empeora el examen? Eso te dice cuánto aportaba la energía dentro del equipo.★★ Cambia los géneros. Sustituye
jazzportechnoen la lista y rehazlo todo. ¿Sube o baja el acierto? ¿El techno se confunde con alguno de los otros?★★ El más confiado. Recorre el examen y encuentra la canción que el bosque clasificó con más confianza (el mayor
predict_proba). Imprime sus rasgos y su género: ¿acertó?★★★ El jefe: elige tú el modelo. Entrena los tres —regla boba, árbol y bosque—, guarda sus aciertos en un diccionario y escribe un bucle que imprima el nombre del ganador (el de mayor acierto) sin que tú digas cuál es. La máquina elige su propio campeón.
★★★ El jefe: demuestra la trampa. Entrena un
DecisionTreeClassifiersin límite de profundidad y mide su acierto en el estudio y en el examen. Enseña los dos números juntos y explica, con tus palabras, por qué el primero (100 %) es una mentira peligrosa.★★★ El jefe: detector con aviso. Amplía
detector_generospara que, si el veredicto es «dudoso», añada con qué segundo género anda dudando (el de la segunda probabilidad más alta). Un detector que, además del género, confiesa entre qué dos titubea.
¿Te has atascado? En el apéndice C tienes, para cada reto, primero una pista y solo después la solución. Pero el pacto es este: entra ahí después de haberlo intentado de verdad.
Tu caja de herramientas
Mira todo lo que sabes hacer ahora y hace unas páginas no sabías. Esta es tu chuleta de aprendizaje automático: pégala en la bitácora y vuelve a ella cuando dudes.
Preparar: separa los rasgos (
X) de la etiqueta (y).Partir honesto:
train_test_splitcontest_size=0.2,random_statefijo ystratify=y.Entrenar:
modelo.fit(X_tr, y_tr)(con el estudio, nunca con el examen).Clasificar:
modelo.predict(X_te); ypredict_probapara la confianza.Medir:
accuracy_score—el porcentaje de aciertos— y laconfusion_matrixpara ver en qué se lía.Modelos:
DecisionTreeClassifier(transparente, el del dialmax_depth) yRandomForestClassifier(el bosque que vota).Vigilar el sobreajuste: compara acierto de estudio y de examen; si el primero es mucho mayor que el segundo, hay brecha (memoriza).
Comparar: mide dos o más modelos en el mismo examen y quédate con el de mayor acierto.
Reproducir:
random_stateen todo lo que lleve azar, para que salga igual cada vez.
No memorices esta lista: úsala. La memoria viene sola de tanto entrenar modelos.
Cuando quieras ir en serio
Lo que has hecho —partir, entrenar, medir en el examen, comparar— es el esqueleto de cualquier proyecto de aprendizaje automático, desde el que clasifica música hasta el que recomienda vídeos o detecta un tumor en una radiografía. Cambia el dato y el modelo; el método es este. Cuando quieras dar el salto, hay un mundo esperándote: encadenar la limpieza y el modelo en una sola tubería (pipeline) para que no se te cuele ninguna trampa; probar muchos ajustes de forma automática y elegir el mejor con validación cruzada (partir en varios exámenes y promediar, para no fiarlo todo a un reparto con suerte); y modelos más potentes —el gradient boosting, las redes neuronales— que aprenden patrones que ni un solo bosque alcanza. No lo necesitas todavía: con lo de esta misión ya clasificas y ya te mides con honestidad, que es lo que de verdad importa.
Y una última idea para llevarte, la que resume la misión entera: en aprendizaje automático, la pregunta nunca es «¿acierto en los datos que tengo?» —eso es fácil, basta memorizar— sino «¿acertaré en los que no tengo?». Todo tu oficio de domador de modelos consiste en no engañarte al responderla. El examen apartado, el acierto medido, la comparación honesta: no son burocracia, son la única forma de que tu juicio sobre una canción nueva signifique algo cuando suene.
Misión 7 completada. Insignia domador de modelos, desbloqueada. Has enseñado a una máquina a reconocer géneros a partir de ejemplos, la has medido sin hacerte trampas sobre canciones que no oyó, has desenmascarado al empollón que memoriza y has coronado, con pruebas, al mejor de dos modelos. Ya no solo cuentas y dibujas el pasado: clasificas lo nuevo y sabes exactamente cuánto puedes fiarte de tu modelo. Eso, exactamente eso, es lo que hace un científico de datos.