Aikasarjaennustaminen 1

Aikasarjaennustamisessa oletan, että toteutuneiden havaintojen muodostama aikasarja sisältää informaatiota, joka auttaa tulevien havaintojen ennustamisessa. Ennustusmenetelmä riippuu siitä, minkälaista systemaattista vaihtelua aikasarjassa esiintyy. Eksponentiaalisia tasoitusmenetelmiä käytettäessä on kolme päävaihtoehtoa:

  • Yksinkertainen eksponentiaalinen tasoitus aikasarjoille, joissa ei ole trendiä eikä kausivaihtelua.
  • Kaksinkertainen eksponentiaalinen tasoitus eli Holtin menetelmä aikasarjoille, joissa on trendi, mutta ei kausivaihtelua.
  • Kolminkertainen eksponentiaalinen tasoitus eli Holt-Winterin menetelmä aikasarjoille, joissa on sekä trendi että kausivaihtelu.

Tämä artikkeli käsittelee yksinkertaista eksponentiaalista tasoitusta. Yksinkertaisessa eksponentiaalisessa tasoituksessa ennuste lasketaan seuraavasti:

alfa*edellinen havainto + (1 – alfa)*edellinen ennuste

Ennuste saadaan viimeisimmän havainnon ja siihen liittyneen ennusteen painotettuna summana. Painokerroin alfa on välillä 0 – 1 oleva luku, joka ilmaisee, kuinka suurella painolla edellistä havaintoa painotetaan ennustetta laskettaessa:

    • Jos alfa on 0, niin ennuste on sama kuin edellinen ennuste.
    • Jos alfa on 1, niin ennuste on sama kuin edellinen havainto.
    • Suuret alfan arvot antavat ennusteita, jotka reagoivat herkästi aikasarjassa esiintyvään vaihteluun, koska viimeisimmillä havainnoilla on suurempi paino.
    • Pienet alfan arvot tasoittavat voimakkaasti aikasarjan vaihtelua.

 

Alfan arvo valitaan yleensä siten että keskimääräinen ennustevirhe saadaan mahdollisimman pieneksi. Voin kirjoittaa ennusteen laskentakaavan myös muotoon

edellinen ennuste + alfa*(edellinen havainto – edellinen ennuste)

Ennustetta siis korjataan jokaisen toteutuneen havainnon jälkeen korjaustermillä alfa*edellisen ennusteen virhe.

Python toteutus

Tämän artikkelin ohjelmakoodin ja tulosteet löydät GitHubista:

https://github.com/taanila/tilastoapu/blob/master/forecast1.ipynb

Jos kopioit koodia itsellesi, niin kannattaa käyttää GitHubia. Tästä artikkelista kopioidut koodit eivät välttämättä toimi oikein (esimerkiksi sisennykset voivat kopioitua virheellisesti).

Oletan, että lukijalla on asennettuna Anaconda ja sen mukana tuleva Jupyter notebook.

Kirjastot

Tarvitsen monia ohjelmakirjastoja: pandas dataframen käsittelyyn, matplotlib kuvioiden tekemiseen, statsmodels eksponentiaaliseen tasoitukseen, sklearn ennustevirhettä kuvaavien tunnuslukujen laskemiseen ja math neliöjuuren laskemiseen.

import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline
from statsmodels.tsa.api import SimpleExpSmoothing
from sklearn.metrics import mean_squared_error, mean_absolute_error
from math import sqrt

Aikasarja

Tallennan vuosineljänneksittäisiä myyntilukuja sisältävän aikasarjan data-nimiseen dataframeen:

series=[500,350,250,400,450,350,200,300,350,200,150,400,
   550,350,250,550,550,400,350,600,750,500,400,650,850]
index=pd.date_range('2000-03-31', periods=25, freq='Q')
data=pd.DataFrame(series, index=index)
data.columns=['Demand']

Huomaa, kuinka kätevästi määrittelen vuosineljännekset pandas-kirjaston date_range-toiminnolla.

Ennustemalli

Sovitan eksponentiaalisen mallin aikasarjaan ja tallennan mallin mukaiset sovitetut arvot datan Predict-sarakkeeseen. Viivakuviosta voin arvioida silmämäärin mallin sopivuutta havaintoihin.

fit1 = SimpleExpSmoothing(data['Demand']).fit()
data['Predict']=fit1.fittedvalues
data.plot()

exp1

Lukiessasi seuraavia artikkeleitani, huomaat, että parempiakin ennustemalleja on tälle aikasarjalle löydettävissä.

Mallin sopivuutta voin mitata laskemalla ennustevirheiden (ennuste-toteutunut) neliöiden keskiarvon ja ottamalla siitä neliöjuuren (RMSE=root mean square error). Tämä kuvaa ennustevirheiden keskihajontaa.

sqrt(mean_squared_error(data['Demand'], data['Predict']))

Tulokseksi saan noin 150. Tätä kannattaa verrata seuraavissa artikkeleissa laskettuihin vastaaviin lukuihin Holtin ja Holt-Winterin malleissa. Karkeasti voisi todeta: Mitä pienempi RMSE sitä parempi malli.

Toinen usein käytetty mallin sopivuutta mittaava luku on virheiden itseisarvojen keskiarvo (MAD=mean absolute deviation):

mean_absolute_error(data['Demand'], data['Predict'])

Tämän arvoksi saan noin 128.

Virheitä kannattaa tarkastella myös sellaisenaan:

data['Resid']=fit1.resid
data['Resid'].plot()

exp2

Hyvässä ennustemallissa virheissä ei saisi olla trendiä tai systemaattista vaihtelua. Tässä virheen vaihtelu näyttää melko systemaattiselta, joten ennustemalli ei ole paras mahdollinen.

Ennuste

Lasken vielä ennusteet neljälle seuraavalle neljännekselle omaan dataframeen ja piirrän samaan kuvioon alkuperäisen aikasarjan ja neljän neljänneksen ennusteet. Yksinkertainen eksponentiaalinen tasoitus antaa tuleville ajankohdille vakioennusteen, jota toki voidaan korjata jokaisen uuden havainnon jälkeen.

index=pd.date_range('2006-06-30', periods=4, freq='Q')
datap=pd.DataFrame(fit1.forecast(4), index=index)
datap.columns=['Predict']
data['Demand'].plot()
datap['Predict'].plot()

exp3

Mallin parametreihin voin tutustua tarkemmin komennolla

fit1.params

{’damping_slope’: nan,
’initial_level’: 388.1086015386066,
’initial_seasons’: array([], dtype=float64),
’initial_slope’: nan,
’lamda’: None,
’remove_bias’: False,
’smoothing_level’: 0.32274949027017524,
’smoothing_seasonal’: nan,
’smoothing_slope’: nan,
’use_boxcox’: False}

Tästä selviää, että mallissa käytetty alfa on noin 0,32. Tämä alfa on määräytynyt siten että RMSE saa pienimmän mahdollisen arvon. Mallin sovitusvaiheessa voin määrittää alfan myös itse, esimerkiksi:

fit1 = SimpleExpSmoothing(data['Demand']).fit
   (smoothing_level=0.6)

Seuraavaksi

Esimerkkinä käyttämässäni aikasarjassa on melko helppo erottaa alkupään laskeva trendi ja loppupään nouseva trendi. Seuraavassa artikkelissani Aikasarjaennustaminen 2 yritän sovittaa aikasarjaan mallin, joka huomioi trendin.

Mainokset