lección 2
Lunes: primer contacto con los datos
Cargar los cinco extractos con pandas, ver su forma y cómo se cruzan por el id de cliente, y toparte con la suciedad del core.
⏱ 50 min
## Lunes, 11:00. Lo primero no es modelar: es mirar
Ya sabes qué te piden: ordenar a los clientes por riesgo de baja. La tentación del primer día es abrir scikit-learn y entrenar algo cuanto antes. Resístela. Antes de modelar hay un trabajo que no sale en las fotos y que separa a quien sabe del oficio de quien improvisa: mirar los datos. Saber cuántas filas tiene cada tabla, qué columnas trae, qué tipo ve el ordenador en cada una, cuántos huecos hay, y cómo se conectan las tablas entre sí. Una hora de mirar al principio te ahorra tres días de perseguir un número que salía mal porque una columna no era lo que creías. Todo lo que escribas hoy va a parar al primer fichero del proyecto, `src/01_explorar.py`: la etapa de reconocimiento del terreno.
Tienes cinco extractos en la carpeta compartida. Vale la pena entender qué papel juega cada uno antes de cargarlos, porque no son todos iguales: unos describen al cliente, otros su comportamiento en el tiempo, y uno define el resultado que quieres predecir.
- clientes — una fila por cliente. Su contrato, su cuota, su antigüedad, su provincia. Es la tabla «de sujeto»: el cliente es la unidad sobre la que todo lo demás se cuelga.
- consumo — varias filas por cliente, una por mes. Cuántos gigas y cuántos minutos gastó cada mes. Es una tabla «de comportamiento en el tiempo»: no basta un número, lo que anticipa una baja es la tendencia.
- tickets — una fila por contacto con soporte. Cuándo llamó un cliente y por qué. Otra tabla de comportamiento: la voz del descontento.
- bajas — una fila por cliente que se dio de baja en el trimestre. Es la tabla «de resultado»: define el target. Si un cliente está aquí, se fue.
- clientes_hoy — los clientes activos a día de hoy, los que siguen con FibraNova. Sobre estos hay que predecir el riesgo y construir la lista final. No llevan la columna de si se fueron, porque todavía no se sabe.
Todas se conectan por una sola columna: `cliente_id`. El consumo de un cliente, sus tickets y su baja (si la hubo) comparten el mismo identificador que su fila en `clientes`. Esa columna es el hilo que lo cose todo, y entender el mapa de cómo encajan es tan importante como los datos mismos. Míralo antes de cargar nada:
La herramienta para cargar y explorar estos ficheros es pandas, la librería de Python para trabajar con tablas de datos. Un fichero CSV se carga con `pd.read_csv()` y queda en memoria como un `DataFrame`: una tabla con filas y columnas, como una hoja de cálculo pero manejada por código. Para un primer vistazo hay cuatro preguntas que se hacen siempre, en este orden: ¿qué tamaño tiene? (`.shape` da filas y columnas), ¿qué pinta tienen los datos? (`.head()` enseña las primeras filas), ¿qué tipo ve pandas en cada columna? (`.info()` o `.dtypes`), y ¿cuántos huecos hay? (`.isnull().sum()`). Esas cuatro preguntas son el reconocimiento del terreno antes de la batalla.
Antes de abrir nada, hay un número que vas a calcular casi sin querer y que es el protagonista escondido de todo el caso: cuántos clientes se van de verdad. En el fichero de bajas hay 600 filas; en el de clientes, 12.000. Seiscientos de doce mil es un 5%. Apunta esa cifra con mayúsculas, porque va a condicionar todo lo que venga después. Cuando una de las dos cosas que quieres distinguir —se va, se queda— es tan rara, el problema cambia de naturaleza: se llama un problema «desbalanceado», y la mayoría de las métricas que se enseñan primero dejan de significar lo que crees. Hoy solo lo apuntas; el jueves verás por qué un 5% es capaz de tumbar un modelo que parecía perfecto.
## Contar filas no es contar clientes
Hay una trampa en la exploración que atrapa a casi todos los junior el primer mes, y quiero que la veas hoy para que no te pille. Cuando cargas un fichero y haces `len(df)`, obtienes el número de filas. Es tentador leer ese número como «cuántos clientes hay», pero una fila no siempre es un cliente distinto. En `consumo` hay seis filas por cliente, así que `len` da seis veces el número de clientes. En `tickets` hay una fila por cada contacto a soporte, así que un cliente quejica aparece diez veces. Contar filas te da el tamaño del fichero, no el tamaño de la realidad. Son dos números distintos, y confundirlos es la forma más silenciosa de dar una cifra inflada.
Por eso, junto a `len(df)`, un científico de datos mira siempre otra cosa al explorar: cuántos valores distintos hay en la columna que identifica cada cosa, con `df["cliente_id"].nunique()`. Si el número de filas y el de identificadores únicos no coinciden, es que una fila no es un cliente, y toca entender por qué antes de contar nada. «Este fichero tiene 72.000 filas» y «en este fichero hay 12.000 clientes, cada uno con seis meses» son dos frases muy distintas: la segunda es información, la primera es solo un tamaño. Cada vez que vayas a dar un «cuántos clientes» o «cuántos pedidos», párate medio segundo y pregúntate si estás contando filas o cosas. El día que interiorices que una fila no es automáticamente una cosa, dejarás de dar por accidente cifras que se pasan del doble.
No confundas «filas repetidas» con «cosas que se repiten legítimamente». Que un cliente aparezca en seis filas de consumo no es un duplicado: es que tiene seis meses de datos, y está bien. Un duplicado de verdad es el MISMO cliente metido dos veces en la tabla de clientes, o la misma fila entera repetida por un fallo de exportación. La diferencia importa: si eliminas «repetidos» sin mirar qué tabla tocas, puedes borrar datos reales creyendo que limpias. Antes de quitar duplicados, ten clarísimo qué debería ser único en esa tabla.
## Por qué hay varias filas de consumo por cliente
Hay una tabla que merece una pausa, porque su forma esconde la señal más interesante del caso: `consumo`. No tiene una fila por cliente, sino seis: una por cada uno de los últimos seis meses. Al principio molesta —te obliga a resumir esos seis meses en un número por cliente antes de poder modelar—, pero esa forma es justo lo que la hace valiosa. Un solo número de consumo te dice cuánto gasta un cliente; seis meses seguidos te dicen hacia dónde va, y la tendencia anticipa una baja mucho antes que el nivel. Un cliente que consume 20 gigas todos los meses está enganchado; uno que pasó de 20 a 15, a 10, a 4 se está desenganchando, aunque hoy todavía pague su cuota. Esa pendiente hacia abajo es una de las pistas legítimas más potentes que tendrás.
## La suciedad del core, que verás con tus propios ojos
En cuanto mires los tipos de la tabla de clientes te vas a llevar la primera sorpresa, y es la que te confirma Bea cuando le preguntas: «bienvenido/a a los extractos de Oracle». La cuota viene como texto, con el símbolo del euro pegado y la coma decimal española (`"29,90 €"`), así que pandas no la ve como un número. Las fechas vienen en tres formatos mezclados dentro de la misma columna. El tipo de contrato está escrito de media docena de maneras (`mensual`, `Mensual`, `MENSUAL`, `dos_anios`, `2 años`, `dos años`). Hoy no vas a limpiar nada: hoy solo te enteras de qué hay y lo apuntas. Mañana lo arreglas. Pero verlo con tus propios ojos, y no fiarte de que «los datos vendrán bien», es parte de la lección.
Una columna que es texto cuando debería ser un número no da error al cargarla: pandas la guarda como «object» (texto) tan tranquila. El problema aparece después, cuando intentas sumar o promediar y, o bien falla, o bien hace algo raro sin avisar. Por eso el `.dtypes` del primer día no es un trámite: es donde descubres qué columnas tendrás que limpiar antes de poder calcular con ellas.
## Una columna que nadie encargó
Explorando la tabla de clientes te encuentras una columna que no estaba en ninguna descripción: `gestion_retencion`, que vale 0 o 1. Se lo preguntas a Bea y te responde algo vago: «esa la metió el equipo de Lola, es un 1 cuando retención ya ha intervenido sobre ese cliente; para reporting les va bien, yo que tú la dejaría apuntada y seguiría». Y remata con su frasecita de siempre, esa a la que nadie hace caso: «ojito con meter según qué cosas al modelo». La dejas en la tabla sin pensártelo mucho —es una columna más, aparentemente— y sigues. Recuerda este momento. Dentro de tres días vas a volver a esta columna, y lo que descubras va a ser el centro de todo el caso.
Fíjate en un detalle que hoy pasa desapercibido y que el jueves será la prueba del delito: esa columna está en la tabla de clientes y en la de modelado, pero NO está en el fichero de clientes activos de hoy. Si lo piensas, tiene todo el sentido del mundo: `gestion_retencion` se enciende cuando retención ya ha actuado sobre un cliente, y sobre los que siguen activos todavía no ha actuado (porque no sabe que se van: averiguarlo es tu trabajo). Pero hoy ni te fijas en esa ausencia. La anotas en el diccionario con la pregunta pendiente de Bea —«¿en qué momento se rellena?»— y sigues explorando. Esa pregunta sin responder es la que, tres días después, va a desmontar un modelo que parecía perfecto.
Cierras el lunes con la sensación de que no has «hecho» gran cosa: no has entrenado nada, no has calculado una métrica, no tienes un número que enseñar. Y sin embargo has hecho el trabajo que más errores evita de toda la semana. Sabes cuántas tablas hay y qué papel juega cada una, sabes que todo cuelga de `cliente_id`, sabes que el 5% de los clientes se va, y tienes una lista de columnas sucias y una columna sospechosa apuntada. Mañana te ensucias las manos de verdad: dejas los datos en un estado en el que sumar, agrupar y comparar signifiquen algo, y construyes el target, la columna que define qué es exactamente «se fue».
Consejo de senior: cuando te encuentres una columna de la que nadie sabe explicarte el origen con precisión, no la metas al modelo «por si acaso». Apúntala con una pregunta pendiente: ¿en qué momento exacto se rellena esta columna? Si la respuesta es «cuando el cliente ya está de salida», acabas de encontrar una fuga de datos antes de que te explote. La mayoría de las fugas se cazan con esa única pregunta.
## El reconocimiento del terreno, con tus propios ojos
Antes de que te pongas con los ficheros, Raúl te deja un mensaje en el canal del equipo que resume el espíritu del día, y conviene que lo tengas presente, porque es la clase de disciplina que no se luce pero sostiene todo lo demás:
1Raúl 10:522Regla para hoy: no modeles nada todavia. Solo mira.3Abre cada extracto, cuenta filas, mira los tipos y apunta las rarezas.4Cuando sepas decirme "esta es la tabla que define el target, estas5describen al cliente, y estas columnas vienen sucias", has terminado.6Explorar bien hoy es lo que hace que el jueves los numeros salgan a7la primera. Nadie ve este trabajo, y es el que mas errores evita.
La exploración no se luce, pero es lo que sostiene todo lo que viene después.
Hay una tentación muy del primer día contra la que conviene prevenirte: creer que «los datos ya están» porque los ficheros se abren sin error. Que un CSV cargue no significa que esté listo para calcular. Hoy vas a abrir los cinco extractos y todos «funcionan», y sin embargo mañana vas a pasar media jornada limpiándolos. Cargar es abrir la caja; entender qué hay dentro y si se puede usar es otra cosa. El error de dar por buenos unos datos solo porque el ordenador no se ha quejado es de los que cuestan un modelo entero, porque entrenas sobre basura y el modelo no protesta: te da un número, y el número está mal de una forma silenciosa.
Y una advertencia que repiten todos los que llevan tiempo: no abras un CSV de trabajo directamente en una hoja de cálculo para «echarle un ojo rápido». Programas como Excel modifican cosas sin avisar: convierten identificadores con ceros delante en números y pierden el cero, reinterpretan las fechas según el idioma del sistema, y a veces truncan filas. Para el primer vistazo se usa pandas, que no toca el original. El `cliente_id` es sagrado —es la clave que cose todas las tablas—, y basta con que una herramienta te lo «arregle» por su cuenta para que un cruce deje de casar y pierdas filas sin enterarte.
Mientras exploras, Bea se pasa por el canal. Ya ha vivido esta película con cada junior que ha entrado, y te suelta el aviso que nadie del equipo acaba de tomarse en serio:
1Bea 13:182jaja bienvenido/a a los extractos de Oracle3la fecha viene en tres formatos, la cuota con el euro pegado y coma,4y el tipo de contrato cada uno escrito como le dio la gana5manana lo limpias, hoy solo enterate de que hay6y oye, ojito con las columnas que no sabes de donde salen7que alguna te esta chivando el futuro 👀
Bea ya sabe lo que te espera mañana. Y suelta, otra vez, lo de las columnas que chivan el futuro.
Esa última frase de Bea, la que nadie escucha, es la que vas a recordar el jueves. Hoy la apuntas sin darle importancia, como hiciste con la columna `gestion_retencion`. Pero fíjate en lo que te está diciendo con el oficio de quien ya se quemó: hay columnas en estos ficheros que parecen datos del cliente y en realidad son un reflejo de lo que quieres predecir. Reconocerlas es medio caso, y la única herramienta para hacerlo no es técnica, es una pregunta: ¿en qué momento se rellena este dato? Guárdala, porque es la que te va a salvar.
## El diccionario de datos que vas a dejar escrito
Recuerda lo que echabas de menos al abrir la carpeta: nadie te dijo qué era cada columna. Esa ausencia tiene nombre —falta un diccionario de datos— y tiene un remedio barato que, además, es la clase de gesto que hace que un junior deje huella en un equipo. Un diccionario de datos es el documento que dice, para cada columna, qué representa, en qué unidad viene y qué valores puede tener. En FibraNova no existe, y por eso Lola te ha pasado cinco cajas sin etiqueta interior. Mientras exploras, ve anotando lo que descubres de cada columna; al terminar tendrás algo que el equipo entero puede reutilizar, en vez de conocimiento que se muere en tu cabeza cuando cierras el portátil.
Así de sencillo puede ser el diccionario de la tabla de clientes, escrito con lo que ya sabes tras explorar: `cliente_id` es la clave, un entero único que cose todas las tablas. `antiguedad_meses` son los meses que lleva el cliente, y viene como decimal porque tiene algún hueco. `tipo_contrato` es texto sucio: `mensual`, `Mensual`, `MENSUAL`, `dos años`, `2 años` son dos categorías escritas de muchas formas. `cuota_mensual` es el precio, disfrazado de texto con el euro pegado. `gestion_retencion` es 0/1 y nadie sabe explicarla del todo: la gran pregunta pendiente. No es un documento solemne; son cuatro líneas por fichero en un bloc de notas, y te sirve tres veces: hoy para no repetir exploraciones, el jueves para defender tus números, y dentro de un mes cuando llegue otra tanda de extractos con la misma suciedad.
Consejo de senior: el mejor momento para escribir el diccionario de datos es mientras exploras, no después, porque después no llega nunca. Cada vez que descubras qué es una columna o le veas una rareza, anótalo en el acto. Y para cada columna que vayas a usar, añade la pregunta que importa en este oficio: ¿en qué momento se rellena? Esa última columna del diccionario es tu primera defensa contra la fuga de datos.
## comentarios
Reporta erratas, ayuda a otros o comparte tu opinión. Sé constructivo.
Inicia sesión para comentar y responder.
cargando comentarios...
Regístrate para guardar tu progreso.