El segon gran projecte seqüencial de TecnoMarket no treballa amb paraules sinó amb números datats: les vendes diàries. Predir la demanda dels propers dies decideix quant estoc demanar, quant personal reforçar a logística i quines promocions llançar — equivocar-se costa diners en totes dues direccions (ruptures d'estoc o magatzems plens). En aquesta lliçó convertiràs la predicció de demanda en un problema d'aprenentatge supervisat mitjançant finestres lliscants, aprendràs a normalitzar sense cometre l'error clàssic de la fuga de dades, construiràs l'imprescindible baseline ingenu, entrenaràs una LSTM sobre una sèrie sintètica de vendes de TecnoMarket (amb estacionalitat setmanal i pics tipus Black Friday) i avaluaràs honestament en euros/unitats reals. Acabarem amb la predicció multipas i els seus riscos, i amb el criteri per decidir quan una LSTM compensa davant dels mètodes clàssics.
Contingut
- La demanda de TecnoMarket com a sèrie temporal
- Components d'una sèrie: tendència, estacionalitat, soroll
- Finestres lliscants: de sèrie a dataset supervisat
- Normalització sense fuga de dades
- El baseline ingenu: la vara de mesurar obligatòria
- LSTM sobre les vendes diàries de TecnoMarket
- Avaluació en unitats reals
- Predicció multipas: iterativa vs. directa
- Quan compensa una LSTM davant dels mètodes clàssics?
La demanda de TecnoMarket com a sèrie temporal
Una sèrie temporal és una seqüència d'observacions preses a intervals regulars: les unitats venudes cada dia, les comandes per hora, les visites per setmana. Es diferencia de les seqüències de text de 04-03 en tres aspectes pràctics:
- Els valors són continus (no índexs de vocabulari): no hi ha Embedding; el problema final és de regressió (MSE/MAE de 02-04), no de classificació.
- El "futur" existeix de debò: el model es farà servir per predir valors que encara no han passat, cosa que imposa regles estrictes sobre quines dades pot veure durant l'entrenament (i descarta
Bidirectional, com vam avisar a 04-02). - El temps té estructura de calendari: els dilluns s'assemblen als dilluns, el novembre no s'assembla a l'agost.
Components d'una sèrie: tendència, estacionalitat, soroll
Gairebé qualsevol sèrie de negoci es pot pensar com la suma de tres components:
| Component | Què és | A les vendes de TecnoMarket |
|---|---|---|
| Tendència | Direcció de fons a llarg termini | Creixement sostingut: la botiga guanya clients cada mes |
| Estacionalitat | Patró que es repeteix amb un període fix | Setmanal: pics el cap de setmana; anual: Black Friday, Nadal, tornada a l'escola |
| Soroll | Variació irregular no explicable | Un dia de pluja, un tuit viral, pur atzar |
Generem una sèrie sintètica de 2 anys de vendes diàries amb aquests tres components més esdeveniments tipus Black Friday. Treballar amb dades sintètiques té un avantatge didàctic: coneixem la veritat que el model ha de descobrir.
import numpy as np
rng = np.random.default_rng(7)
DIES = 730 # 2 anys
t = np.arange(DIES)
tendencia = 200 + 0.15 * t # de ~200 a ~310 unitats/dia
dia_setmana = t % 7 # 0 = dilluns ... 6 = diumenge
estacional = np.where(dia_setmana >= 5, 60, 0) + 10 * np.sin(2*np.pi*t/7)
soroll = rng.normal(0, 15, DIES) # variació aleatòria (σ = 15)
vendes = tendencia + estacional + soroll
# Pics tipus Black Friday: dies 328 i 693 (finals de novembre de cada any)
for bf in (328, 693):
vendes[bf-3:bf+2] *= rng.uniform(2.2, 2.8) # uns quants dies al x2.5
vendes = np.round(np.clip(vendes, 0, None)) # unitats enteres, no negatives
print(vendes[:10]) # p. ex. [214. 199. 217. 208. 224. 288. 273. 216. 204. 223.]Dibuixa la sèrie (plt.plot(vendes)) i veuràs les tres capes: el pendent suau, el dibuix setmanal en dent de serra i dues agulles espectaculars als Black Friday. La pregunta del mòdul: pot una LSTM aprendre tot això només mirant els valors passats?
Finestres lliscants: de sèrie a dataset supervisat
Una xarxa supervisada necessita parells (entrada X, objectiu y), però una sèrie és una sola tira de números. El truc universal és la finestra lliscant: fer servir els últims V valors com a entrada i el valor següent com a objectiu, i lliscar la finestra al llarg de tota la sèrie.
Exemple numèric amb la minisèrie [10, 12, 15, 14, 18, 21, 19] i finestra V = 3:
| Finestra (X) | Objectiu (y) |
|---|---|
| [10, 12, 15] | 14 |
| [12, 15, 14] | 18 |
| [15, 14, 18] | 21 |
| [14, 18, 21] | 19 |
De 7 valors en surten 7 − 3 = 4 exemples supervisats. Cada fila és una pregunta d'examen: "vistos aquests 3 dies, què va passar l'endemà?". És una tasca many-to-one (04-01): molts passos entren, un valor surt.
def crear_finestres(serie, finestra):
"""Converteix una sèrie 1D en (X, y) supervisat amb finestra lliscant."""
X, y = [], []
for i in range(len(serie) - finestra):
X.append(serie[i : i + finestra]) # V valors consecutius
y.append(serie[i + finestra]) # el valor immediatament posterior
return np.array(X), np.array(y)
FINESTRA = 28 # 4 setmanes: prou per captar el patró setmanal unes quantes vegadesTriar V = 28 no és casual: la finestra ha de ser més llarga que el període estacional que vols captar (aquí, 7 dies) — idealment contenint-lo diverses vegades. Amb V = 3, el model no podria "veure" mai que avui és dissabte comparant-lo amb el dissabte anterior.
Normalització sense fuga de dades
Com amb els píxels de MNIST (els vam dividir entre 255 a 02-05), les xarxes entrenen millor amb entrades en rangs petits; unes vendes entre 200 i 800 convé escalar-les. Però en sèries temporals aguaita l'error clàssic: normalitzar fent servir estadístiques de TOTA la sèrie.
Per què és greu? El màxim de la sèrie completa inclou els Black Friday futurs. Si escales amb ell, cada dada d'entrenament porta incrustada una pista sobre el futur ("les vendes arribaran a X") que en producció no tindràs. És fuga de dades (data leakage): l'avaluació sortirà optimista i el model decebrà al món real. És el mateix principi que l'adapt() només-amb-train de 04-03.
La regla d'or té dues parts:
- Divideix primer, i per temps: en sèries temporals MAI no es remena per dividir train/test — el test ha de ser el tram final (el "futur" respecte al train), perquè així es farà servir el model.
- Ajusta l'scaler només amb el train i aplica'l (sense reajustar) al test.
# 1. Divisió temporal: primer 80 % per entrenar, últim 20 % per avaluar
tall = int(DIES * 0.8) # dia 584
serie_train, serie_test = vendes[:tall], vendes[tall:]
# 2. Estadístiques NOMÉS del train
mitjana, desv = serie_train.mean(), serie_train.std()
train_norm = (serie_train - mitjana) / desv # el test s'escala amb les MATEIXES
test_norm = (serie_test - mitjana) / desv # mitjana i desv del train
# 3. Finestres sobre cada tram ja normalitzat
X_train, y_train = crear_finestres(train_norm, FINESTRA)
X_test, y_test = crear_finestres(test_norm, FINESTRA)
# 4. Tercer eix per a la LSTM: (mostres, passos, característiques)
X_train = X_train[..., np.newaxis]
X_test = X_test[..., np.newaxis]
print(X_train.shape, X_test.shape) # (556, 28, 1) (118, 28, 1)Guarda mitjana i desv: són part del model. En producció, cada predicció es desnormalitza amb elles (pred * desv + mitjana) per tornar a unitats reals.
El baseline ingenu: la vara de mesurar obligatòria
Abans d'entrenar res de sofisticat, calcula què aconseguiria una regla trivial. En sèries temporals, dos baselines canònics:
- Ingenu (naive): "demà vendré el mateix que avui" →
ŷ_t = y_{t-1}. - Ingenu estacional: "demà vendré el mateix que fa una setmana" →
ŷ_t = y_{t-7}. En una sèrie amb un patró setmanal fort, és sorprenentment difícil de batre.
# Baselines avaluats sobre el mateix tram que avaluarà la LSTM
reals = serie_test[FINESTRA:] # objectius en unitats reals
mae_naive = np.abs(reals - serie_test[FINESTRA-1:-1]).mean() # ahir
mae_estacional = np.abs(reals - serie_test[FINESTRA-7:-7]).mean() # fa 7 dies
print(f"MAE naive: {mae_naive:.1f} u. | MAE estacional: {mae_estacional:.1f} u.")
# Típic amb aquesta sèrie: naive ≈ 35 u., estacional ≈ 17 u.Aquesta és la regla més important de la lliçó: un model de deep learning que no bat el baseline estacional no aporta res, per moltes capes que tingui. El baseline és a les sèries el que el "50 % d'atzar" era a IMDB: el terra honest de comparació.
LSTM sobre les vendes diàries de TecnoMarket
Amb les dades en forma (mostres, 28, 1), el model és l'aplicació directa de 04-02:
from tensorflow import keras
from tensorflow.keras import layers
model = keras.Sequential([
layers.Input(shape=(FINESTRA, 1)),
layers.LSTM(64, return_sequences=True), # primera capa: passa la seqüència sencera
layers.LSTM(32), # segona capa: resumeix en 32 números
layers.Dense(1) # regressió: sense activació (02-02)
])
model.compile(optimizer="adam", loss="mse", metrics=["mae"])
historial = model.fit(X_train, y_train,
epochs=40, batch_size=32,
validation_split=0.15, # l'ÚLTIM 15 % del train (Keras no remena aquí)
shuffle=True, # remenar FINESTRES ja construïdes sí que és vàlid
verbose=0)Un matís subtil i important: un cop construïdes les finestres, sí que es poden remenar entre elles per entrenar (cada finestra és un exemple autocontingut); el que no es remena mai és la sèrie abans de dividir train/test.
Avaluació en unitats reals
El MAE que reporta Keras està en unitats normalitzades — ningú a la reunió de logística no entén "0.21". Desnormalitza:
pred_norm = model.predict(X_test, verbose=0).ravel()
pred = pred_norm * desv + mitjana # de tornada a unitats/dia
reals = y_test * desv + mitjana
mae_lstm = np.abs(reals - pred).mean()
print(f"MAE LSTM: {mae_lstm:.1f} unitats/dia")
print(f"vs. naive: {mae_naive:.1f} | vs. estacional: {mae_estacional:.1f}")
# Resultat típic: LSTM ≈ 13-15 u. — bat l'estacional (~17), i de llarg el naive (~35)Com llegir-ho en clau de negoci:
- Un MAE de ~14 unitats sobre vendes mitjanes de ~300 és un error relatiu del ~5 %: prou per dimensionar l'estoc amb un marge raonable.
- La millora respecte al baseline estacional (~17 → ~14) sembla modesta, però és on viu el valor: el patró setmanal ja el donava gratis el baseline; la LSTM hi afegeix la tendència i les interaccions. Grafica
predcontrareals: veuràs que segueix bé la dent de serra setmanal i el pendent. - I els Black Friday? Si cauen al tram de test, la LSTM els suavitzarà o hi arribarà tard: un pic anual apareix 1-2 vegades en tot l'entrenament, insuficient per aprendre'l només de la sèrie. A la pràctica això es resol afegint característiques de calendari com a entrades addicionals (dia de la setmana, "és campanya de Black Friday": el tercer eix d'
Xpassa d'1 a diverses característiques per pas) — el format(mostres, passos, característiques)de 04-01 estava preparat per a això des del principi.
Predicció multipas: iterativa vs. directa
Logística no vol només demà: vol els propers 7 dies. Dues estratègies:
| Estratègia | Com funciona | Avantatges | Riscos |
|---|---|---|---|
| Iterativa | Prediues t+1, fiques aquesta predicció a la finestra i prediues t+2, i així 7 vegades | Un sol model; horitzó flexible | Acumulació d'error: cada pas es recolza en prediccions, no en dades; l'error creix amb l'horitzó |
| Directa | Un model entrenat per predir el vector de 7 valors de cop (Dense(7)), o un model per horitzó |
Cada horitzó s'optimitza amb dades reals; sense realimentació d'errors | Més entrenament; no reutilitza la predicció de t+1 per a t+2 |
def predir_iteratiu(model, ultima_finestra_norm, passos):
"""Predicció multipas iterativa: realimenta cada predicció."""
finestra = ultima_finestra_norm.copy() # (FINESTRA,)
futur = []
for _ in range(passos):
p = model.predict(finestra[np.newaxis, :, np.newaxis], verbose=0)[0, 0]
futur.append(p)
finestra = np.append(finestra[1:], p) # llisca: hi entra la predicció
return np.array(futur) * desv + mitjana # a unitats reals
print(predir_iteratiu(model, test_norm[-FINESTRA:], passos=7))El risc de la iterativa s'entén amb una imatge: és el joc del telèfon trencat — cada predicció hereta i amplifica els errors de l'anterior. Per a 2-3 passos sol servir; per a 14-30 dies, l'estratègia directa (o models clàssics d'estacionalitat explícita) sol ser més segura. Avalua sempre el MAE per horitzó (quant fallo a t+1?, i a t+7?): veuràs la corba de degradació amb els teus propis ulls.
Quan compensa una LSTM davant dels mètodes clàssics?
El deep learning no és sempre la resposta en sèries temporals. Els mètodes estadístics clàssics (mitjanes mòbils, suavitzat exponencial, ARIMA/SARIMA) fa dècades que prediuen demanda:
| Situació | Millor aposta inicial |
|---|---|
| Una sola sèrie, curta (< 1-2 anys), patró regular | Clàssics (SARIMA, suavitzat exponencial): més simples, interpretables i sovint igual de precisos |
| Centenars/milers de sèries relacionades (una per producte de TecnoMarket) | LSTM o altres models de DL: un sol model global aprèn patrons compartits entre productes |
| Moltes variables externes (preu, promocions, calendari, meteo) | DL: incorpora característiques per pas amb naturalitat |
| Relacions no lineals complexes (promoció × dia × categoria) | DL |
| Necessites explicar la predicció al negoci | Clàssics (o com a mínim, acompanya el DL d'un baseline clar) |
| Dades molt escasses o molt sorolloses | Clàssics o baseline estacional; el DL sobreajustarà |
L'honestedat metodològica d'aquesta lliçó —baseline primer, divisió temporal, avaluació en unitats reals— val per a tots dos mons, i és el que distingeix un prototip seriós d'una demo.
Errors Comuns i Consells
- Ajustar l'scaler amb tota la sèrie. L'error clàssic de fuga de dades: el test queda contaminat amb estadístiques del futur i les mètriques s'inflen.
fitde l'scaler només amb train, sempre. - Dividir train/test remenant. En sèries, el test ha de ser el tram temporal final. Si remenes abans de dividir, el model "entrena amb el futur" i l'avaluació és ficció. (Remenar les finestres ja construïdes del train, en canvi, és correcte.)
- No calcular el baseline. Sense baseline no saps si el teu MAE de 14 és bo o vergonyós. L'ingenu estacional es calcula en una línia i és la primera xifra que hauries d'apuntar.
- Finestra més curta que l'estacionalitat. Amb
V < 7en una sèrie setmanal, el model no pot comparar "avui" amb "fa una setmana". Finestra ≥ 2-4 períodes estacionals. - Reportar l'error en unitats normalitzades. "MAE 0.21" no informa cap decisió. Desnormalitza i parla en unitats/dia (o euros): és el que el negoci pot jutjar.
- Refiar-se de la predicció multipas iterativa a horitzons llargs. L'error s'acumula pas a pas. Mesura el MAE per horitzó i trunca on deixi de ser útil.
Exercicis
-
Finestres a mà: amb la sèrie
[100, 110, 105, 120, 125, 118, 130]iV = 4, escriu totes les parelles (X, y) resultants. Quants exemples supervisats obtens d'una sèrie deNvalors amb finestraV? -
Caça la fuga: aquest codi té dos errors de metodologia — troba'ls i corregeix-los:
mitjana, desv = vendes.mean(), vendes.std() norm = (vendes - mitjana) / desv X, y = crear_finestres(norm, 28) X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, shuffle=True) -
Baseline i veredicte: al tram de test, el baseline estacional aconsegueix un MAE de 17.2 unitats i la teva LSTM 16.8. L'entrenament de la LSTM triga 20 minuts i el baseline és una línia de codi. Què recomanaries a l'equip de TecnoMarket i què provaries abans de descartar la LSTM?
Solucions
- Parelles:
([100,110,105,120] → 125),([110,105,120,125] → 118),([105,120,125,118] → 130). En general,N − Vexemples: aquí7 − 4 = 3. - Error 1: l'scaler s'ajusta amb tota la sèrie (
vendes.mean()) — s'ha de calcular només sobre el tram de train. Error 2:train_test_splitambshuffle=Trueremena abans de dividir, barrejant futur dins el train — la divisió ha de ser temporal (primer 80 % / últim 20 %) i fer-se abans de crear les finestres (si es fa després, a més, hi ha finestres que creuen la frontera train/test). Versió correcta: dividir la sèrie per índex temporal, normalitzar amb estadístiques del train, i construir les finestres dins de cada tram. - Amb una millora de 0.4 unitats (~2 %), la LSTM amb prou feines justifica el seu cost: recomanaria desplegar el baseline estacional avui mateix com a sistema de referència. Abans de descartar la LSTM provaria: afegir característiques de calendari (dia de la setmana, festius, campanyes — on el DL pot marcar una diferència real), ampliar la finestra, i entrenar un model global sobre molts productes alhora en lloc d'una sola sèrie. Si després d'això la millora continua sent marginal, el mètode simple guanya: és la conclusió honesta que permet el baseline.
Conclusió
Has convertit la predicció de demanda de TecnoMarket en un problema de deep learning de principi a fi: descompondre la sèrie (tendència + estacionalitat + soroll), transformar-la en dataset supervisat amb finestres lliscants, normalitzar sense fuga de dades (scaler ajustat només amb train, divisió temporal sense remenar), exigir un baseline ingenu abans de celebrar res, entrenar una LSTM apilada que bat aquest baseline, i avaluar en unitats que el negoci entén — més la predicció multipas amb la seva acumulació d'error i el criteri per triar entre LSTM i mètodes clàssics. Amb això es tanca el mòdul de xarxes recurrents: ja saps modelar l'ordre, la memòria i el temps, tant en text com en números. El mòdul següent canvia de pregunta: en lloc de classificar o predir, pot una xarxa crear — generar imatges promocionals, comprimir representacions, aprofitar models preentrenats? Comencem amb les xarxes generatives adversàries (GAN).
Curs de Deep Learning
Mòdul 1: Introducció al Deep Learning
- Què és el Deep Learning?
- Història i evolució del Deep Learning
- Aplicacions del Deep Learning
- Conceptes bàsics de xarxes neuronals
- Preparació de l'entorn de treball
Mòdul 2: Fonaments de Xarxes Neuronals
- Perceptró i Perceptró Multicapa
- Funció d'activació
- Propagació cap endavant i cap enrere
- Optimització i funció de pèrdua
- La teva primera xarxa neuronal completa
Mòdul 3: Xarxes Neuronals Convolucionals (CNN)
- Introducció a les CNN
- Capes convolucionals i de pooling
- Arquitectures populars de CNN
- Aplicacions de CNN en reconeixement d'imatges
Mòdul 4: Xarxes Neuronals Recurrents (RNN)
- Introducció a les RNN
- LSTM i GRU
- Aplicacions de RNN en processament del llenguatge natural
- Seqüències i sèries temporals
Mòdul 5: Tècniques Avançades en Deep Learning
- Xarxes Generatives Adversàries (GAN)
- Autoencoders
- Transfer Learning
- Regularització i tècniques de millora
- Mecanismes d'atenció i Transformers
Mòdul 6: Eines i Frameworks
- Introducció a TensorFlow
- Introducció a PyTorch
- Comparació de frameworks
- Entorns de desenvolupament i recursos addicionals
- Desar, carregar i desplegar models
Mòdul 7: Projectes Pràctics
- Classificació d'imatges amb CNN
- Generació de text amb RNN
- Detecció d'anomalies amb Autoencoders
- Creació d'una GAN per a generació d'imatges
- Fine-tuning d'un model preentrenat
