Misión 9. Tu propio análisis

▶ 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é.

Jefe Final. Encargo: «coge tus propios datos —no el catálogo que yo te daba, los tuyos— y hazlos hablar».
Victoria: tu primer proyecto entero, de cero a figura.
Insignia en juego: analista.

El encargo

Hasta aquí, la música te ha llevado de la mano. Te dio la primera pregunta —«¿de qué está hecha una canción por dentro?»—, te sirvió el catálogo ya descargado y te acompañó misión a misión: aprendiste a traer un fichero a tu cuaderno, a interrogarlo con pandas, a cazar sus datos rotos, a dibujarlo en una figura, a medir sin engañarte, a adivinar el género por el sonido y a proteger tu propia huella de escucha. Ocho misiones, ocho insignias. Ya no eres quien abrió el primer cuaderno sin saber qué era una variable.

Pero un aprendiz deja de serlo el día en que nadie le da la pregunta. Y ese día es hoy. Este es el jefe final, y su encargo es distinto a todos los anteriores: no te voy a dar los datos. Ni la pregunta. Las eliges tú. Coge un dato que te importe de verdad —tus propias canciones de Spotify, tus horas de sueño, los goles de tu equipo, los terremotos del año— y hazlo hablar con todo cuanto sabes hacer. Ese es el salto que separa a quien ha seguido un libro de quien ya sabe hacer esto: no repetir el camino del catálogo, sino abrir uno tuyo con las mismas herramientas.

Por qué esto lo cambia todo.

Mientras la pregunta te la daban, seguías una receta. En cuanto la eliges tú, tienes que decidir: ¿es una buena pregunta?, ¿existen datos para responderla?, ¿están limpios?, ¿es real cuanto veo o es casualidad? Esas decisiones —no teclear pandas— son el oficio de verdad. Un analista no es quien conoce las órdenes; es quien sabe qué preguntar y hasta dónde puede fiarse de la respuesta. La buena noticia: ya tienes todas las piezas. Esta misión solo te enseña a montarlas tú solo, sobre un dato que nadie ha masticado por ti.

El mapa de la misión.

No vas a improvisar. La campaña entera se condensa en un método de siete pasos —el arma que has ido fabricando sin darte cuenta—, y este capítulo hace tres cosas con él:

  1. Te da el método completo como una receta reutilizable: los siete pasos, en orden, para cualquier dato.

  2. Te enseña las dos decisiones que el catálogo te ahorraba: elegir una buena pregunta y encontrar datos abiertos.

  3. Recorre el método entero, de principio a fin, sobre un dato nuevo —una biblioteca de música propia— para que veas el flujo de cero a figura antes de lanzarte con el tuyo.

Al final tendrás dos cosas: un ejemplo completo que imitar y el encargo del jefe final de verdad —tu propio proyecto—. Cuando lo termines, la insignia analista será tuya, y no será una medalla por asistir: será la prueba de que puedes coger un dato que nadie ha tocado y sacarle una verdad. Vamos allá.

La herramienta: el método

En las misiones anteriores, la herramienta de cada capítulo era una técnica nueva: pandas, un tipo de figura, un modelo. Aquí la herramienta no es nueva —es todas a la vez, ordenadas—. Cuanto has aprendido, misión a misión, era en realidad un solo método partido en trozos. Ha llegado el momento de verlo entero. Grábatelo, porque es el esqueleto de cualquier análisis de datos del mundo, del tuyo de mañana y del de un científico con un telescopio:

  1. Traer. Meter el dato en el cuaderno. Un read_csv y a correr.

  2. Interrogar. Las primeras preguntas: ¿cuántas filas?, ¿qué columnas?, ¿cuál es el máximo, el mínimo, la media?

  3. Limpiar. Cazar lo roto: huecos, marcadores de «sin dato», valores imposibles. Un dato sucio miente.

  4. Ver. Darle forma: una figura dice en un vistazo cuanto mil cifras esconden.

  5. Medir. Comparar sin engañarte: ¿la diferencia es real o es casualidad? Siempre con su margen.

  6. Predecir. Que el patrón sirva para adelantar aquello que aún no conoces —y comprobar si acierta—.

  7. Proteger. Preguntarte de quién es este dato y a quién puede hacer daño. La honestidad no es solo con los números.

No es una lista para memorizar: es un orden de trabajo. Se recorre de arriba abajo, y casi siempre se vuelve atrás —ves una figura rara (paso 4) y descubres que te quedaba basura por limpiar (paso 3)—. Eso no es fallar: es como funciona. Un análisis no es una flecha recta, es un ir y venir por estos siete pasos hasta que el dato, por fin, habla claro.

NotaPara saber más: este método no es solo para datos

Mira otra vez los siete pasos y cámbiales el nombre: preguntar, observar, descartar cuanto no encaja, representar, comparar con cuidado, predecir, responsabilizarte. Es el método científico de toda la vida, el mismo que usa quien estudia estrellas, virus o volcanes. Por eso este libro se llama «para futuros científicos»: no estás aprendiendo a manejar una biblioteca de Python, estás aprendiendo a pensar como quien saca verdades del mundo midiéndolo. Python es solo el idioma en el que se lo cuentas a la máquina.

Elegir una buena pregunta

Todo empieza aquí, y es lo más difícil —más que cualquier línea de código—. Una buena pregunta de datos no es cualquier curiosidad: tiene cuatro propiedades, y si le falta una, el proyecto se atasca. Una buena pregunta es:

  • Concreta. «¿Es interesante mi música?» no es una pregunta, es un tema. «¿Qué género escucho más?» sí lo es: se puede contestar con un número.

  • Medible. Tiene que existir algo que se cuente o se mida: canciones, grados, goles, minutos, euros. Si no se puede poner en una columna, no hay dato que valga.

  • Respondible con datos que puedas conseguir. «¿Qué música le gusta a toda mi ciudad?» es medible… si haces una encuesta que no puedes hacer. Elige preguntas cuyos datos ya existan o puedas exportar.

  • Tuya. Que te importe de verdad. Vas a pasar horas con estos números; que sean de algo que te pique la curiosidad, no de algo que crees que «queda serio».

Fíjate en la diferencia con dos ejemplos. «¿El reggaeton es bueno?» falla en todo: ni concreta, ni medible, ni respondible. «¿Mi reggaeton es más bailable que mi rock?» las cumple las cuatro: concreta (comparar dos grupos de canciones), medible (la bailabilidad), respondible (con tu biblioteca exportada) y tuya. La segunda es un proyecto; la primera, un suspiro.

La trampa de lo imposible de medir.

Cuidado con las preguntas que parecen buenas y no lo son. «¿La gente es más feliz escuchando pop?» suena estupenda, y falla por la base: ¿cómo mides «feliz»? No existe una columna de felicidad. Y aunque la hubiera, ¿y si quien escucha pop ya venía contento y no es el pop quien lo anima? Antes de enamorarte de una pregunta, comprueba dos cosas: que aquello que quieres medir se puede poner en números sin discutir, y que no estás mezclando dos cosas que van juntas dando por hecho que una causa la otra. Una pregunta que no se mide limpia no es un proyecto: es una charla de café.

Un truco para afinar.

Casi cualquier tema se convierte en pregunta buena metiéndole una de estas cuatro formas, que —no por casualidad— son las que ya sabes responder:

  • ¿Cuánto / cuántos? Un conteo o una media. «¿Cuántas de mis canciones son de fiesta pura?»

  • ¿Cuál es el mayor / el menor? Un récord. «¿Cuál es mi canción más bailable?»

  • ¿A es distinto de B? Una comparación. «¿Mis canciones explícitas son más de fiesta que el resto?» (spoiler: comprobarlo enseña).

  • ¿Qué pasará? Una predicción. «Sabiendo cómo de bailable es una canción, ¿puedo adivinar cómo de alegre suena?»

Cada una de esas cuatro formas es, exactamente, una de las victorias que ya te has llevado en la campaña. Elegir la pregunta es, en el fondo, elegir cuál de tus armas vas a usar.

Dónde vive el dato abierto

Tienes la pregunta; ahora hace falta el dato. Y aquí está la maravilla de vivir en 2026: hay montañas de datos abiertos —publicados gratis, para que cualquiera los mire— esperando a que alguien les haga una pregunta. Puede que esa persona seas tú. Estos son los sitios donde buscar:

  • Tu propio Spotify. El dato más tuyo de todos: tu biblioteca y tu historial de escucha. Desde los ajustes de privacidad de tu cuenta puedes pedir una copia de tus datos, y hay herramientas gratuitas que exportan una lista a un CSV. Nadie más en el mundo tiene ese dato: es el del jefe final.

  • Comunidades de datos. En sitios como Kaggle, miles de personas comparten datasets de casi cualquier cosa —canciones, películas, partidos, videojuegos—. De una comunidad así salió, de hecho, el catálogo de música que has usado toda la campaña.

  • Portales públicos de tu país o ciudad. En España, el gran almacén es datos.gob.es; muchos ayuntamientos tienen el suyo. Hay de todo: transporte, contaminación, bibliotecas, árboles de la ciudad.

  • Europa y el mundo. data.europa.eu reúne datos de toda la Unión Europea; Our World in Data tiene datasets cuidadísimos sobre clima, salud o energía, pensados para aprender.

  • Tú mismo, con un cuaderno. El dato más honesto es el que mides tú: tus horas de estudio, los pasos de tu móvil, las canciones que pones cada día. Dos semanas de anotar bastan para un proyecto redondo.

Qué pinta tiene un dato bueno para empezar.

No todos los datasets sirven igual de bien para un primer proyecto. Busca uno que sea, sobre todo, manejable: un fichero CSV (esa tabla de texto separada por comas que ya sabes leer), con pocas columnas (dos o tres bastan para una gran pregunta), una fila por cosa (una canción, un partido, un día) y un tamaño que no asuste (unos miles de filas se mueven de sobra en Colab). Huye, para la primera vez, de los datasets con cincuenta columnas y nombres en clave: no son más serios, solo más pesados. Con una columna de categoría y unas de números —justo cuanto trae tu música: género y rasgos— se hace un proyecto redondo.

NotaPara saber más: cuando el dato no es un CSV

No todo llega en CSV. A veces el dato vive detrás de una API: una puerta por la que tu programa pide los datos y un servidor se los manda, normalmente en un formato llamado JSON (parecido a un diccionario de Python anidado). Otras veces está en una hoja de cálculo (.xlsx) o repartido por una página web. Pandas sabe leer casi todo —read_csv, read_json, read_excel—, y para lo demás está el capítulo del volumen adulto sobre entrada y salida de datos. Para tu primer proyecto, quédate en el CSV: es el idioma común de los datos abiertos, y con él te sobra.

El contrato con tus datos

Antes de fiarte de una sola cifra, hazle a tu dataset cinco preguntas. Es un contrato: hasta que no te las responda, no te crees nada de cuanto diga. Un analista que se salta esto acaba defendiendo un número falso con toda la seguridad del mundo, que es la peor forma de equivocarse.

  1. ¿En qué unidades está? ¿La duración en milisegundos o en minutos? ¿El tempo en pulsaciones por minuto? ¿La bailabilidad de 0 a 1 o de 0 a 100? Un número sin unidad no significa nada, y confundirlas ha estrellado sondas espaciales de verdad.

  2. ¿Quién lo hizo y cuándo? Un dato tiene autor y fecha. Un dataset de música de hace diez años no lleva lo de este verano, y una fuente anónima no merece la misma confianza que una oficial.

  3. ¿Cómo marca los huecos? Casi ningún dataset está completo. ¿Usa una casilla vacía?, ¿una duración de 0?, ¿un tempo de 0? Saberlo antes te ahorra el disgusto de calcular una media con basura dentro.

  4. ¿Cada fila es una cosa? Comprueba que entiendes qué representa una fila. Si no lo tienes claro, cualquier cuenta que hagas será una cuenta de no-sabes-qué. (Aquí: una fila, una canción.)

  5. ¿Es un dato personal? ¿Hay dentro personas identificables, o eres tú? Tu historial de escucha te retrata; si la respuesta es sí, cambia todo —y de eso trata el último paso del método, que no se te olvide—.

Con la pregunta elegida, el dato localizado y el contrato firmado, ya puedes hacer cuanto hace un analista de verdad. Deja de leer y hazlo conmigo: vamos a recorrer el método entero, de cero a figura, sobre un dato nuevo.

La campaña, de cero a figura

Rompamos el cascarón. Se acabó el catálogo que yo te servía: para este ejemplo trabajado he cogido otra cosa —una biblioteca de Spotify, la de alguien con un gusto muy marcado, que bien podría ser la tuya—. Y una pregunta que cualquiera que use Spotify se ha hecho alguna vez:

¿Qué dice mi música de mí? ¿Qué género mando yo, en qué me distingo del oyente medio del catálogo, y hay reglas escondidas en cómo suenan mis canciones?

Ahora bien, una advertencia de honestidad, que en este libro van por delante: una biblioteca de Spotify de verdad tiene una pega para un libro —sería la mía, no la tuya, y no te saldrían mis números—. Así que no la voy a descargar: la voy a fabricar con una semilla fija, cogiendo canciones reales del catálogo que ya conoces, como las elegiría alguien muy de reggaeton y pop. El conjunto es de mentira (nadie escucha justo estas cien), pero cada canción es de verdad, con sus rasgos de verdad. En tu proyecto, esta primera celda será un read_csv de tu propia biblioteca exportada; aquí es el molde que fabrica un gusto de mentira. Cuanto viene después —interrogar, limpiar, ver, medir, predecir— es idéntico se fabrique o se exporte el dato. Empecemos.

Traer: el dato entra al cuaderno

Esta es la única celda rara de todo el capítulo, y puedes copiarla sin entenderla del todo. Coge del catálogo cien canciones de cinco géneros —muchas de reggaeton y pop, algunas de rock, salsa y classical— y, al final, les mete tres averías a propósito —de las que trae cualquier fichero exportado de verdad—. La semilla 42 garantiza que a ti te salgan las mismas canciones que aquí.

import numpy as np
import pandas as pd

# el catalogo que usaste toda la campana; subelo a colab
catalogo = pd.read_csv("musica.csv")

# --- fabricamos una biblioteca de mentira, pero realista ---
# cogemos canciones de verdad, con una semilla fija, como las
# elegiria alguien muy de reggaeton y pop
rng = np.random.default_rng(42)
receta = {"reggaeton": 30, "pop": 25, "rock": 20,
          "salsa": 15, "classical": 10}

trozos = []
for genero, cuantas in receta.items():
    del_genero = catalogo[catalogo["track_genre"] == genero]
    trozos.append(del_genero.sample(n=cuantas, random_state=rng))
mi_musica = pd.concat(trozos, ignore_index=True)

# y le metemos, aposta, tres canciones rotas tipicas de un export
mi_musica.loc[40, "duration_ms"] = 0    # una que dura 0 ms
mi_musica.loc[80, "tempo"] = 0          # tempo imposible: 0 bpm
mi_musica.loc[95, "energy"] = np.nan    # un hueco

print("Filas y columnas:", mi_musica.shape)
print(mi_musica[["track_name", "track_genre", "danceability",
                 "energy", "valence"]].head())
Filas y columnas: (100, 10)
    track_name track_genre  danceability  energy  valence
0  Moscow Mule   reggaeton         0.804   0.674    0.292
1   Dos Mil 16   reggaeton         0.817   0.670    0.495
2        Caile   reggaeton         0.704   0.756    0.461
3   La Bachata   reggaeton         0.835   0.679    0.850
4   Los Cachos   reggaeton         0.774   0.730    0.421

Ya tienes tu biblioteca dentro del cuaderno: un DataFrame —la tabla de pandas— de 100 filas (cien canciones) y 10 columnas (el nombre, el artista, el género y siete rasgos de sonido). El .head() te enseña las cinco primeras: puro reggaeton, con bailabilidades altas (0,80, 0,82…). Tiene buena pinta. Pero «tiene buena pinta» no es «está bien»: las cinco primeras filas nunca cuentan toda la historia. Toca interrogar.

Firmemos el contrato.

Antes, las cinco preguntas de la sección 9.2.3, respondidas de un tirón: unidades, bailabilidad, energía y alegría van de 0 a 1, la duración en milisegundos, el tempo en pulsaciones por minuto; autor y fecha, el catálogo de Spotify, muestreado con semilla 42; marcador de hueco, un 0 en duración o tempo que ya hemos colado (lo cazaremos enseguida); qué es una fila, una canción; ¿es personal?, esta biblioteca de mentira, no —pero la tuya de verdad, sí, y de eso hablaremos al final—. Contrato firmado; ahora ya podemos fiarnos de cuanto preguntemos.

NotaPara saber más: qué es una semilla

El azar de un ordenador es un falso azar: una receta que escupe números que parecen aleatorios pero salen de una fórmula. La semilla es el número con el que arranca esa receta. Con la misma semilla, la misma tirada: por eso np.random.default_rng(42) muestrea a ti, en tu Colab, exactamente las mismas canciones que a mí —y por eso te salen mis mismas cifras—. Cambia el 42 por cualquier otro número y tendrás otra biblioteca, igual de válida pero distinta. Fijar la semilla convierte un experimento con azar en algo reproducible: la casualidad, domada y repetible a voluntad.

NotaPara saber más: cómo sería con datos de verdad

En tu proyecto, la celda de arriba se reduce a una línea. Exporta tu biblioteca (o una lista) a un CSV, súbelo a Colab con el botón de la carpeta y:

mi_musica = pd.read_csv("mi_biblioteca.csv")

Y si aún no puedes exportar tus rasgos, hay un atajo honesto: coge el propio catálogo musica.csv y fíltralo a tus géneros y artistas favoritos —esa es tu forma de mirarte en el catálogo—. El resto del capítulo funciona igual, letra por letra. Lo único que cambia es de dónde sale la tabla; cuanto le haces, no.

Interrogar: la primera conversación

Nada más traer un dato, hazle la pregunta que lo resume de un golpe: .describe(). Devuelve, para cada columna de números, sus estadísticos básicos —cuántos hay, la media, la desviación, el mínimo y el máximo, y los cuartiles—. Es lo primero que mira un analista, siempre, porque delata lo raro en una sola ojeada.

rasgos = ["danceability", "energy", "tempo", "duration_ms"]
print(mi_musica[rasgos].describe().round(2))
       danceability  energy   tempo  duration_ms
count        100.00   99.00  100.00       100.00
mean           0.64    0.64  121.50    223732.68
std            0.18    0.22   33.69     57842.87
min            0.14    0.00    0.00         0.00
25%            0.53    0.55   97.79    184571.50
50%            0.66    0.69  116.98    224530.50
75%            0.78    0.79  139.99    252656.00
max            0.91    0.96  199.89    439120.00

Léelo con ojo de detective, porque aquí hay tres pistas de que algo huele mal. Primera: count vale 99 en energy, pero la tabla tenía 100 filas —falta un dato, hay un hueco—. Segunda: el min de tempo es 0. ¿Una canción a cero pulsaciones por minuto? No existe: eso es el marcador de «no medí el tempo» disfrazado de número. Tercera: el min de duration_ms es 0  —una canción que dura cero milisegundos, o sea, que no suena—. (Y de paso: esos números gigantes de la duración no son un error, es que están en milisegundos; el contrato ya te avisó.)

Fíjate en algo importante, distinto de otras veces: aquí la basura apenas mueve la media —un par de ceros entre cien no descuadran un promedio—, y por eso se cuela sin que la media te avise. La lección, entonces, es doble: no basta mirar la media, hay que mirar el mínimo y el máximo con lupa. Un cero escondido en el mínimo hace tan poco ruido como daño hará luego. Antes de preguntar nada serio, hay que limpiar.

NotaPara saber más: la media y la mediana, cara a cara

Compara la mean (0,64) de la bailabilidad con su 50 % —la mediana, el valor de en medio— (0,66). Casi iguales: buena señal, quiere decir que no hay basura gorda tirando de la media hacia un lado. Cuando esas dos cifras se separan mucho es cuando debes sospechar: significa que algún puñado de valores extremos (o de basura) está arrastrando la media, mientras la mediana, que solo mira quién está en el centro, aguanta firme. Por eso el .describe() te da las dos, para que las compares de un vistazo.

Caza lo roto: limpiar

Sabes qué buscar: una duración de 0, un tempo de 0 y un hueco. Vamos a cazarlos en dos gestos. Primero, los imposibles: ni una canción dura 0 ms ni suena a 0 bpm, así que todo eso es un «no me lo creo» \(\rightarrow\) lo convertimos en hueco de verdad (NaN, el «nada» de pandas). Y segundo, ya con toda la basura marcada como hueco (los dos ceros y la energía que faltaba), la tiramos de un golpe con .dropna().

# 0 ms y 0 bpm son imposibles: no son datos, son averias
mi_musica.loc[mi_musica["duration_ms"] <= 0, "duration_ms"] = np.nan
mi_musica.loc[mi_musica["tempo"] <= 0, "tempo"] = np.nan

rotas = mi_musica.isna().any(axis=1).sum()
print("Canciones con algo roto:", rotas)

limpio = mi_musica.dropna().copy()
print("Canciones que quedan:", len(limpio), "de", len(mi_musica))
Canciones con algo roto: 3
Canciones que quedan: 97 de 100

Ahí está el recuento de tu limpieza, y es justo el que esperábamos: tres averías (la duración a cero, el tempo a cero y el hueco de energía) marcadas como NaN, y 97 canciones buenas de las 100. Has perdido tres de cien —un 3 %—, un precio ridículo por quitarte de encima cifras que habrían envenenado cada cuenta posterior. Fíjate en el .copy() del final: le pide a pandas una tabla nueva e independiente, para no andar pisando la original —una buena costumbre que evita errores sutiles—.

NotaPara saber más: tirar no es la única salida

Aquí hemos tirado las tres canciones rotas, y con tres sobre 97 es lo más limpio. Pero a veces no puedes permitirte perder filas —quizá tu biblioteca es pequeña, o cada canción cuenta—. Entonces se rellena en vez de tirar: a la energía que falta se le pone, por ejemplo, la mediana de su género (.fillna() con el valor típico de las canciones parecidas). No es hacer trampa si lo cuentas: es una estimación honesta de un hueco, marcada como tal. Tirar o rellenar es una decisión tuya, y como toda decisión de análisis, se escribe para que otro sepa qué hiciste y por qué.

Interrogar otra vez: ahora sí

Con el dato limpio, las preguntas ya no mienten. Repite el .describe() y compara con el de antes:

print(limpio[rasgos].describe().round(2))
       danceability  energy   tempo  duration_ms
count         97.00   97.00   97.00        97.00
mean           0.64    0.64  123.09    226309.02
std            0.18    0.22   31.72     52384.51
min            0.14    0.00   58.30    111442.00
25%            0.53    0.55   99.97    187146.00
50%            0.66    0.69  117.40    226088.00
75%            0.79    0.78  139.99    252346.00
max            0.91    0.96  199.89    439120.00

Otro mundo. Ahora todo cuadra: el tempo va de un mínimo sensato de 58 pulsaciones a un máximo de 200, y la duración más corta ya son 111 442 ms (poco menos de dos minutos), no cero. Este sí es el retrato de una biblioteca de verdad. Ahora, preguntas concretas. ¿Cuál es la canción más bailable de tu biblioteca, y la menos?

mas = limpio.loc[limpio["danceability"].idxmax()]
menos = limpio.loc[limpio["danceability"].idxmin()]
print("Mas bailable: ", mas["track_name"], "->", mas["danceability"])
print("Menos bailable:", menos["track_genre"], "->",
      menos["danceability"])
Mas bailable:  Me Porto Bonito -> 0.911
Menos bailable: classical -> 0.136

.idxmax() te da la posición de la fila con el valor más alto, y .loc[...] la trae entera; así no solo sabes cuánto fue el récord, sino qué canción lo tiene. La más bailable es «Me Porto Bonito», un reggaeton de manual (0,91 de bailabilidad); la menos, una pieza de classical (0,14), como manda el sentido común —nadie perrea a Tchaikovsky—. El dato empieza a contar cosas que no te habías parado a pensar.

Ahora, ¿cómo se reparte tu gusto? Cuento las canciones de cada género con .value_counts(), para ver de un vistazo qué mandas:

print(limpio["track_genre"].value_counts())
track_genre
reggaeton    30
pop          24
rock         20
salsa        14
classical     9
Name: count, dtype: int64

Tu biblioteca no está equilibrada, y eso ya es un hallazgo: el reggaeton manda con 30 canciones de 97 —casi un tercio de todo—, y el classical apenas asoma con 9 (perdió una en la limpieza). Esta cuenta de treinta segundos evita el error clásico de sacar conclusiones «de tu música» cuando en realidad hablas casi solo de reggaeton. Ahora agrupamos con .groupby() —la herramienta reina de pandas— y pedimos la bailabilidad media de cada género: «júntame las canciones por género y dame su media».

print(limpio.groupby("track_genre")["danceability"].mean()
      .round(2).sort_values(ascending=False))
track_genre
reggaeton    0.77
salsa        0.69
rock         0.60
pop          0.58
classical    0.33
Name: danceability, dtype: float64

Ahí tienes la firma bailable de tu gusto, género a género: el reggaeton en la cima (0,77), la salsa pisándole los talones, y el classical hundido en 0,33 —la música de fondo no está hecha para bailar—. Es una tabla preciosa… pero es una tabla, y cinco números todavía cuestan de sentir. Vamos a hacer aquello que mejor cuenta una forma: un dibujo.

Ver: dale forma a tu gusto

Aquí llega la primera victoria que se enseña: la figura. Con matplotlib —la caja de pinturas de Python— vamos a dibujar dos. Y ojo a una diferencia con las misiones del volumen adulto: tu música no tiene fechas, no hay una línea de tiempo que seguir. Así que la primera figura no es una serie: es una nube. Cada punto, una canción, colocada por su energía y su bailabilidad.

import matplotlib.pyplot as plt

fig, ax = plt.subplots(figsize=(6.4, 3.2))
ax.scatter(limpio["energy"], limpio["danceability"],
           color="#0072B2", alpha=0.6)
ax.set_xlabel("energia")
ax.set_ylabel("bailabilidad")
fig.tight_layout()
fig.savefig("mis09_dispersion.pdf")

Figura 9.1. Cada punto es una canción de tu biblioteca, colocada por su energía (horizontal) y su bailabilidad (vertical). Sin ninguna orden extra, tu gusto dibuja su forma: una nube alta y a la derecha —música con energía y para moverse— con una cola baja a la izquierda, la de las piezas tranquilas. La figura cuenta en un vistazo cuanto 97 filas escondían.

Mira la figura 9.1. No has tenido que decirle a la máquina «agrupa mi música»: los grumos han salido solos, porque estaban en el dato. Arriba a la derecha se apelotona el reggaeton y la salsa (mucha energía, muy bailable); abajo a la izquierda, sueltas, las piezas de classical. Ver eso es entender de un golpe cuanto las columnas de números solo insinuaban.

Pero para comparar géneros y rasgos a la vez, mejor que la nube es un mapa de calor: una fila por género, una columna por rasgo, y el color dice el valor. Es la firma sonora de tu gusto, entera, en una rejilla:

rasgos3 = ["danceability", "energy", "valence"]
tabla = limpio.groupby("track_genre")[rasgos3].mean()
tabla = tabla.sort_values("danceability", ascending=False)

fig, ax = plt.subplots(figsize=(6.4, 3.2))
mapa = ax.imshow(tabla.values, cmap="magma", vmin=0, vmax=1,
                 aspect="auto")
ax.set_xticks(range(3))
ax.set_xticklabels(["bailable", "energia", "alegria"])
ax.set_yticks(range(len(tabla)))
ax.set_yticklabels(tabla.index)
fig.colorbar(mapa, ax=ax, label="valor medio (0 a 1)")
fig.tight_layout()
fig.savefig("mis09_mapacalor.pdf")

Figura 9.2. La media de cada rasgo (columnas) en cada género (filas): cuanto más claro, más alto el valor. De un vistazo se lee la firma de cada estilo: el reggaeton, encendido en bailabilidad; la salsa, disparada en alegría; el classical, apagado en todo. Es la misma tabla de números de antes, pero ahora se siente.

La figura 9.2 es tu respuesta a «¿qué define cada género?», hecha imagen. Cualquiera que la mire un segundo entiende que el classical es la fila oscura y el reggaeton la encendida, sin que le expliques nada —y esa, que un desconocido capte tu hallazgo de un vistazo, es la marca de una buena figura—. Pero antes de medir en serio, sácale a tu música una pregunta más —de las de contar—, que la respuesta te va a sorprender.

Contar y dibujar: las canciones de fiesta

Preguntar no es solo pedir medias: muchas veces la pregunta que más golpea es un conteo. «¿Cuántas canciones de fiesta pura tengo de cada género?» El truco es bonito: creas una columna de verdadero/falso —¿pasa esa canción de 0,7 de bailabilidad?— y la sumas por género. En pandas, sumar una columna de True y False cuenta los verdaderos, porque por dentro True vale 1 y False vale 0.

limpio["muy_bailable"] = limpio["danceability"] > 0.7
por_genero = limpio.groupby("track_genre")["muy_bailable"].sum()
print(por_genero.sort_values(ascending=False))
track_genre
reggaeton    23
salsa         7
pop           7
rock          5
classical     0
Name: muy_bailable, dtype: int64

Léelo despacio: 23 de tus 30 reggaetones cruzan la raya de «fiesta pura»… y el classical, cero. Dibújalo y salta a la vista:

por_genero = por_genero.sort_values(ascending=False)
fig, ax = plt.subplots(figsize=(6.4, 3.2))
ax.bar(por_genero.index, por_genero.values, color="#D55E00")
ax.set_xlabel("genero")
ax.set_ylabel("canciones muy bailables (> 0.7)")
fig.tight_layout()
fig.savefig("mis09_generos.pdf")

Figura 9.3. Cuántas canciones pasan de 0,7 de bailabilidad en cada género. El reggaeton arrasa (23); el classical no tiene ninguna. Es la misma firma bailable de antes, vista con otros ojos: no como una media alta, sino como montones de canciones que, una a una, son para moverse.

La figura 9.3 guarda la lección de fondo, que vale para todo tu futuro como analista: el mismo dato y la misma verdad, dichos de dos formas —«el reggaeton tiene 0,77 de bailabilidad media», o «23 de sus 30 canciones son de fiesta pura»—. Un buen analista elige la forma que su público entiende mejor, sin mentir en ninguna. Ahora sí: a medir con cuidado.

Medir sin engañarte: reggaeton contra classical

La figura grita que el reggaeton es más bailable que el classical. Pero «se ve mucho» no es una medida; un analista lo cuantifica, y —esto separa a un profesional de un aficionado— le pone un margen. Comparemos las dos:

regg = limpio[limpio["track_genre"] == "reggaeton"]["danceability"]
clas = limpio[limpio["track_genre"] == "classical"]["danceability"]

def margen(s):
    return 1.96 * s.std() / np.sqrt(len(s))

print("Reggaeton:", round(regg.mean(), 2), " desv",
      round(regg.std(), 2), " n", len(regg))
print("Classical:", round(clas.mean(), 2), " desv",
      round(clas.std(), 2), " n", len(clas))
dif = regg.mean() - clas.mean()
m = margen(regg) + margen(clas)
print("Diferencia:", round(dif, 2), " margen aprox +/-", round(m, 2))
Reggaeton: 0.77  desv 0.08  n 30
Classical: 0.33  desv 0.18  n 9
Diferencia: 0.45  margen aprox +/- 0.15

El reggaeton marca 0,77 de bailabilidad media; el classical, 0,33. La diferencia es de 0,45. Y ahora la parte que casi nadie hace: ese margen de \(\pm 0,15\). Significa que, con estos datos, la diferencia real anda por 0,45 arriba o abajo de 0,15. Como la diferencia (0,45) es tres veces mayor que su margen (0,15), la conclusión es sólida: no es casualidad, tu reggaeton es de verdad mucho más bailable que tu classical. Aquí la respuesta era obvia, pero el hábito —medir la diferencia y su margen— es el que te salvará el día que compares dos cosas parecidas, donde el ojo se engaña y solo el margen dice la verdad.

(Un aviso para el que compruebe con lápiz: si restas las medias redondeadas no te saldrá exactamente la diferencia impresa —0,77 menos 0,33 da 0,44, y aquí pone 0,45—. No es un error: la resta se hace con los valores completos y solo se redondea al final, que es lo honrado. Es la regla que aprendiste en la Misión 1, viva en tu propio proyecto.)

El otro filo del margen: cuando no puedes concluir

Con el reggaeton contra el classical, el margen solo confirmaba lo evidente. Su verdadero valor aparece cuando la respuesta no salta a la vista —y ahí es donde casi todo el mundo mete la pata—. Pregunta fina: ¿es tu pop más bailable que tu rock? En la nube no se distingue. Midámoslo, cada uno con su margen:

pop = limpio[limpio["track_genre"] == "pop"]["danceability"]
rock = limpio[limpio["track_genre"] == "rock"]["danceability"]
print("Pop: ", round(pop.mean(), 2), " margen +/-",
      round(margen(pop), 2))
print("Rock:", round(rock.mean(), 2), " margen +/-",
      round(margen(rock), 2))
dif = pop.mean() - rock.mean()
print("Diferencia:", round(dif, 2), " margen aprox +/-",
      round(margen(pop) + margen(rock), 2))
Pop:  0.58  margen +/- 0.06
Rock: 0.6  margen +/- 0.06
Diferencia: -0.02  margen aprox +/- 0.12

Aquí está la lección más importante del capítulo, así que subráyala: la diferencia es 0,02 (y encima con el signo «al revés», el rock sale un pelo por encima), pero el margen es 0,12 —seis veces más grande que la propia diferencia—. ¿Qué significa? Que no puedes concluir que un género sea más bailable que el otro. El vaivén del azar es mayor que la diferencia que crees ver; con este dato, tu pop y tu rock son indistinguibles en bailabilidad. La respuesta honesta a «¿cuál es más bailable?» es «no lo sé, y mi dato no da para saberlo».

Cuesta decir «no lo sé». Un titular gritaría «¡el rock, más bailable que el pop!», y sería una mentira con forma de dato: cierto que 0,60 es mayor que 0,58, pero esa diferencia cabe entera dentro del azar. Saber cuándo callar es tan de analista como saber cuándo afirmar, y el margen es quien te dice cuál de las dos toca: si la diferencia lo supera de sobra —como el 0,45 de antes—, afirma; si no lo supera —como estos 0,02—, calla. Esa disciplina de no afirmar más de lo que el dato sostiene es, exactamente, la honestidad que da nombre a esta misión.

Cuando esperabas un patrón y no está

Un último gesto de medir, y de los que más carácter forman. A veces tienes una corazonada razonable —«las canciones explícitas serán las más de fiesta, las más bailables»— y quieres comprobarla. Separamos las que van marcadas como explícitas de las que no y comparamos su bailabilidad:

explicitas = limpio[limpio["explicit"]]["danceability"]
normales = limpio[~limpio["explicit"]]["danceability"]
print("Explicitas:  ", round(explicitas.mean(), 2), " margen +/-",
      round(margen(explicitas), 2), " n", len(explicitas))
print("No explicitas:", round(normales.mean(), 2), " margen +/-",
      round(margen(normales), 2), " n", len(normales))
dif = explicitas.mean() - normales.mean()
print("Diferencia:", round(dif, 2), " margen aprox +/-",
      round(margen(explicitas) + margen(normales), 2))
Explicitas:   0.71  margen +/- 0.08  n 16
No explicitas: 0.62  margen +/- 0.04  n 81
Diferencia: 0.08  margen aprox +/- 0.11

Casi nada. La diferencia es de 0,08, dentro de un margen de 0,11 —más ancho que la propia diferencia—. Traducido: con estos datos no puedes afirmar que tus canciones explícitas sean más bailables. Parece que apuntan hacia arriba (0,71 frente a 0,62), pero solo tienes 16 explícitas y el azar cabe entero en ese hueco. Tu corazonada, por razonable que sonara, no está demostrada en los datos.

Y esto —atención— no es un fracaso: es un hallazgo. «No puedo concluir» es una respuesta de verdad, tan valiosa como un «sí, y con margen de sobra», y hay que contarla igual. La ciencia está llena de corazonadas preciosas que los datos no sostuvieron, y aceptarlo sin enfadarse es la señal de que ya piensas como analista y no como quien defiende su idea a toda costa. El objetivo nunca fue tener razón; era saber la verdad. Si tu proyecto termina en «esperaba esto y el dato no llega para afirmarlo», enhorabuena: has hecho ciencia de la buena.

Predecir: ¿adivino la alegría por el sonido?

La pregunta gorda, la que da nombre al proyecto. ¿Se puede adivinar un rasgo de una canción a partir de otro? Corazonada: cuanto más bailable es una canción, más alegre suena (la valence, ese rasgo de 0 a 1 que mide cómo de positiva es). Un modelo de predicción convierte esa corazonada en un número y en una recta. El más sencillo del mundo —y de los más útiles— es la recta de tendencia: trazar la línea que mejor pasa por los puntos. La calcula np.polyfit, que devuelve la pendiente (cuánto sube la alegría por cada punto de bailabilidad) y el corte.

pend, corte = np.polyfit(limpio["danceability"],
                         limpio["valence"], 1)
r = limpio["danceability"].corr(limpio["valence"])
print("Relacion (r):", round(r, 2))
print("pendiente:", round(pend, 2), " corte:", round(corte, 2))
Relacion (r): 0.59
pendiente: 0.86  corte: -0.06

La pendiente es positiva (0,86): sí, cuanto más bailable, más alegre, como intuías. Y la fuerza de esa relación es 0,59 —eso es la \(r\), que va de 0 (ninguna) a 1 (perfecta)—: una relación real, pero floja. El sonido predice el ánimo a medias, no lo clava. Pero —y este «pero» es el alma del método— un número que sale de los mismos datos que lo inspiraron no vale de nada hasta que lo pones a prueba. La prueba honesta: esconde un trozo de canciones, ajusta la recta sin ellas, y que las prediga «a ciegas». Luego destapa el valor real y mira si acertó.

prueba = limpio.sample(frac=0.3, random_state=7)
entreno = limpio.drop(prueba.index)

p, c = np.polyfit(entreno["danceability"], entreno["valence"], 1)
pred = p * prueba["danceability"] + c
error = (pred - prueba["valence"]).abs().mean()
print("Entreno:", len(entreno), " prueba:", len(prueba))
print("Error medio de la alegria:", round(error, 2))
Entreno: 68  prueba: 29
Error medio de la alegria: 0.19

Tu recta, sin haber visto esas 29 canciones, adivinó su alegría con un error medio de 0,19 (en una escala de 0 a 1). No es magia —0,19 no es poco, la relación era floja—, pero para adivinar el ánimo solo por lo bailable de la canción, tampoco está mal. Y este gesto —predecir sobre algo que el modelo no ha visto— es la única forma decente de saber si tu predicción sirve o solo repite cuanto ya sabía. Un modelo que solo acierta los datos con los que lo entrenaste no ha aprendido nada; solo se los ha memorizado. Toca pintarlo: la nube de bailabilidad contra alegría, con la recta encima.

recta_x = np.array([limpio["danceability"].min(),
                    limpio["danceability"].max()])
recta_y = pend * recta_x + corte

fig, ax = plt.subplots(figsize=(6.4, 3.2))
ax.scatter(limpio["danceability"], limpio["valence"],
           color="#0072B2", alpha=0.6)
ax.plot(recta_x, recta_y, color="#D55E00", linewidth=2,
        label="recta de tendencia")
ax.set_xlabel("bailabilidad")
ax.set_ylabel("alegria (valence)")
ax.legend()
fig.tight_layout()
fig.savefig("mis09_prediccion.pdf")

Figura 9.5. Cada punto, una canción, por su bailabilidad (horizontal) y su alegría (vertical); la recta naranja resume la relación. Sube de izquierda a derecha —más bailable, más alegre—, pero la nube es gorda: la recta acierta la tendencia, no cada canción. Eso es una relación real pero floja, dibujada.

En la figura 9.5 se ve a la vez la verdad y su límite: la recta sube (más bailable, más alegre), pero los puntos se esparcen lejos de ella. Habías sentido «lo bailable suena más alegre»; ahora lo has medido, predicho y dibujado, y también has aprendido a no fiarte de más: la relación existe, pero es floja. Eso es cerrar el círculo del método con honestidad.

NotaPara saber más: por qué NO se predice el éxito por el sonido

Podrías pensar: «si adivino la alegría por el sonido, ¿adivino el éxito?». Pues no, y conviene que lo compruebes tú:

mejor = catalogo["popularity"].corr(catalogo["danceability"])
print("popularity ~ danceability: r =", round(mejor, 2),
      " r2 =", round(mejor ** 2, 2))
popularity ~ danceability: r = 0.25  r2 = 0.06

El rasgo que más se relaciona con la popularidad (lo bailable) explica un 6 % de ella; el otro 94 % es cosa social —quién la canta, en qué playlist entra, el momento que pilla—, no acústica. El éxito de una canción no está en su sonido. Es la trampa de siempre: que dos cosas se relacionen un poco no significa que una cause la otra, y aquí ni relación fuerte hay. Un analista honesto predice cuanto el dato sostiene (la alegría, a medias) y calla cuanto no (el éxito).

NotaPara saber más: qué hace por dentro polyfit

Una recta es \(y = a + b\,x\): \(a\) es el corte (dónde cruza) y \(b\) la pendiente (cuánto sube por cada paso de \(x\)). Por una nube de puntos no pasa una recta perfecta, así que polyfit busca la que se equivoca lo menos posible con todos a la vez: la que hace más pequeña la suma de las distancias (al cuadrado) de cada punto a la línea. Se llama mínimos cuadrados, y es el ladrillo con el que están hechos casi todos los modelos que verás de mayor. Tú le das los puntos; él te da la mejor recta. En el volumen adulto se deduce con álgebra; aquí te basta saber qué pide y qué devuelve.

NotaPara saber más: no estires la recta demasiado

Una recta de tendencia es de fiar cerca de los datos que la fabricaron, y cada vez menos según te alejas. Tus canciones van de 0,14 a 0,91 de bailabilidad; usar la recta para adivinar la alegría de una hipotética canción con bailabilidad 1,5 sería un disparate —ni existe ese valor, ni la recta sabe qué pasa tan lejos—. A eso se le llama extrapolar, y es de las trampas más comunes: la recta no sabe que se te acaba el dato, sigue subiendo obediente hacia el infinito. Tú sí lo sabes. Usa la tendencia dentro del rango de tus canciones, no fuera; y si predices lejos, di bien alto lo poco que puedes fiarte.

Proteger: ¿de quién es este dato?

Queda el séptimo paso, el que casi nadie enseña y por eso este libro insiste. Antes de publicar tu proyecto, la pregunta del contrato que dejamos pendiente: ¿de quién es este dato, y puede hacer daño a alguien?

Con esta biblioteca de mentira, la respuesta es tranquila: sale del catálogo público de Spotify, son canciones publicadas, de nadie en particular. Puedes compartir este análisis sin pensarlo dos veces. Por eso es un dato ideal para aprender el método: te deja practicar sin pisar terreno delicado.

Pero cambia el dato y cambia todo. Cuando hagas tu proyecto con tu biblioteca de verdad —tu historial de escucha exportado— estarás tocando un dato personal, tuyo. Y no es inocente: cuánto escuchas, a qué horas, qué pones cuando estás triste, con quién compartes playlists… tu música te retrata más de cuanto crees. La regla que aprendiste en la misión de la huella se enciende como una alarma: lo defensivo primero. Nunca publiques el historial de escucha de otra persona sin su permiso; con el tuyo, piensa dos veces qué compartes, porque tres datos inocentes juntos pueden señalarte más de lo que imaginas. El poder de hacer hablar a los datos viene con el deber de no hacerles decir cosas que perjudiquen a nadie.

La regla de oro del analista con conciencia.

Antes de publicar, pregúntate: «si este dato fuera sobre mí, ¿me parecería bien que alguien lo colgara así?». Si la respuesta titubea, no lo cuelgues, o quítale los datos que te identifican. Un analista de verdad no es solo el que saca la verdad de los números: es el que sabe cuándo no debe.

La victoria

Has recorrido el método entero sobre un dato que no era el catálogo que te daban, y ha hablado: tienes la firma de tu gusto, tu récord, tu comparación con margen, tu predicción medida y puesta a prueba, cinco figuras y una reflexión sobre a quién pertenece. Eso ya es un proyecto. Rematémoslo como remata un analista: con una función que resume todo el hallazgo en un parte listo para enseñar.

def informe(df):
    d = df["danceability"]
    return {
        "canciones": len(df),
        "genero_top": df["track_genre"].value_counts().idxmax(),
        "bailabilidad_media": round(d.mean(), 2),
        "mas_bailable": round(d.max(), 2),
        "menos_bailable": round(d.min(), 2),
    }

parte = informe(limpio)
for clave, valor in parte.items():
    print(clave, "->", valor)
canciones -> 97
genero_top -> reggaeton
bailabilidad_media -> 0.64
mas_bailable -> 0.91
menos_bailable -> 0.14

Cinco hechos que resumen tu gusto entero, calculados —no tecleados a mano— por una función que servirá igual para la biblioteca de cualquiera que le pases. Ese diccionario es tu proyecto en miniatura: la respuesta a la pregunta con la que empezaste, en cifras que puedes defender porque sabes de dónde sale cada una.

¿Lo lograste?

Como en cada misión, no te fías de que «parece bien»: lo compruebas. Estos tres guardianes vigilan las decisiones que más fácil se te habrían torcido —la limpieza, los valores fuera de rango y las duraciones a cero—. Si los tres callan, has vencido al jefe final:

assert parte["canciones"] == 97, "Revisa la limpieza."
assert parte["mas_bailable"] <= 1.0, "Bailabilidad fuera de rango."
assert (limpio["duration_ms"] > 0).all(), "Quedan duraciones a 0."
print("Lo lograste. Insignia desbloqueada: analista.")
Lo lograste. Insignia desbloqueada: analista.

Si ves ese mensaje, enhorabuena doble: has completado un análisis entero de cero a figura y lo has comprobado en vez de creértelo. La insignia analista es tuya. Pero ojo —y esto es lo importante—, la has ganado con mi dato. La de verdad, la que no te puede dar ningún libro, la ganas con el tuyo. A eso vamos en los retos.

Guarda y comparte tu trabajo

Un proyecto que solo vive en tu pantalla no le sirve a nadie. Antes de cerrar, guarda las dos cosas con valor: el dato ya limpio —para que otro, o tú mañana, no tenga que repetir la limpieza— y tus figuras.

limpio.to_csv("mi_musica_limpia.csv", index=False)  # el dato limpio
# las cinco figuras ya quedaron guardadas: cada bloque de dibujo
# terminaba en su propio fig.savefig(...). En Colab las descargas
# desde el panel de la carpeta, a la izquierda.
print("Guardado:", len(limpio), "canciones limpias")

.to_csv(...) escribe tu tabla en un fichero de texto, listo para volver a cargar con read_csv; el index=False evita que pandas le añada una columna de números de fila que no necesitas. Y para compartir el proyecto entero —código, figuras y bitácora, todo junto y ejecutable— Colab te lo pone fácil: el botón Compartir genera un enlace, y desde su menú puedes guardar una copia en GitHub para que cualquiera lo abra y lo reejecute. Eso —un cuaderno que otra persona puede abrir y correr— es un proyecto de verdad: no un resultado suelto, sino el camino entero, reproducible de principio a fin.

La bitácora del analista: tu primer portafolio

Durante toda la campaña has ido anotando tus hallazgos misión a misión en la bitácora. Pues bien: ese cuaderno-diario ya es tu primer portafolio —la prueba, enseñable a cualquiera, de todo cuanto sabes hacer—. Un portafolio no es un examen con nota; es una colección de trabajos que hablan por ti. Y para este proyecto final, tu entrada de bitácora debe ser la más completa de todas, porque es la plantilla de cualquier proyecto que hagas a partir de ahora. Anota:

  • La pregunta, tal cual, con sus cuatro propiedades: «¿qué dice mi música de mí, qué género mando y hay reglas en cómo suena?».

  • La fuente del dato: de dónde salió, en qué unidades. (Aquí: biblioteca de mentira muestreada del catálogo de Spotify con semilla 42, 100 canciones de cinco géneros.)

  • Qué limpiaste: «3 rotas de 100 —una a 0 ms, un tempo a 0 y un hueco de energía—; tiradas, quedan 97».

  • Los hechos, con su número: género top reggaeton (30 canciones); bailabilidad media 0,64 (catálogo 0,58); reggaeton \(0{,}45 \pm 0{,}15\) más bailable que classical; alegría predicha desde la bailabilidad con error de 0,19 en la prueba a ciegas.

  • Las figuras: pega las que cuenten tu historia. Una imagen vale por mil celdas.

  • Qué no sabes todavía: «el sonido predice la alegría solo a medias (\(r\) 0,59), y la popularidad, casi nada (\(r\) 0,25)». Un buen analista presume de cuanto ignora tanto como de cuanto sabe.

Escríbelo en una celda de texto al final del cuaderno, con sus figuras dentro, y guárdalo. Eso —no un diploma— es lo que le enseñarás a quien quieras convencer de que sabes hacer ciencia con datos. Y lo mejor: lo hiciste tú, se reproduce ejecutándolo entero, y cada cifra tiene su origen. Un portafolio honesto vale más que uno espectacular.

Retos: elige tu nivel

Ahora en serio: te toca a ti. Los primeros retos son sobre la biblioteca que ya tienes cargada —para soltar la mano—; los últimos te sueltan del todo. Como siempre: \(\star\) imprescindible, \(\star\star\) te reta, \(\star\star\star\) es de jefe. Y en todos, la regla de oro de la campaña: predice antes de ejecutar.

  • El género menos bailable. Ya sabes que el reggaeton es el más bailable. Usa el groupby de la bailabilidad media y, con .idxmin(), encuentra el de media más baja. Apuesta cuál antes de mirar.

  • Pop contra rock, pero en energía. Copia la comparación con margen, pero enfrenta pop y rock en energy en vez de bailabilidad. ¿Puedes concluir algo, o vuelve a ganar el margen?

  • Canciones muy alegres. Cuenta cuántas canciones de toda tu biblioteca pasan de 0,8 de valence. Pista: filtra con limpio[limpio["valence"] > 0.8] y mira su len.

  • La mediana por género. Repite la firma bailable con .median() en vez de .mean(). ¿Cambia el orden de los géneros? Si apenas cambia, ¿qué te dice eso sobre la basura que quedaba?

  • ★★ Tu propia figura. Dibuja la bailabilidad media por género como una línea con marcadores (ax.plot(..., marker="o")) en vez del mapa de calor. ¿Cuál cuenta mejor las diferencias?

  • ★★ Limpiar rellenando. En vez de tirar la canción sin energía, rellénala con la mediana de su género (.fillna()) antes del dropna. Compara la media final: ¿cuánto cambia? ¿Te fías más de una o de otra, y por qué?

  • ★★ La media a mano. Calcula la bailabilidad media del reggaeton sin groupby: filtra sus filas y usa .mean(). Comprueba que te da 0,77, como la tabla. Si cuadra, entiendes qué hace groupby por dentro.

  • ★★ Caza un intruso nuevo. Añade a mano una canción con valence de 5 (imposible: la alegría va de 0 a 1) y amplía tu limpieza para que también la cace. ¿Tu tope de «imposible» vigilaba solo la duración y el tempo? Amplíalo a los rasgos de 0 a 1.

  • ★★★ El jefe: el método en una función. Escribe proyecto(df) que reciba la tabla sucia y haga sola los pasos: limpiar, resumir y devolver el diccionario del informe. Pruébala con un assert de que devuelve 97 canciones. Acabas de empaquetar toda la campaña en un botón.

  • ★★★ El jefe: adivina el género por el sonido. En vez de predecir un rasgo, retoma la victoria de la misión de los modelos y entrena algo que, dados los rasgos de una canción, adivine su track_genre. ¿Distingue el reggaeton del classical? (Pista: son la firma más separada, tiene que acertarlos casi siempre.)

  • ★★★ El jefe final de verdad: tu proyecto. Este es el jefe, el que de verdad te hace analista. Hazlo entero, tú solo:

    1. Elige una pregunta tuya que cumpla las cuatro propiedades (concreta, medible, respondible, tuya).

    2. Consigue los datos: exporta tu biblioteca de Spotify —o filtra el catálogo a tus favoritos, o mide tú algo dos semanas—. Fírmales el contrato de las cinco preguntas.

    3. Corre el método entero: trae, interroga, limpia, ve, mide, predice, protege. No te saltes ninguno.

    4. Saca al menos una figura que conteste tu pregunta de un vistazo.

    5. Escribe la bitácora de ese proyecto como te enseñé arriba, con su honestidad: qué sabes y qué no.

    Cuando lo termines, no habrás hecho un ejercicio de un libro: habrás hecho ciencia. Ese cuaderno es tuyo, sobre algo que te importa, y no existía hasta que tú lo hiciste. Ahí, y no antes, eres analista de verdad.

¿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.

Los tropiezos del novato

Antes de soltarte del todo, un mapa de las trampas —las mismas en las que cae todo el mundo la primera vez, y que tú ya sabes esquivar porque las has sufrido en la campaña—. Cuando tu proyecto te dé un resultado raro, repasa esta lista: casi siempre el fallo es uno de estos siete.

  1. Fiarte de un dato sucio. Un cero escondido en el mínimo no te descuadra la media, pero envenena las cuentas. Siempre .describe() antes de concluir nada, y mira el mínimo y el máximo con lupa. (Recuerda aquella duración a 0 y aquel tempo a 0.)

  2. Afirmar sin margen. «A es mayor que B» no vale si la diferencia cabe dentro del azar. Mide la diferencia y su margen, y calla cuando el margen gana. (Recuerda el pop y el rock, indistinguibles.)

  3. Evaluar sobre datos que el modelo ya vio. Un modelo que acierta los datos con los que lo entrenaste no ha aprendido: se los ha memorizado. Reserva siempre canciones que no vea para probarlo a ciegas.

  4. Estirar la recta demasiado lejos. Una tendencia vale dentro del rango de tus datos, no fuera. Cuanto más lejos extrapolas, más frágil es la cifra —y más honesto hay que ser al darla—.

  5. Confundir que dos cosas vayan juntas con que una cause la otra. Lo bailable y lo alegre van juntos; eso no prueba que bailar cause alegría. Y el sonido se relaciona un pelín con el éxito, pero no lo causa: «van juntos» y «uno causa el otro» son cosas distintas, y demostrar la segunda es muchísimo más difícil.

  6. Enseñar una tabla donde cabía una figura. Cinco números en fila no se sienten; un mapa de calor o dos montañas, sí. Si tu hallazgo puede entrar por los ojos, que entre por los ojos.

  7. Teclear a mano un número que podías calcular. El número tecleado no se reproduce ni se puede comprobar; el calculado, sí. Que cada cifra de tu informe salga de una celda que se puede reejecutar.

Ninguno de estos tropiezos es de tontos: son los que comete quien tiene prisa por concluir. El antídoto es siempre el mismo —ir despacio, comprobar y no afirmar más de lo que el dato aguanta—. Si esquivas estos siete, ya analizas con más cabeza que muchísima gente que lleva años en esto.

Tu caja de herramientas

Esta es la chuleta del método entero: no órdenes sueltas, sino el orden de trabajo completo con el arma de cada paso. Pégala en la bitácora; es el guion de cualquier proyecto que hagas.

  • 0. Pregunta. Concreta, medible, respondible y tuya. Y el contrato: unidades, autor, fecha, marcador de hueco, qué es una fila, ¿es personal?

  • 1. Traer. pd.read_csv("datos.csv"); mira .shape y .head().

  • 2. Interrogar. .describe(), .idxmax(), .idxmin(), y agrupar con .groupby("clave").mean().

  • 3. Limpiar. Marcar imposibles con .loc[...] = np.nan, contar con .isna().sum(), tirar con .dropna() o rellenar con .fillna().

  • 4. Ver. plt.subplots(), ax.scatter(...), ax.bar(...), ax.hist(...), fig.savefig("fig.pdf").

  • 5. Medir. Media y margen (1.96 * s.std() / np.sqrt(len(s))); histogramas para ver si dos grupos se solapan.

  • 6. Predecir. np.polyfit(x, y, 1) para la recta; probar a ciegas sobre datos que el modelo no vio.

  • 7. Proteger. «Si fuera sobre mí, ¿me parecería bien publicarlo?». Lo defensivo primero.

  • Comprobar. assert resultado == esperado en cada victoria.

  • Guardar. La bitácora con sus figuras: tu portafolio.

No la memorices: úsala. Después de dos o tres proyectos, el método se te hará tan natural como respirar —y ese día, ya no necesitarás la chuleta—.

Cuando quieras ir en serio

Toda la campaña ha cabido en una pestaña del navegador, sin instalar nada, y para aprender ha sido perfecto. Pero llega un momento —cuando un proyecto te importa de verdad, cuando quieres que corra idéntico dentro de un año o que otra persona lo reejecute sin sustos— en que apetece dar el salto al taller de los mayores. No lo necesitas para nada de cuanto has hecho; está ahí para cuando lo quieras.

  • Tu propio ordenador, con un buen editor. En vez del navegador, un programa como VS Code, donde escribes tu código en ficheros .py y los ejecutas tú. Más control, menos magia.

  • Versiones clavadas con uv. El mayor enemigo del «en mi cuaderno funcionaba» es que las bibliotecas cambian. Herramientas como uv congelan la versión exacta de pandas, de numpy y de todo lo demás, para que tu proyecto corra idéntico en cualquier máquina y en cualquier fecha. Es la reproducibilidad que aprendiste —«reabre y sale lo mismo»—, subida de nivel.

  • Historial con git. Un cuaderno de bitácora para tu código: guarda cada versión, quién cambió qué y cuándo, y te deja volver atrás si rompes algo. Es la máquina del tiempo de todo programador.

  • Pruebas automáticas. Tus assert de «¿lo lograste?», crecidos: un montón de comprobaciones que se lanzan solas cada vez que tocas el código, para avisarte al instante si algo dejó de funcionar. La honestidad de comprobar, hecha rutina.

NotaPara saber más: git en tres órdenes

No te asustes: el git de andar por casa cabe en tres gestos. git add pone tus cambios «en la cola»; git commit -m "lo que hice" los guarda para siempre con una nota tuya; git push los sube a la nube (por ejemplo, a GitHub). A partir de ahí tienes una máquina del tiempo: cada commit es una foto de tu proyecto a la que siempre puedes volver, y su nota recuerda qué cambiaste y por qué. Suena a mucho para una biblioteca de música, pero el día que un proyecto tuyo crezca —o que lo hagáis entre varios— git es lo que te ahorra el caos de acabar con diez ficheros llamados «definitivo», «definitivo_bueno» y «definitivo_de_verdad».

El puente hacia ese mundo es el volumen adulto del que nace este libro: Python para la Ciencia de Datos. Allí está el álgebra que aquí dejamos en cajas, la ingeniería que aquí escondimos, y la misma música tratada con todo el rigor. Si te ha picado el gusanillo —y espero que sí—, ese es tu siguiente paso. Y para el gran salto de estilo, dos clásicos: la filosofía de Python en veinte líneas (escribe import this y léela; sigue siendo verdad [@pep20]) y, cuando quieras escribir código del que presumir, @ramalho2022fluent.

NotaPara saber más: el cuaderno también se comprueba entero

Antes de enseñar un proyecto, hazle la prueba de fuego de la reproducibilidad: en Colab, Entorno de ejecución \(\rightarrow\) Reiniciar y ejecutar todo. Borra toda la memoria y lo corre limpio, de la primera celda a la última. Si sale lo mismo, tu proyecto es sólido; si algo se rompe, mejor descubrirlo tú ahora que otro después. En un estudio de más de un millón de cuadernos públicos, la mayoría no volvía a dar el mismo resultado, casi siempre por celdas ejecutadas en desorden [@pimentel2019large]. Que tu portafolio no sea de esos: un resultado que no se puede repetir no es un resultado, es una anécdota.

Jefe Final superado. Insignia analista, desbloqueada —y con ella, la campaña entera—. Piensa por un momento en el camino: empezaste sin saber qué era una variable y ahora coges un dato que nadie ha tocado, le haces una pregunta, lo limpias, lo dibujas, lo mides con su margen, predices aquello que aún no conoces y decides con conciencia qué publicar. Por el camino has llenado la vitrina, insignia a insignia:

  • primer contacto —hiciste que la máquina te obedeciera—;

  • mensajero del dato —bajaste el catálogo real a tu cuaderno—;

  • domador de pandas —lo interrogaste hasta sacarle una respuesta—;

  • cazador de atípicos —cazaste sus canciones rotas—;

  • cartógrafo del sonido —lo dibujaste hasta verle la forma—;

  • juez del dato —mediste sin dejar que el azar te engañara—;

  • domador de modelos —enseñaste a la máquina a adivinar el género por el sonido—;

  • guardián de la huella —aprendiste a protegerte y a respetar a los demás—;

  • y hoy, analista —capaz de hacerlo todo con un dato que elijas tú—.

Nueve insignias; pero ninguna vale tanto como la costumbre que llevas puesta debajo: no fiarte de un número que no puedas reproducir, no adornar un resultado, no esconder aquello que ignoras.

Piensa en qué significa eso de verdad. Casi todo el mundo vive rodeado de datos —en las noticias, en las redes, en las aplicaciones del móvil— y los recibe sin poder comprobarlos: se cree el titular, o no se lo cree, a fe. Tú ya no. Tú puedes coger la cifra, rastrear de dónde sale, mirarla con sus márgenes y decidir por ti mismo si se sostiene. Eso es una forma de libertad, y la tienen muy pocos. No la malgastes creyéndote todo; tampoco dudando de todo por sistema. Úsala como un analista: comprobando.

La música fue solo la excusa —una buena excusa— para enseñarte un oficio que sirve para el clima, para la salud, para las estrellas o para cuanto se te ocurra medir. Ahora el dato lo eliges tú, y la pregunta también. El mundo está lleno de números esperando a que alguien, por fin, les pregunte lo correcto. Ese alguien ya puedes ser tú. Ve y hazlos hablar.