lección 3
Martes: limpiar, agregar la serie y fabricar las features
Limpiar y agregar los avisos a una serie por zona, fecha y hora, cazar los huecos, y fabricar los lags, las medias móviles y el calendario.
⏱ 55 min
## Martes, 10:00. El día menos glamuroso y el más importante
Ayer dibujaste el mapa; hoy toca el trabajo que ocupa la mayor parte del tiempo de un científico de datos y que nadie enseña en los cursos: dejar la serie en condiciones de que un modelo la pueda usar. No es glamuroso y no sale en las fotos, pero es donde se gana o se pierde el proyecto. Un modelo entrenado sobre una serie sucia o mal alineada aprende la suciedad, da igual lo bueno que sea el algoritmo. Hoy tienes tres trabajos encadenados: limpiar los avisos, agregarlos a una serie por zona/fecha/hora, y fabricar las pistas temporales. Al terminar tendrás la tabla con la que de verdad vas a modelar.
Conviene tener claro el orden desde el principio, porque hacerlo al revés estropea el resultado. Primero se limpia, después se agrega, y solo al final se fabrican las features. Si construyeras los lags antes de ordenar y limpiar la serie, estarías mirando "la hora anterior" de una fila que en realidad no es la anterior, y el lag quedaría mal alineado. Y si agregaras sin haber reconstruido el índice horario, un hueco (una hora sin fila) haría que el lag de una fila saltara por encima del hueco y cogiera la demanda de hace tres horas creyendo que es la de hace una. El orden no es una manía: cambia los números.
## Lo primero y lo más traicionero: las tres formas de fecha
La marca de tiempo es la columna de la que depende toda la serie, así que si se parsea mal, todo lo demás se derrumba. Viene en tres formatos mezclados. Los dos primeros los resuelve pandas con una sola llamada: su función de parseo de fechas acepta un modo que detecta el formato de cada fila por su cuenta, y con la opción de "día primero" entiende tanto el ISO ("2023-07-26 22:26") como el español de día primero ("27/03/2023 22:17"). El problema es el tercero: "19 ago 2023 08:09", con el mes abreviado en español. Pandas no sabe que "ago" es agosto —espera los meses en inglés—, así que esa fila revienta el parseo entero si la metes en el mismo saco.
La solución honesta es tratar ese formato aparte: detectar las filas que llevan un mes en letra, sustituir la abreviatura española por el número de mes ("ago" por "08", "mar" por "03", y así) y solo entonces parsear. No hay un atajo mágico que lo haga todo de una vez, y por eso este es un buen sitio para que escribas tú la función: se te da la firma y el diccionario de meses, y tú implementas la conversión. El andamiaje es más fino que en tus casos anteriores a propósito: ya tienes tres encargos encima, y a estas alturas se espera que escribas una función de limpieza a partir de su diseño, no que rellenes un hueco de una línea.
No intentes parsear las tres formas con una sola llamada en el modo automático de pandas. La fila con el mes en español ("19 ago 2023") hace que la llamada falle con un error que menciona "ago", y es un fallo silencioso de los peores: o revienta todo el parseo, o —según cómo lo montes— convierte en nulo una de cada tres fechas sin avisar, y pierdes un tercio de la serie sin enterarte. El mes en español se convierte a número ANTES de parsear. Es el gran defecto a evitar del día, y por eso lo escribes tú.
## Después: zonas, duplicados y la serie
Con las fechas en condiciones, el resto de la limpieza es más llevadero. La zona se normaliza quitando los espacios de los lados y pasándola a minúsculas, y mapeando cada variante a su zona canónica: "zgz", "zaragoza", "zaragoza centro" van todas a "Zaragoza", y así con las cuatro. Los duplicados se quitan con una deduplicación por aviso_id —y solo por aviso_id, nunca por timestamp, por lo que viste ayer—. Y entonces llega la agregación: se agrupa por zona, fecha y hora, y se cuenta cuántos avisos cae en cada grupo. Ese recuento es n_servicios, el target. La serie empieza a existir.
Pero falta un paso que no había en tus casos anteriores, y es propio de las series: reconstruir el índice horario. Cuando una hora no tiene ningún aviso —una madrugada tranquila, o un rato en que el CAU se cayó—, no hay fila en la serie agregada, simplemente no existe. Y eso NO es lo mismo que n_servicios igual a cero. El problema es que un hueco envenena los lags: si falta la hora de las 4 de la madrugada, el lag de "hace una hora" de las 5 cogería la demanda de las 3, creyendo que es la de las 4. Por eso hay que reconstruir el calendario horario completo por zona —todas las horas de principio a fin, estén o no— y así ver exactamente qué horas faltan antes de calcular ninguna pista.
## El corazón del caso: los lags, las medias móviles y el calendario
Y ahora, lo que hace posible el forecasting sin ARIMA: convertir la serie en una tabla de pistas. La idea es que, por cada fila (una zona, una hora), se añaden columnas con información que el modelo habría conocido en ese momento. Los lags son la demanda de hace un rato: el lag de 1 hora, el de 24 horas (ayer a esta hora) y el de 7 días (el mismo día de la semana pasada). Se calculan desplazando la columna de demanda hacia abajo dentro de cada zona: desplazar una posición da el valor de la hora anterior, veinticuatro posiciones el de ayer, ciento sesenta y ocho el de hace una semana. Las medias móviles son el promedio de las últimas horas: la de las últimas 3 y la de las últimas 24, que suavizan el ruido y captan la tendencia reciente. Y el calendario sale de la propia marca de tiempo: la hora, el día de la semana, el mes, y si es festivo.
Aquí está el defecto sutil que tienes que cazar y corregir hoy, y es de higiene, no el gran insight del caso. Una media móvil, tal como se escribe de forma natural, incluye la propia hora en el promedio: la media de las últimas 3 horas calculada sobre las horas 8, 9 y 10 incluye la demanda de las 10, que es justo la que querrías predecir. Eso es una fuga: le estás dando al modelo, como pista, un trocito de la respuesta. La corrección es desplazar la media una posición hacia atrás, de modo que la media "de las últimas 3 horas" de la fila de las 10 se calcule sobre las 7, 8 y 9, sin tocar las 10. Es una fuga pequeña y local, se corrige en una línea, y no tiene nada que ver con el problema del jueves —ese es de cómo se parte la serie, no de las features—.
Consejo de senior: la regla para no colar fugas en las features de una serie es sencilla de decir y fácil de olvidar: toda pista que uses para predecir la hora H tiene que calcularse SOLO con información anterior a H. Un lag ya cumple eso por naturaleza (mira hacia atrás). Una media móvil no, a menos que la desplaces una posición. Cuando construyas cualquier feature nueva, hazte la pregunta: ¿esto incluye algo de la hora que estoy prediciendo? Si la respuesta es sí, tienes una fuga.
Al terminar de construir los lags y las medias, las primeras filas de cada zona se quedan con huecos: la primera hora no tiene "hace una hora", la primera semana no tiene "hace 7 días". Esas filas con pistas incompletas se descartan, porque el modelo no puede aprender de una pista que no existe. Lo que queda, limpio y con todas sus pistas, es la tabla de modelado: el entregable del martes.
Trabajas con los CSV de CoberturaYa en la carpeta datos/: servicios (los avisos crudos), zonas, meteo y calendario_festivos. Hoy construyes la serie a partir de ellos. Para los ejercicios de modelado de los próximos días tendrás además serie_modelo.csv, la tabla ya construida, para partir todos del mismo punto.
volver a la visión del caso y descargar los datasets## 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.