|
2 weeks ago | |
---|---|---|
.. | ||
solution | 2 weeks ago | |
working | 3 weeks ago | |
README.md | 2 weeks ago | |
assignment.md | 2 weeks ago |
README.md
Idősorok előrejelzése ARIMA-val
Az előző leckében megismerkedtél az idősorok előrejelzésének alapjaival, és betöltöttél egy adatállományt, amely az elektromos terhelés ingadozásait mutatja egy időszak alatt.
🎥 Kattints a fenti képre egy videóért: Rövid bevezetés az ARIMA modellekbe. Az példa R-ben készült, de a koncepciók univerzálisak.
Előadás előtti kvíz
Bevezetés
Ebben a leckében megismerkedsz az ARIMA: AutoRegressive Integrated Moving Average modellek építésének egy konkrét módjával. Az ARIMA modellek különösen alkalmasak olyan adatok illesztésére, amelyek nem állomásosak.
Általános fogalmak
Ahhoz, hogy ARIMA-val dolgozhass, néhány alapfogalmat ismerned kell:
-
🎓 Állomásosság. Statisztikai értelemben az állomásosság olyan adatokra utal, amelyek eloszlása nem változik időbeli eltolás esetén. A nem állomásos adatok ingadozásokat mutatnak trendek miatt, amelyeket át kell alakítani az elemzéshez. Például a szezonális hatások ingadozásokat okozhatnak az adatokban, amelyeket 'szezonális differenciálás' révén lehet eltávolítani.
-
🎓 Differenciálás. A differenciálás statisztikai értelemben az a folyamat, amely során a nem állomásos adatokat állomásossá alakítjuk az állandó trend eltávolításával. "A differenciálás eltávolítja az idősor szintjének változásait, megszünteti a trendet és a szezonális hatásokat, ezáltal stabilizálja az idősor átlagát." Shixiong et al tanulmánya
ARIMA az idősorok kontextusában
Nézzük meg az ARIMA részeit, hogy jobban megértsük, hogyan segít az idősorok modellezésében és előrejelzések készítésében.
-
AR - AutoRegresszív. Az autoregresszív modellek, ahogy a nevük is sugallja, visszatekintenek az időben, hogy elemezzék az adatok korábbi értékeit, és feltételezéseket tegyenek róluk. Ezeket a korábbi értékeket 'késéseknek' nevezzük. Példa lehet a havi ceruzaeladások adatai. Minden hónap eladási összesítése az adathalmazban egy 'változó' lenne. Ez a modell úgy épül fel, hogy "az érdeklődésre számot tartó változót saját késleltetett (azaz korábbi) értékeire regresszálják." wikipedia
-
I - Integrált. Az ARIMA modellekben az 'I' az integrált aspektusra utal. Az adatok 'integrálása' a differenciálási lépések alkalmazásával történik, hogy megszüntessük a nem állomásosságot.
-
MA - Mozgó Átlag. A mozgó átlag aspektus az output változóra utal, amelyet a késések aktuális és korábbi értékeinek megfigyelésével határozunk meg.
Összefoglalva: Az ARIMA-t arra használjuk, hogy a modell minél jobban illeszkedjen az idősorok speciális formájához.
Gyakorlat - ARIMA modell építése
Nyisd meg a /working mappát ebben a leckében, és keresd meg a notebook.ipynb fájlt.
-
Futtasd a notebookot, hogy betöltsd a
statsmodels
Python könyvtárat; erre szükséged lesz az ARIMA modellekhez. -
Töltsd be a szükséges könyvtárakat.
-
Most tölts be néhány további könyvtárat, amelyek hasznosak az adatok ábrázolásához:
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
-
Töltsd be az adatokat a
/data/energy.csv
fájlból egy Pandas dataframe-be, és nézd meg:energy = load_data('./data')[['load']] energy.head(10)
-
Ábrázold az összes elérhető energiaadatot 2012 januárjától 2014 decemberéig. Nem lesz meglepetés, hiszen ezt az adatot láttuk az előző leckében:
energy.plot(y='load', subplots=True, figsize=(15, 8), fontsize=12) plt.xlabel('timestamp', fontsize=12) plt.ylabel('load', fontsize=12) plt.show()
Most építsünk egy modellt!
Képzési és tesztelési adathalmazok létrehozása
Most, hogy betöltötted az adatokat, szétválaszthatod őket képzési és tesztelési halmazokra. A modell képzését a képzési halmazon végzed. Szokás szerint, miután a modell befejezte a képzést, a tesztelési halmazzal értékeled annak pontosságát. Biztosítanod kell, hogy a tesztelési halmaz egy későbbi időszakot fed le, mint a képzési halmaz, hogy a modell ne szerezzen információt a jövőbeli időszakokról.
-
Jelölj ki egy két hónapos időszakot 2014. szeptember 1-től október 31-ig a képzési halmaz számára. A tesztelési halmaz a 2014. november 1-től december 31-ig tartó két hónapos időszakot foglalja magában:
train_start_dt = '2014-11-01 00:00:00' test_start_dt = '2014-12-30 00:00:00'
Mivel ezek az adatok az energia napi fogyasztását tükrözik, erős szezonális mintázat figyelhető meg, de a fogyasztás leginkább a legutóbbi napok fogyasztásához hasonló.
-
Vizualizáld a különbségeket:
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()
Ezért viszonylag kis időablak használata elegendő lehet az adatok képzéséhez.
Megjegyzés: Mivel az ARIMA modell illesztéséhez használt függvény a fitting során mintán belüli validációt alkalmaz, kihagyjuk a validációs adatokat.
Az adatok előkészítése a képzéshez
Most elő kell készítened az adatokat a képzéshez, szűréssel és skálázással. Szűrd az adathalmazt, hogy csak a szükséges időszakokat és oszlopokat tartalmazza, és skálázd az adatokat, hogy az értékek a 0 és 1 közötti intervallumba essenek.
-
Szűrd az eredeti adathalmazt, hogy csak az említett időszakokat és a szükséges 'load' oszlopot, valamint a dátumot tartalmazza:
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)
Megnézheted az adatok alakját:
Training data shape: (1416, 1) Test data shape: (48, 1)
-
Skálázd az adatokat, hogy a (0, 1) tartományba essenek.
scaler = MinMaxScaler() train['load'] = scaler.fit_transform(train) train.head(10)
-
Vizualizáld az eredeti és a skálázott adatokat:
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()
Az eredeti adatok
A skálázott adatok
-
Most, hogy kalibráltad a skálázott adatokat, skálázd a tesztadatokat is:
test['load'] = scaler.transform(test) test.head()
ARIMA megvalósítása
Elérkezett az idő az ARIMA megvalósítására! Most használni fogod a korábban telepített statsmodels
könyvtárat.
Kövesd az alábbi lépéseket:
- Határozd meg a modellt a
SARIMAX()
meghívásával, és add meg a modell paramétereit: p, d, és q paraméterek, valamint P, D, és Q paraméterek. - Készítsd elő a modellt a képzési adatokhoz a fit() függvény meghívásával.
- Készíts előrejelzéseket a
forecast()
függvény meghívásával, és add meg az előrejelzés lépéseinek számát (ahorizontot
).
🎓 Mire valók ezek a paraméterek? Az ARIMA modellben három paramétert használunk, amelyek segítenek az idősorok főbb aspektusainak modellezésében: szezonális hatások, trendek és zaj. Ezek a paraméterek:
p
: az autoregresszív aspektushoz kapcsolódó paraméter, amely a múltbeli értékeket veszi figyelembe.
d
: az integrált részhez kapcsolódó paraméter, amely meghatározza, hogy mennyi differenciálást (🎓 emlékszel a differenciálásra 👆?) kell alkalmazni az idősorra.
q
: a mozgó átlag részhez kapcsolódó paraméter.
Megjegyzés: Ha az adatok szezonális aspektussal rendelkeznek - mint ezek -, akkor szezonális ARIMA modellt (SARIMA) használunk. Ebben az esetben egy másik paraméterkészletet kell használni:
P
,D
, ésQ
, amelyek ugyanazokat az összefüggéseket írják le, mintp
,d
, ésq
, de a modell szezonális komponenseire vonatkoznak.
-
Kezdd azzal, hogy beállítod a preferált horizontértéket. Próbáljunk ki 3 órát:
# Specify the number of steps to forecast ahead HORIZON = 3 print('Forecasting horizon:', HORIZON, 'hours')
Az ARIMA modell paramétereinek legjobb értékeinek kiválasztása kihívást jelenthet, mivel ez némileg szubjektív és időigényes. Érdemes lehet használni az
auto_arima()
függvényt apyramid
könyvtárból. -
Egyelőre próbálj ki néhány manuális beállítást, hogy jó modellt találj.
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())
Egy eredménytábla jelenik meg.
Elkészítetted az első modelledet! Most meg kell találnunk egy módot annak értékelésére.
A modell értékelése
A modell értékeléséhez alkalmazhatod az úgynevezett lépésről lépésre
validációt. A gyakorlatban az idősor modelleket minden alkalommal újra kell tanítani, amikor új adatok válnak elérhetővé. Ez lehetővé teszi, hogy a modell minden időlépésnél a legjobb előrejelzést készítse.
Ezzel a technikával az idősor elején kezdve tanítsd a modellt a képzési adathalmazon. Ezután készíts előrejelzést a következő időlépésre. Az előrejelzést összehasonlítjuk az ismert értékkel. A képzési halmazt ezután kibővítjük az ismert értékkel, és a folyamatot megismételjük.
Megjegyzés: A képzési halmaz ablakát érdemes fixen tartani a hatékonyabb képzés érdekében, így minden alkalommal, amikor új megfigyelést adsz hozzá a képzési halmazhoz, eltávolítod az ablak elejéről a megfigyelést.
Ez a folyamat robusztusabb becslést nyújt arról, hogy a modell hogyan fog teljesíteni a gyakorlatban. Ugyanakkor számítási költséggel jár, mivel sok modellt kell létrehozni. Ez elfogadható, ha az adatok kicsik vagy a modell egyszerű, de problémát jelenthet nagyobb léptékben.
A lépésről lépésre validáció az idősor modellek értékelésének arany standardja, és ajánlott saját projektjeidhez.
-
Először hozz létre egy tesztadatpontot minden HORIZONT lépéshez.
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 Az adatok vízszintesen eltolódnak a horizont pontja szerint.
-
Készíts előrejelzéseket a tesztadatokon ezzel a csúszó ablak megközelítéssel, a tesztadatok hosszának megfelelő méretű ciklusban:
%%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)
Nézheted a képzés folyamatát:
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]
-
Hasonlítsd össze az előrejelzéseket a tényleges terheléssel:
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()
Kimenet
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 Figyeld meg az óránkénti adatok előrejelzését, összehasonlítva a tényleges terheléssel. Mennyire pontos ez?
A modell pontosságának ellenőrzése
Ellenőrizd a modell pontosságát az összes előrejelzés átlagos abszolút százalékos hibájának (MAPE) tesztelésével.
🧮 Mutasd a matematikát
A MAPE a predikció pontosságát mutatja egy arányként, amelyet a fenti képlet határoz meg. A tényleges és az előrejelzett érték közötti különbséget elosztjuk a tényleges értékkel.
"Ennek a számításnak az abszolút értékét minden előrejelzett időpontra összegezzük, majd elosztjuk az illesztett pontok számával, n." wikipedia
-
Fejezd ki az egyenletet kódban:
if(HORIZON > 1): eval_df['APE'] = (eval_df['prediction'] - eval_df['actual']).abs() / eval_df['actual'] print(eval_df.groupby('h')['APE'].mean())
-
Számítsd ki az egy lépésre vonatkozó MAPE értéket:
print('One step forecast MAPE: ', (mape(eval_df[eval_df['h'] == 't+1']['prediction'], eval_df[eval_df['h'] == 't+1']['actual']))*100, '%')
Egy lépés előrejelzés MAPE: 0.5570581332313952 %
-
Nyomtasd ki a több lépésre vonatkozó előrejelzés MAPE értékét:
print('Multi-step forecast MAPE: ', mape(eval_df['prediction'], eval_df['actual'])*100, '%')
Multi-step forecast MAPE: 1.1460048657704118 %
Egy alacsony szám a legjobb: gondolj arra, hogy egy előrejelzés, amelynek MAPE értéke 10, 10%-kal tér el.
-
De mint mindig, az ilyen pontosságmérést vizuálisan könnyebb megérteni, ezért ábrázoljuk:
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()
🏆 Egy nagyon szép ábra, amely egy jó pontosságú modellt mutat. Szép munka!
🚀Kihívás
Merülj el az idősor modellek pontosságának tesztelési módjaiban. Ebben a leckében érintjük a MAPE-t, de vannak más módszerek, amelyeket használhatnál? Kutass utána, és jegyzeteld le őket. Egy hasznos dokumentumot itt találhatsz: itt
Utó-leckekvíz
Áttekintés és önálló tanulás
Ez a lecke csak az ARIMA-val történő idősor előrejelzés alapjait érinti. Szánj időt arra, hogy elmélyítsd tudásodat, és nézd meg ezt a repót és annak különböző modell típusait, hogy megtanuld, hogyan lehet más módokon idősor modelleket építeni.
Feladat
Felelősség kizárása:
Ez a dokumentum az AI fordítási szolgáltatás, a Co-op Translator segítségével lett lefordítva. Bár törekszünk a pontosságra, kérjük, vegye figyelembe, hogy az automatikus fordítások hibákat vagy pontatlanságokat tartalmazhatnak. Az eredeti dokumentum az eredeti nyelvén tekintendő hiteles forrásnak. Kritikus információk esetén javasolt professzionális emberi fordítást igénybe venni. Nem vállalunk felelősséget semmilyen félreértésért vagy téves értelmezésért, amely a fordítás használatából eredhet.