|
3 weeks ago | |
---|---|---|
.. | ||
solution | 3 weeks ago | |
working | 3 weeks ago | |
README.md | 3 weeks ago | |
assignment.md | 3 weeks ago |
README.md
Tidsserieprognoser med ARIMA
I forrige leksjon lærte du litt om tidsserieprognoser og lastet inn et datasett som viser svingninger i elektrisk belastning over en tidsperiode.
🎥 Klikk på bildet ovenfor for en video: En kort introduksjon til ARIMA-modeller. Eksempelet er gjort i R, men konseptene er universelle.
Quiz før leksjonen
Introduksjon
I denne leksjonen vil du oppdage en spesifikk måte å bygge modeller på med ARIMA: AutoRegressive Integrated Moving Average. ARIMA-modeller er spesielt godt egnet til å tilpasse data som viser ikke-stasjonaritet.
Generelle konsepter
For å kunne jobbe med ARIMA, er det noen konsepter du må kjenne til:
-
🎓 Stasjonaritet. Fra et statistisk perspektiv refererer stasjonaritet til data der distribusjonen ikke endres når den forskyves i tid. Ikke-stasjonære data viser derimot svingninger på grunn av trender som må transformeres for å kunne analyseres. Sesongvariasjoner, for eksempel, kan introdusere svingninger i data og kan elimineres ved en prosess kalt 'sesongdifferensiering'.
-
🎓 Differensiering. Differensiering av data, igjen fra et statistisk perspektiv, refererer til prosessen med å transformere ikke-stasjonære data for å gjøre dem stasjonære ved å fjerne deres ikke-konstante trend. "Differensiering fjerner endringene i nivået til en tidsserie, eliminerer trend og sesongvariasjoner og stabiliserer dermed gjennomsnittet av tidsserien." Paper av Shixiong et al
ARIMA i konteksten av tidsserier
La oss pakke ut delene av ARIMA for bedre å forstå hvordan det hjelper oss med å modellere tidsserier og lage prognoser basert på dem.
-
AR - for AutoRegressiv. Autoregressive modeller, som navnet antyder, ser 'tilbake' i tid for å analysere tidligere verdier i dataene dine og gjøre antakelser om dem. Disse tidligere verdiene kalles 'lags'. Et eksempel kan være data som viser månedlige salg av blyanter. Hver måneds salgssum vil bli betraktet som en 'utviklende variabel' i datasettet. Denne modellen bygges ved at "den utviklende variabelen av interesse regresseres på sine egne forsinkede (dvs. tidligere) verdier." wikipedia
-
I - for Integrert. I motsetning til de lignende 'ARMA'-modellene, refererer 'I' i ARIMA til dens integrerte aspekt. Dataene blir 'integrert' når differensieringstrinn brukes for å eliminere ikke-stasjonaritet.
-
MA - for Glidende Gjennomsnitt. Det glidende gjennomsnittet i denne modellen refererer til utgangsvariabelen som bestemmes ved å observere nåværende og tidligere verdier av lags.
Kort oppsummert: ARIMA brukes til å lage en modell som passer så tett som mulig til den spesielle formen for tidsseriedata.
Øvelse - bygg en ARIMA-modell
Åpne /working-mappen i denne leksjonen og finn filen notebook.ipynb.
-
Kjør notebooken for å laste inn Python-biblioteket
statsmodels
; du trenger dette for ARIMA-modeller. -
Last inn nødvendige biblioteker.
-
Deretter laster du inn flere biblioteker som er nyttige for å plotte data:
import os import warnings import matplotlib.pyplot as plt import numpy as np import pandas as pd import datetime as dt import math from pandas.plotting import autocorrelation_plot from statsmodels.tsa.statespace.sarimax import SARIMAX from sklearn.preprocessing import MinMaxScaler from common.utils import load_data, mape from IPython.display import Image %matplotlib inline pd.options.display.float_format = '{:,.2f}'.format np.set_printoptions(precision=2) warnings.filterwarnings("ignore") # specify to ignore warning messages
-
Last inn data fra
/data/energy.csv
-filen til en Pandas dataframe og ta en titt:energy = load_data('./data')[['load']] energy.head(10)
-
Plot all tilgjengelig energidata fra januar 2012 til desember 2014. Det bør ikke være noen overraskelser, da vi så disse dataene i forrige leksjon:
energy.plot(y='load', subplots=True, figsize=(15, 8), fontsize=12) plt.xlabel('timestamp', fontsize=12) plt.ylabel('load', fontsize=12) plt.show()
Nå, la oss bygge en modell!
Opprett trenings- og testdatasett
Nå er dataene dine lastet inn, så du kan dele dem opp i trenings- og testsett. Du vil trene modellen din på treningssettet. Som vanlig, etter at modellen er ferdig trent, vil du evaluere nøyaktigheten ved hjelp av testsettet. Du må sørge for at testsettet dekker en senere tidsperiode enn treningssettet for å sikre at modellen ikke får informasjon fra fremtidige tidsperioder.
-
Tildel en to-måneders periode fra 1. september til 31. oktober 2014 til treningssettet. Testsettet vil inkludere to-måneders perioden fra 1. november til 31. desember 2014:
train_start_dt = '2014-11-01 00:00:00' test_start_dt = '2014-12-30 00:00:00'
Siden disse dataene reflekterer det daglige energiforbruket, er det et sterkt sesongmønster, men forbruket er mest likt forbruket i mer nylige dager.
-
Visualiser forskjellene:
energy[(energy.index < test_start_dt) & (energy.index >= train_start_dt)][['load']].rename(columns={'load':'train'}) \ .join(energy[test_start_dt:][['load']].rename(columns={'load':'test'}), how='outer') \ .plot(y=['train', 'test'], figsize=(15, 8), fontsize=12) plt.xlabel('timestamp', fontsize=12) plt.ylabel('load', fontsize=12) plt.show()
Derfor bør det være tilstrekkelig å bruke et relativt lite tidsvindu for å trene dataene.
Merk: Siden funksjonen vi bruker for å tilpasse ARIMA-modellen bruker in-sample validering under tilpasning, vil vi utelate valideringsdata.
Forbered dataene for trening
Nå må du forberede dataene for trening ved å filtrere og skalere dem. Filtrer datasettet ditt for kun å inkludere de nødvendige tidsperiodene og kolonnene, og skaler dataene for å sikre at de projiseres i intervallet 0,1.
-
Filtrer det originale datasettet for kun å inkludere de nevnte tidsperiodene per sett og kun inkludere den nødvendige kolonnen 'load' pluss datoen:
train = energy.copy()[(energy.index >= train_start_dt) & (energy.index < test_start_dt)][['load']] test = energy.copy()[energy.index >= test_start_dt][['load']] print('Training data shape: ', train.shape) print('Test data shape: ', test.shape)
Du kan se formen på dataene:
Training data shape: (1416, 1) Test data shape: (48, 1)
-
Skaler dataene til å være i området (0, 1).
scaler = MinMaxScaler() train['load'] = scaler.fit_transform(train) train.head(10)
-
Visualiser de originale vs. skalerte dataene:
energy[(energy.index >= train_start_dt) & (energy.index < test_start_dt)][['load']].rename(columns={'load':'original load'}).plot.hist(bins=100, fontsize=12) train.rename(columns={'load':'scaled load'}).plot.hist(bins=100, fontsize=12) plt.show()
De originale dataene
De skalerte dataene
-
Nå som du har kalibrert de skalerte dataene, kan du skalere testdataene:
test['load'] = scaler.transform(test) test.head()
Implementer ARIMA
Det er på tide å implementere ARIMA! Du vil nå bruke statsmodels
-biblioteket som du installerte tidligere.
Nå må du følge flere trinn:
- Definer modellen ved å kalle
SARIMAX()
og sende inn modellparametrene: p, d og q-parametere, samt P, D og Q-parametere. - Forbered modellen for treningsdataene ved å kalle fit()-funksjonen.
- Lag prognoser ved å kalle
forecast()
-funksjonen og spesifisere antall steg (horisonten) som skal prognoseres.
🎓 Hva er alle disse parameterne til? I en ARIMA-modell er det 3 parametere som brukes for å modellere de viktigste aspektene ved en tidsserie: sesongvariasjon, trend og støy. Disse parameterne er:
p
: parameteren knyttet til den autoregressive delen av modellen, som inkorporerer tidligere verdier.
d
: parameteren knyttet til den integrerte delen av modellen, som påvirker mengden differensiering (🎓 husk differensiering 👆?) som skal brukes på en tidsserie.
q
: parameteren knyttet til den glidende gjennomsnittsdelen av modellen.
Merk: Hvis dataene dine har en sesongmessig komponent - som disse dataene har - bruker vi en sesongmessig ARIMA-modell (SARIMA). I så fall må du bruke et annet sett med parametere:
P
,D
ogQ
, som beskriver de samme assosiasjonene somp
,d
ogq
, men tilsvarer de sesongmessige komponentene i modellen.
-
Start med å sette din foretrukne horisontverdi. La oss prøve 3 timer:
# Specify the number of steps to forecast ahead HORIZON = 3 print('Forecasting horizon:', HORIZON, 'hours')
Å velge de beste verdiene for en ARIMA-modells parametere kan være utfordrende, da det er noe subjektivt og tidkrevende. Du kan vurdere å bruke en
auto_arima()
-funksjon frapyramid
-biblioteket. -
For nå, prøv noen manuelle valg for å finne en god modell.
order = (4, 1, 0) seasonal_order = (1, 1, 0, 24) model = SARIMAX(endog=train, order=order, seasonal_order=seasonal_order) results = model.fit() print(results.summary())
En tabell med resultater blir skrevet ut.
Du har bygget din første modell! Nå må vi finne en måte å evaluere den på.
Evaluer modellen din
For å evaluere modellen din kan du utføre den såkalte walk forward
-valideringen. I praksis blir tidsseriemodeller re-trent hver gang nye data blir tilgjengelige. Dette lar modellen lage den beste prognosen ved hvert tidssteg.
Start ved begynnelsen av tidsserien med denne teknikken, tren modellen på treningsdatasettet. Deretter lager du en prognose for neste tidssteg. Prognosen evalueres mot den kjente verdien. Treningssettet utvides deretter til å inkludere den kjente verdien, og prosessen gjentas.
Merk: Du bør holde treningssettets vindu fast for mer effektiv trening, slik at hver gang du legger til en ny observasjon i treningssettet, fjerner du observasjonen fra begynnelsen av settet.
Denne prosessen gir en mer robust estimering av hvordan modellen vil prestere i praksis. Imidlertid kommer det med beregningskostnaden ved å lage så mange modeller. Dette er akseptabelt hvis dataene er små eller hvis modellen er enkel, men kan være et problem i stor skala.
Walk-forward validering er gullstandarden for evaluering av tidsseriemodeller og anbefales for dine egne prosjekter.
-
Først, opprett et testdatapunkt for hvert HORIZON-steg.
test_shifted = test.copy() for t in range(1, HORIZON+1): test_shifted['load+'+str(t)] = test_shifted['load'].shift(-t, freq='H') test_shifted = test_shifted.dropna(how='any') test_shifted.head(5)
load load+1 load+2 2014-12-30 00:00:00 0.33 0.29 0.27 2014-12-30 01:00:00 0.29 0.27 0.27 2014-12-30 02:00:00 0.27 0.27 0.30 2014-12-30 03:00:00 0.27 0.30 0.41 2014-12-30 04:00:00 0.30 0.41 0.57 Dataene forskyves horisontalt i henhold til horisontpunktet.
-
Lag prognoser for testdataene dine ved hjelp av denne glidende vindustilnærmingen i en løkke på størrelse med testdatasettets lengde:
%%time training_window = 720 # dedicate 30 days (720 hours) for training train_ts = train['load'] test_ts = test_shifted history = [x for x in train_ts] history = history[(-training_window):] predictions = list() order = (2, 1, 0) seasonal_order = (1, 1, 0, 24) for t in range(test_ts.shape[0]): model = SARIMAX(endog=history, order=order, seasonal_order=seasonal_order) model_fit = model.fit() yhat = model_fit.forecast(steps = HORIZON) predictions.append(yhat) obs = list(test_ts.iloc[t]) # move the training window history.append(obs[0]) history.pop(0) print(test_ts.index[t]) print(t+1, ': predicted =', yhat, 'expected =', obs)
Du kan se treningen foregå:
2014-12-30 00:00:00 1 : predicted = [0.32 0.29 0.28] expected = [0.32945389435989236, 0.2900626678603402, 0.2739480752014323] 2014-12-30 01:00:00 2 : predicted = [0.3 0.29 0.3 ] expected = [0.2900626678603402, 0.2739480752014323, 0.26812891674127126] 2014-12-30 02:00:00 3 : predicted = [0.27 0.28 0.32] expected = [0.2739480752014323, 0.26812891674127126, 0.3025962399283795]
-
Sammenlign prognosene med den faktiske belastningen:
eval_df = pd.DataFrame(predictions, columns=['t+'+str(t) for t in range(1, HORIZON+1)]) eval_df['timestamp'] = test.index[0:len(test.index)-HORIZON+1] eval_df = pd.melt(eval_df, id_vars='timestamp', value_name='prediction', var_name='h') eval_df['actual'] = np.array(np.transpose(test_ts)).ravel() eval_df[['prediction', 'actual']] = scaler.inverse_transform(eval_df[['prediction', 'actual']]) eval_df.head()
Output
timestamp h prediction actual 0 2014-12-30 00:00:00 t+1 3,008.74 3,023.00 1 2014-12-30 01:00:00 t+1 2,955.53 2,935.00 2 2014-12-30 02:00:00 t+1 2,900.17 2,899.00 3 2014-12-30 03:00:00 t+1 2,917.69 2,886.00 4 2014-12-30 04:00:00 t+1 2,946.99 2,963.00 Observer prognosen for timebaserte data sammenlignet med den faktiske belastningen. Hvor nøyaktig er dette?
Sjekk modellens nøyaktighet
Sjekk nøyaktigheten til modellen din ved å teste dens gjennomsnittlige absolutte prosentvise feil (MAPE) over alle prognosene.
🧮 Vis meg matematikken
MAPE brukes for å vise prediksjonsnøyaktighet som et forhold definert av formelen ovenfor. Forskjellen mellom faktisk og forutsagt deles på det faktiske.
"Den absolutte verdien i denne beregningen summeres for hvert prognosert tidspunkt og deles på antall tilpassede punkter n." wikipedia
-
Uttrykk ligningen i kode:
if(HORIZON > 1): eval_df['APE'] = (eval_df['prediction'] - eval_df['actual']).abs() / eval_df['actual'] print(eval_df.groupby('h')['APE'].mean())
-
Beregn MAPE for ett steg:
print('One step forecast MAPE: ', (mape(eval_df[eval_df['h'] == 't+1']['prediction'], eval_df[eval_df['h'] == 't+1']['actual']))*100, '%')
MAPE for ett steg: 0.5570581332313952 %
-
Skriv ut MAPE for flertrinnsprognosen:
print('Multi-step forecast MAPE: ', mape(eval_df['prediction'], eval_df['actual'])*100, '%')
Multi-step forecast MAPE: 1.1460048657704118 %
Et lavt tall er best: husk at en prognose med en MAPE på 10 er feil med 10%.
-
Men som alltid, det er enklere å se denne typen nøyaktighetsmåling visuelt, så la oss plotte det:
if(HORIZON == 1): ## Plotting single step forecast eval_df.plot(x='timestamp', y=['actual', 'prediction'], style=['r', 'b'], figsize=(15, 8)) else: ## Plotting multi step forecast plot_df = eval_df[(eval_df.h=='t+1')][['timestamp', 'actual']] for t in range(1, HORIZON+1): plot_df['t+'+str(t)] = eval_df[(eval_df.h=='t+'+str(t))]['prediction'].values fig = plt.figure(figsize=(15, 8)) ax = plt.plot(plot_df['timestamp'], plot_df['actual'], color='red', linewidth=4.0) ax = fig.add_subplot(111) for t in range(1, HORIZON+1): x = plot_df['timestamp'][(t-1):] y = plot_df['t+'+str(t)][0:len(x)] ax.plot(x, y, color='blue', linewidth=4*math.pow(.9,t), alpha=math.pow(0.8,t)) ax.legend(loc='best') plt.xlabel('timestamp', fontsize=12) plt.ylabel('load', fontsize=12) plt.show()
🏆 Et veldig fint plot som viser en modell med god nøyaktighet. Bra jobbet!
🚀Utfordring
Utforsk måter å teste nøyaktigheten til en tidsseriemodell. Vi berører MAPE i denne leksjonen, men finnes det andre metoder du kan bruke? Undersøk dem og kommenter dem. Et nyttig dokument kan finnes her
Quiz etter leksjonen
Gjennomgang & Selvstudium
Denne leksjonen berører kun det grunnleggende innen tidsserieprognoser med ARIMA. Ta deg tid til å utdype kunnskapen din ved å utforske dette repositoriet og dets ulike modelltyper for å lære andre måter å bygge tidsseriemodeller på.
Oppgave
Ansvarsfraskrivelse:
Dette dokumentet er oversatt ved hjelp av AI-oversettelsestjenesten Co-op Translator. Selv om vi tilstreber nøyaktighet, vennligst vær oppmerksom på at automatiske oversettelser kan inneholde feil eller unøyaktigheter. Det originale dokumentet på sitt opprinnelige språk bør anses som den autoritative kilden. For kritisk informasjon anbefales profesjonell menneskelig oversettelse. Vi er ikke ansvarlige for eventuelle misforståelser eller feiltolkninger som oppstår ved bruk av denne oversettelsen.