In questo articolo ci addentriamo nel cuore del progetto: andiamo ad analizzare come abbiamo realizzato il programma in Python che addestra i modelli, calcola gli errori ed effettua le previsioni vere e proprie. Come sempre ricordo che al termine dell’articolo sarà possibile scaricare il file con il codice completo.
Cominciamo innanzitutto ad importare tutte le librerie necessarie:
import numpy #per manipolare i numeri
import pandas #per creare e gestire tabelle
import sklearn #per machine learning
import matplotlib.pyplot as plt #per visualizzare grafici
import urllib.request #per eseguire una pagina web
from sklearn.tree import DecisionTreeRegressor #importa il modello ad albero decisionale
from sklearn.ensemble import RandomForestRegressor, GradientBoostingRegressor #importa il modello a foresta casuale ed il modello Gradient Boosting Regressor
from sklearn.linear_model import LinearRegression, ElasticNet #importa il modello Linear Regression ed il modello Elastic Net
from sklearn.svm import SVR #importa il modello SVR
from catboost import CatBoostRegressor #importa il modello Cat Boost Regressor
from xgboost.sklearn import XGBRegressor #importa il modello XGB Regressor
from sklearn.model_selection import train_test_split #importa la funzione train_test_split
from sklearn.metrics import mean_squared_error #importa errore quadratico medio
from sklearn.metrics import mean_absolute_error #importa errore assoluto medio
from math import sqrt #importa radice quadrata
import datetime #importa datetime per manipolare date e orari
Iniziamo subito ad elaborare il nostro set di dati: in particolare importiamo i valori dal file dati_machine_learning.csv, stampiamo a video le prime righe ed una elaborazione riassuntiva dei dati per effettuare un rapido controllo visivo (operazioni non obbligatorie), verifichiamo la presenza di valori nulli ed eliminiamo eventuali righe nulle per evitare di sporcare le nostre analisi.
wheather = pandas.read_csv("https://www.nome_sito.it/dati_machine_learning.csv", header = 0, sep = ";")
#importa il set di dati
#la prima riga contiene l'intestazione quindi impostando header = 0, pandas si occuperà in automatico di gestirla
print("\n")
print(wheather.head()) #stampa le prime righe del set di dati, di default le prime 5
print("\n")
print(wheather.describe()) #stampa una elaborazione riassuntiva dei dati: conteggio, media, max, min, ecc. per ogni colonna
print("\nPresenza di valori nulli: ")
print(wheather.isnull().values.any()) #stampa true se ci sono righe con valori nulli
print("\n")
wheather = wheather.dropna() #rimuove le righe che contengono qualche valore nullo
Andiamo ad integrare i dati importati dal file dati_machine_learning.csv con le nostre colonne obiettivo, ovvero con i valori che vogliamo prevedere: la temperatura massima, la temperatura minima e le precipitazioni cumulate del giorno seguente. Inoltre sostituiamo eventuali valori nulli con il primo non nullo precedente (l’ultima riga infatti ha i campi target vuoti non essendoci i valori del giorno seguente quindi li impostiamo come quelli del giorno precedente).
wheather["target_tmax"] = wheather.shift(-1)["temperatura_max"] #aggiunge una nuova colonna "obiettivo" con la temperatura max del giorno seguente
wheather["target_tmin"] = wheather.shift(-1)["temperatura_min"] #aggiunge una nuova colonna "obiettivo" con la temperatura min del giorno seguente
wheather["target_precipitazioni_cumulate"] = wheather.shift(-1)["precipitazioni_cumulate"] #aggiunge una nuova colonna "obiettivo" con le precipitazioni_cumulate del giorno seguente
wheather = wheather.ffill() #sostituisce eventuali valori nulli prendendo il primo non nullo precedente (ultima riga ha i campi target vuoti, imposta quelli del giorno precedente)
Definiamo il giorno da elaborare: l’obiettivo sarà analizzare i valori di ieri per calcolare la previsione per la data odierna.
#selezione del giorno da elaborare
oggi=datetime.date.today()
un_giorno=datetime.timedelta(days=1)
ieri=oggi-un_giorno
giorno_selezionato = int(ieri.strftime("%Y%m%d"))
Ora ci concentriamo sulla creazione dei modelli e la previsione della temperatura massima, ma la parte di codice relativa alla temperatura minima e alle precipitazioni cumulate sarà del tutto simile e potrete visionarla scaricando il file completo alla fine di questa pagina.
Creiamo i due set di dati X (dati indipendenti, su cui basare la previsione, quindi tutti i campi visti finora senza le colonne obiettivo oggetto di previsione) e y (dati dipendenti, che vogliamo prevedere, in questo caso la temperatura massima obiettivo).
In particolare andiamo a creare quattro insiemi, ovvero i dati di allenamento per x e y (X_train e Y_train) ed i dati di test per x e y (X_test e Y_test).
L’insieme di training (pari all’80% dei dati) allena il modello mentre l’insieme di test (pari al 20% dei dati) ne misura l’efficacia.
X = wheather.drop(["target_tmax", "target_tmin", "target_precipitazioni_cumulate"], axis=1) #array con tutte le colonne tranne le colonne target_tmax, target_tmin, target_precipitazioni_cumulate
y = wheather["target_tmax"] #array con i valori della colonna target_tmax
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
#la funzione train_test_split crea i dati di allenamento e test per x e y (X_train, X_test, Y_train, Y_test)
#L'INSIEME DI TRAINING ALLENA IL MODELLO MENTRE L'INSIEME DI TEST NE MISURA L'EFFICACIA
#impostiamo random_state = 42 così da poter ripetere i test e poterli confrontare
#test_size=0.2 significa che i dati del test rappresentano il 20% dei dati totali (divisione modello 80/20)
print("\nElementi per il training (80%):")
print(X_train.shape) #stampa il numero di elementi in ciascuna dimensione (80%)
print("\nElementi per il test (20%):")
print(X_test.shape) #stampa il numero di elementi in ciascuna dimensione (20%)
print("\n")
Ora che i nostri dati sono pronti per essere analizzati, inizializziamo e addestriamo i modelli:
#inizializza i modelli
modello_DecisionTreeRegressor = DecisionTreeRegressor()
modello_RandomForestRegressor = RandomForestRegressor()
modello_GradientBoostingRegressor = GradientBoostingRegressor()
modello_LinearRegression = LinearRegression()
modello_ElasticNet = ElasticNet()
modello_SVR = SVR()
modello_CatBoostRegressor = CatBoostRegressor()
modello_XGBRegressor = XGBRegressor()
#addestramento dei modelli
modello_DecisionTreeRegressor.fit(X_train, y_train)
modello_RandomForestRegressor.fit(X_train, y_train)
modello_GradientBoostingRegressor.fit(X_train, y_train)
modello_LinearRegression.fit(X_train, y_train)
modello_ElasticNet.fit(X_train, y_train)
modello_SVR.fit(X_train, y_train)
modello_CatBoostRegressor.fit(X_train, y_train)
modello_XGBRegressor.fit(X_train, y_train)
Calcoliamo per ogni modello l’errore assoluto medio che rappresenta l’errore di previsione medio e l’errore quadratico medio che rappresenta la “dispersione” degli errori:
#calcolo errori quadratici medi per la parte di TRAINING
errore_quadratico_medio_training_DecisionTreeRegressor = mean_squared_error(y_train, modello_DecisionTreeRegressor.predict(X_train))
errore_quadratico_medio_training_RandomForestRegressor = mean_squared_error(y_train, modello_RandomForestRegressor.predict(X_train))
errore_quadratico_medio_training_GradientBoostingRegressor = mean_squared_error(y_train, modello_GradientBoostingRegressor.predict(X_train))
errore_quadratico_medio_training_LinearRegression = mean_squared_error(y_train, modello_LinearRegression.predict(X_train))
errore_quadratico_medio_training_ElasticNet = mean_squared_error(y_train, modello_ElasticNet.predict(X_train))
errore_quadratico_medio_training_SVR = mean_squared_error(y_train, modello_SVR.predict(X_train))
errore_quadratico_medio_training_CatBoostRegressor = mean_squared_error(y_train, modello_CatBoostRegressor.predict(X_train))
errore_quadratico_medio_training_XGBRegressor = mean_squared_error(y_train, modello_XGBRegressor.predict(X_train))
#calcolo errori assoluti medi per la parte di TRAINING
errore_assoluto_medio_training_DecisionTreeRegressor = mean_absolute_error(y_train, modello_DecisionTreeRegressor.predict(X_train))
errore_assoluto_medio_training_RandomForestRegressor = mean_absolute_error(y_train, modello_RandomForestRegressor.predict(X_train))
errore_assoluto_medio_training_GradientBoostingRegressor = mean_absolute_error(y_train, modello_GradientBoostingRegressor.predict(X_train))
errore_assoluto_medio_training_LinearRegression = mean_absolute_error(y_train, modello_LinearRegression.predict(X_train))
errore_assoluto_medio_training_ElasticNet = mean_absolute_error(y_train, modello_ElasticNet.predict(X_train))
errore_assoluto_medio_training_SVR = mean_absolute_error(y_train, modello_SVR.predict(X_train))
errore_assoluto_medio_training_CatBoostRegressor = mean_absolute_error(y_train, modello_CatBoostRegressor.predict(X_train))
errore_assoluto_medio_training_XGBRegressor = mean_absolute_error(y_train, modello_XGBRegressor.predict(X_train))
#calcolo errori quadratici medi per la parte di TEST
errore_quadratico_medio_test_DecisionTreeRegressor = mean_squared_error(y_test, modello_DecisionTreeRegressor.predict(X_test))
errore_quadratico_medio_test_RandomForestRegressor = mean_squared_error(y_test, modello_RandomForestRegressor.predict(X_test))
errore_quadratico_medio_test_GradientBoostingRegressor = mean_squared_error(y_test, modello_GradientBoostingRegressor.predict(X_test))
errore_quadratico_medio_test_LinearRegression = mean_squared_error(y_test, modello_LinearRegression.predict(X_test))
errore_quadratico_medio_test_ElasticNet = mean_squared_error(y_test, modello_ElasticNet.predict(X_test))
errore_quadratico_medio_test_SVR = mean_squared_error(y_test, modello_SVR.predict(X_test))
errore_quadratico_medio_test_CatBoostRegressor = mean_squared_error(y_test, modello_CatBoostRegressor.predict(X_test))
errore_quadratico_medio_test_XGBRegressor = mean_squared_error(y_test, modello_XGBRegressor.predict(X_test))
#calcolo errori assoluti medi per la parte di TEST
errore_assoluto_medio_test_DecisionTreeRegressor = mean_absolute_error(y_test, modello_DecisionTreeRegressor.predict(X_test))
errore_assoluto_medio_test_RandomForestRegressor = mean_absolute_error(y_test, modello_RandomForestRegressor.predict(X_test))
errore_assoluto_medio_test_GradientBoostingRegressor = mean_absolute_error(y_test, modello_GradientBoostingRegressor.predict(X_test))
errore_assoluto_medio_test_LinearRegression = mean_absolute_error(y_test, modello_LinearRegression.predict(X_test))
errore_assoluto_medio_test_ElasticNet = mean_absolute_error(y_test, modello_ElasticNet.predict(X_test))
errore_assoluto_medio_test_SVR = mean_absolute_error(y_test, modello_SVR.predict(X_test))
errore_assoluto_medio_test_CatBoostRegressor = mean_absolute_error(y_test, modello_CatBoostRegressor.predict(X_test))
errore_assoluto_medio_test_XGBRegressor = mean_absolute_error(y_test, modello_XGBRegressor.predict(X_test))
Raccogliamo gli errori in una tabella e stampiamo a video i valori calcolati così da poter visionare quale è il modello migliore per la previsione della temperatura massima:
tabella_errori = [
["", "Err. quadratico medio training", "Err. assoluto medio training", "Err. quadratico medio test", "Err. assoluto medio test"],
["Decision Tree Regressor", errore_quadratico_medio_training_DecisionTreeRegressor, errore_assoluto_medio_training_DecisionTreeRegressor, errore_quadratico_medio_test_DecisionTreeRegressor, errore_assoluto_medio_test_DecisionTreeRegressor],
["Random Forest Regressor", errore_quadratico_medio_training_RandomForestRegressor, errore_assoluto_medio_training_RandomForestRegressor, errore_quadratico_medio_test_RandomForestRegressor, errore_assoluto_medio_test_RandomForestRegressor],
["Gradient Boosting Regressor", errore_quadratico_medio_training_GradientBoostingRegressor, errore_assoluto_medio_training_GradientBoostingRegressor, errore_quadratico_medio_test_GradientBoostingRegressor, errore_assoluto_medio_test_GradientBoostingRegressor],
["Linear Regression", errore_quadratico_medio_training_LinearRegression, errore_assoluto_medio_training_LinearRegression,errore_quadratico_medio_test_LinearRegression , errore_assoluto_medio_test_LinearRegression],
["Elastic Net", errore_quadratico_medio_training_ElasticNet, errore_assoluto_medio_training_ElasticNet,errore_quadratico_medio_test_ElasticNet, errore_assoluto_medio_test_ElasticNet],
["SVR", errore_quadratico_medio_training_SVR, errore_assoluto_medio_training_SVR, errore_quadratico_medio_test_SVR, errore_assoluto_medio_test_SVR],
["Cat Boost Regressor", errore_quadratico_medio_training_CatBoostRegressor, errore_assoluto_medio_training_CatBoostRegressor, errore_quadratico_medio_test_CatBoostRegressor, errore_assoluto_medio_test_CatBoostRegressor],
["XGB Regressor", errore_quadratico_medio_training_XGBRegressor, errore_assoluto_medio_training_XGBRegressor, errore_quadratico_medio_test_XGBRegressor, errore_assoluto_medio_test_XGBRegressor]
]
tabella = pandas.DataFrame(tabella_errori)
print("\n")
print(tabella) #stampa la tabella di tutti gli errori calcolati
print("\n")
Il modello Random Forest Regressor sembra essere il modello con errori assoluto e quadratico medi più bassi nella fase di test per la previsione della temperatura massima. Calcoliamo quindi la temperatura massima prevista per il giorno da elaborare utilizzando il modello Random Forest Regressor. Inoltre ricaviamo quale sarebbe stato il valore target della temperatura massima per quel giorno per verificare di quanto il modello si è allontanato rispetto alla realtà.
#calcolo del valore previsto
giorno_da_elaborare = X.loc[X['data'] == giorno_selezionato] #elabora il giorno precedente che ha come target il valore del giorno dopo
temperatura_max_prevista = round(modello_RandomForestRegressor.predict(giorno_da_elaborare)[0], 2)
#calcolo del valore target per il confronto
giorno_da_elaborare = wheather.loc[wheather['data'] == giorno_selezionato]
temperatura_max_target = round(giorno_da_elaborare.iloc[0]["target_tmax"], 2)
print("Il giorno", giorno_da_elaborare.iloc[0]["data"], "la temperatura massima obiettivo per il giorno seguente era", temperatura_max_target, "°C")
print("Il sistema ha previsto una temperatura massima di", temperatura_max_prevista, "°C")
print("Il delta è pari a", round(temperatura_max_target-temperatura_max_prevista, 2), "°C")
print("\n")
Quanto appena visto va ripetuto ovviamente anche per la temperatura minima e le precipitazioni cumulate.
Una volta calcolati tutti i valori da prevedere non rimane altro che inviarli al database mysql tramite la pagina web aggiungi_previsione.php, i cui dettagli li vedremo nel capitolo 7 di questa guida.
#esegue la pagina web per caricare i dati nel database
url = "https://www.nome_sito.it/aggiungi_previsione.php?temperatura_max_prevista=" + str(temperatura_max_prevista) + "&temperatura_min_prevista=" + str(temperatura_min_prevista) + "&precipitazioni_cumulate_previste=" + str(precipitazioni_cumulate_previste)
print (url)
webUrl = urllib.request.urlopen(url)
if webUrl.getcode()==200 : #se la lettura è avvenuta con successo restituisce 200
print("\n")
print("Valori caricati correttamente nel database")
print("\n")
exit()
Il file contenente il codice completo è disponibile cliccando qui ma ricordate di modificare i valori relativi al vostro sito web che ospita la pagina aggiungi_previsione.php.
