# Previsione di serie temporali con ARIMA
Nella lezione precedente, hai appreso un po' sulla previsione di serie temporali e hai caricato un dataset che mostra le fluttuazioni del carico elettrico nel tempo.
[](https://youtu.be/IUSk-YDau10 "Introduzione ad ARIMA")
> 🎥 Clicca sull'immagine sopra per un video: Una breve introduzione ai modelli ARIMA. L'esempio è fatto in R, ma i concetti sono universali.
## [Quiz pre-lezione](https://gray-sand-07a10f403.1.azurestaticapps.net/quiz/43/)
## Introduzione
In questa lezione, scoprirai un modo specifico per costruire modelli con [ARIMA: *A*uto*R*egressive *I*ntegrated *M*oving *A*verage](https://wikipedia.org/wiki/Autoregressive_integrated_moving_average). I modelli ARIMA sono particolarmente adatti per adattarsi ai dati che mostrano [non-stazionarietà](https://wikipedia.org/wiki/Stationary_process).
## Concetti generali
Per poter lavorare con ARIMA, ci sono alcuni concetti che devi conoscere:
- 🎓 **Stazionarietà**. In un contesto statistico, la stazionarietà si riferisce a dati la cui distribuzione non cambia quando viene spostata nel tempo. I dati non stazionari, invece, mostrano fluttuazioni dovute a tendenze che devono essere trasformate per essere analizzate. La stagionalità, per esempio, può introdurre fluttuazioni nei dati e può essere eliminata attraverso un processo di 'differenziazione stagionale'.
- 🎓 **[Differenziazione](https://wikipedia.org/wiki/Autoregressive_integrated_moving_average#Differencing)**. La differenziazione dei dati, ancora una volta in un contesto statistico, si riferisce al processo di trasformazione dei dati non stazionari per renderli stazionari rimuovendo la loro tendenza non costante. "La differenziazione rimuove i cambiamenti nel livello di una serie temporale, eliminando tendenza e stagionalità e stabilizzando di conseguenza la media della serie temporale." [Paper di Shixiong et al](https://arxiv.org/abs/1904.07632)
## ARIMA nel contesto delle serie temporali
Esaminiamo le parti di ARIMA per capire meglio come ci aiuta a modellare le serie temporali e a fare previsioni.
- **AR - per AutoRegressivo**. I modelli autoregressivi, come suggerisce il nome, guardano 'indietro' nel tempo per analizzare i valori precedenti nei tuoi dati e fare ipotesi su di essi. Questi valori precedenti sono chiamati 'lag'. Un esempio potrebbe essere i dati che mostrano le vendite mensili di matite. Il totale delle vendite di ogni mese sarebbe considerato una 'variabile evolutiva' nel dataset. Questo modello è costruito come "la variabile evolutiva di interesse è regressa sui suoi stessi valori ritardati (cioè, precedenti)." [wikipedia](https://wikipedia.org/wiki/Autoregressive_integrated_moving_average)
- **I - per Integrato**. A differenza dei modelli simili 'ARMA', la 'I' in ARIMA si riferisce al suo aspetto *[integrato](https://wikipedia.org/wiki/Order_of_integration)*. I dati sono 'integrati' quando vengono applicati passaggi di differenziazione per eliminare la non stazionarietà.
- **MA - per Media Mobile**. L'aspetto della [media mobile](https://wikipedia.org/wiki/Moving-average_model) di questo modello si riferisce alla variabile di output che è determinata osservando i valori attuali e passati dei lag.
In sintesi: ARIMA viene utilizzato per adattare un modello alla forma speciale dei dati di serie temporali nel modo più preciso possibile.
## Esercizio - costruisci un modello ARIMA
Apri la cartella [_/working_](https://github.com/microsoft/ML-For-Beginners/tree/main/7-TimeSeries/2-ARIMA/working) in questa lezione e trova il file [_notebook.ipynb_](https://github.com/microsoft/ML-For-Beginners/blob/main/7-TimeSeries/2-ARIMA/working/notebook.ipynb).
1. Esegui il notebook per caricare la libreria `statsmodels` Python; avrai bisogno di questa per i modelli ARIMA.
1. Carica le librerie necessarie
1. Ora, carica altre librerie utili per la visualizzazione dei dati:
```python
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
```
1. Carica i dati dal file `/data/energy.csv` in un dataframe Pandas e dai un'occhiata:
```python
energy = load_data('./data')[['load']]
energy.head(10)
```
1. Traccia tutti i dati energetici disponibili da gennaio 2012 a dicembre 2014. Non ci dovrebbero essere sorprese poiché abbiamo visto questi dati nella lezione precedente:
```python
energy.plot(y='load', subplots=True, figsize=(15, 8), fontsize=12)
plt.xlabel('timestamp', fontsize=12)
plt.ylabel('load', fontsize=12)
plt.show()
```
Ora, costruiamo un modello!
### Crea dataset di addestramento e test
Ora i tuoi dati sono caricati, quindi puoi separarli in set di addestramento e di test. Addestrerai il tuo modello sul set di addestramento. Come al solito, dopo che il modello ha terminato l'addestramento, valuterai la sua accuratezza utilizzando il set di test. Devi assicurarti che il set di test copra un periodo di tempo successivo rispetto al set di addestramento per garantire che il modello non acquisisca informazioni dai periodi futuri.
1. Assegna un periodo di due mesi dal 1 settembre al 31 ottobre 2014 al set di addestramento. Il set di test includerà il periodo di due mesi dal 1 novembre al 31 dicembre 2014:
```python
train_start_dt = '2014-11-01 00:00:00'
test_start_dt = '2014-12-30 00:00:00'
```
Poiché questi dati riflettono il consumo giornaliero di energia, c'è un forte schema stagionale, ma il consumo è più simile al consumo nei giorni più recenti.
1. Visualizza le differenze:
```python
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()
```

Pertanto, utilizzare una finestra di tempo relativamente piccola per l'addestramento dei dati dovrebbe essere sufficiente.
> Nota: Poiché la funzione che utilizziamo per adattare il modello ARIMA utilizza la validazione in-sample durante l'adattamento, ometteremo i dati di validazione.
### Prepara i dati per l'addestramento
Ora, devi preparare i dati per l'addestramento eseguendo il filtraggio e la scalatura dei tuoi dati. Filtra il tuo dataset per includere solo i periodi di tempo e le colonne di cui hai bisogno e scala i dati per assicurarti che siano proiettati nell'intervallo 0,1.
1. Filtra il dataset originale per includere solo i periodi di tempo sopra menzionati per set e includendo solo la colonna 'load' necessaria più la data:
```python
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)
```
Puoi vedere la forma dei dati:
```output
Training data shape: (1416, 1)
Test data shape: (48, 1)
```
1. Scala i dati per essere nell'intervallo (0, 1).
```python
scaler = MinMaxScaler()
train['load'] = scaler.fit_transform(train)
train.head(10)
```
1. Visualizza i dati originali vs. scalati:
```python
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()
```

> I dati originali

> I dati scalati
1. Ora che hai calibrato i dati scalati, puoi scalare i dati di test:
```python
test['load'] = scaler.transform(test)
test.head()
```
### Implementa ARIMA
È ora di implementare ARIMA! Ora utilizzerai la libreria `statsmodels` che hai installato in precedenza.
Ora devi seguire diversi passaggi
1. Definisci il modello chiamando `SARIMAX()` and passing in the model parameters: p, d, and q parameters, and P, D, and Q parameters.
2. Prepare the model for the training data by calling the fit() function.
3. Make predictions calling the `forecast()` function and specifying the number of steps (the `horizon`) to forecast.
> 🎓 What are all these parameters for? In an ARIMA model there are 3 parameters that are used to help model the major aspects of a time series: seasonality, trend, and noise. These parameters are:
`p`: the parameter associated with the auto-regressive aspect of the model, which incorporates *past* values.
`d`: the parameter associated with the integrated part of the model, which affects the amount of *differencing* (🎓 remember differencing 👆?) to apply to a time series.
`q`: the parameter associated with the moving-average part of the model.
> Note: If your data has a seasonal aspect - which this one does - , we use a seasonal ARIMA model (SARIMA). In that case you need to use another set of parameters: `P`, `D`, and `Q` which describe the same associations as `p`, `d`, and `q`, ma corrispondono ai componenti stagionali del modello.
1. Inizia impostando il tuo valore di orizzonte preferito. Proviamo 3 ore:
```python
# Specify the number of steps to forecast ahead
HORIZON = 3
print('Forecasting horizon:', HORIZON, 'hours')
```
Selezionare i migliori valori per i parametri di un modello ARIMA può essere impegnativo poiché è in parte soggettivo e richiede tempo. Potresti considerare di utilizzare una libreria `auto_arima()` function from the [`pyramid`](https://alkaline-ml.com/pmdarima/0.9.0/modules/generated/pyramid.arima.auto_arima.html),
1. Per ora prova alcune selezioni manuali per trovare un buon modello.
```python
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())
```
Viene stampata una tabella di risultati.
Hai costruito il tuo primo modello! Ora dobbiamo trovare un modo per valutarlo.
### Valuta il tuo modello
Per valutare il tuo modello, puoi eseguire la cosiddetta validazione `walk forward`. In pratica, i modelli di serie temporali vengono ri-addestrati ogni volta che sono disponibili nuovi dati. Questo consente al modello di fare la migliore previsione a ogni passo temporale.
Partendo dall'inizio della serie temporale utilizzando questa tecnica, addestra il modello sul set di dati di addestramento. Quindi fai una previsione sul passo temporale successivo. La previsione viene valutata rispetto al valore noto. Il set di addestramento viene quindi ampliato per includere il valore noto e il processo viene ripetuto.
> Nota: Dovresti mantenere la finestra del set di addestramento fissa per un addestramento più efficiente in modo che ogni volta che aggiungi una nuova osservazione al set di addestramento, rimuovi l'osservazione dall'inizio del set.
Questo processo fornisce una stima più robusta di come il modello si comporterà in pratica. Tuttavia, comporta il costo computazionale di creare tanti modelli. Questo è accettabile se i dati sono piccoli o se il modello è semplice, ma potrebbe essere un problema su larga scala.
La validazione walk-forward è lo standard d'oro per la valutazione dei modelli di serie temporali ed è raccomandata per i tuoi progetti.
1. Innanzitutto, crea un punto dati di test per ogni passo HORIZON.
```python
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 |
I dati vengono spostati orizzontalmente in base al punto di orizzonte.
1. Fai previsioni sui tuoi dati di test utilizzando questo approccio a finestra scorrevole in un ciclo della lunghezza dei dati di test:
```python
%%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)
```
Puoi osservare l'addestramento in corso:
```output
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]
```
1. Confronta le previsioni con il carico effettivo:
```python
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 |
Osserva la previsione dei dati orari, rispetto al carico effettivo. Quanto è accurata questa previsione?
### Verifica l'accuratezza del modello
Verifica l'accuratezza del tuo modello testando il suo errore percentuale assoluto medio (MAPE) su tutte le previsioni.
> **🧮 Mostrami i calcoli**
>
> 
>
> [MAPE](https://www.linkedin.com/pulse/what-mape-mad-msd-time-series-allameh-statistics/) viene utilizzato per mostrare l'accuratezza della previsione come rapporto definito dalla formula sopra. La differenza tra actualt e predictedt viene divisa per actualt. "Il valore assoluto in questo calcolo viene sommato per ogni punto di previsione nel tempo e diviso per il numero di punti adattati n." [wikipedia](https://wikipedia.org/wiki/Mean_absolute_percentage_error)
1. Esprimi l'equazione in codice:
```python
if(HORIZON > 1):
eval_df['APE'] = (eval_df['prediction'] - eval_df['actual']).abs() / eval_df['actual']
print(eval_df.groupby('h')['APE'].mean())
```
1. Calcola il MAPE di un singolo passo:
```python
print('One step forecast MAPE: ', (mape(eval_df[eval_df['h'] == 't+1']['prediction'], eval_df[eval_df['h'] == 't+1']['actual']))*100, '%')
```
MAPE della previsione di un passo: 0.5570581332313952 %
1. Stampa il MAPE della previsione multi-passo:
```python
print('Multi-step forecast MAPE: ', mape(eval_df['prediction'], eval_df['actual'])*100, '%')
```
```output
Multi-step forecast MAPE: 1.1460048657704118 %
```
Un numero basso è il migliore: considera che una previsione con un MAPE di 10 è sbagliata del 10%.
1. Ma come sempre, è più facile vedere questo tipo di misurazione dell'accuratezza visivamente, quindi tracciamolo:
```python
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()
```

🏆 Un grafico molto bello, che mostra un modello con buona accuratezza. Ben fatto!
---
## 🚀Sfida
Approfondisci i modi per testare l'accuratezza di un modello di serie temporali. Abbiamo trattato il MAPE in questa lezione, ma ci sono altri metodi che potresti usare? Ricercali e annotali. Un documento utile può essere trovato [qui](https://otexts.com/fpp2/accuracy.html)
## [Quiz post-lezione](https://gray-sand-07a10f403.1.azurestaticapps.net/quiz/44/)
## Revisione & Autoapprendimento
Questa lezione tocca solo le basi della previsione di serie temporali con ARIMA. Prenditi del tempo per approfondire la tua conoscenza esplorando [questo repository](https://microsoft.github.io/forecasting/) e i suoi vari tipi di modelli per imparare altri modi per costruire modelli di serie temporali.
## Compito
[Un nuovo modello ARIMA](assignment.md)
**Disclaimer**:
Questo documento è stato tradotto utilizzando servizi di traduzione automatica basati su intelligenza artificiale. Sebbene ci sforziamo di ottenere accuratezza, si prega di notare che le traduzioni automatiche possono contenere errori o inesattezze. Il documento originale nella sua lingua madre dovrebbe essere considerato la fonte autorevole. Per informazioni critiche, si raccomanda una traduzione professionale umana. Non siamo responsabili per eventuali malintesi o interpretazioni errate derivanti dall'uso di questa traduzione.