Monitorare i dati e i modelli nelle operazioni delle compagnie aeree con Evidently & Streamlit in produzione.

Analizzare i dati e i modelli nelle operazioni delle compagnie aeree con Evidently & Streamlit in produzione.

Introduzione

Hai mai provato la frustrazione di un modello ben funzionante nell’addestramento e nella valutazione che si comporta peggio nell’ambiente di produzione? È una sfida comune affrontata nella fase di produzione, ed è qui che entra in gioco Evidently.ai, uno strumento open source fantastico che rende il nostro modello di apprendimento automatico osservabile e facile da monitorare. Questa guida coprirà le ragioni dei cambiamenti nei dati e nelle prestazioni del modello nell’ambiente di produzione e le azioni necessarie per implementarle. Impareremo anche come integrare questo strumento con l’app di previsione Streamlit. Iniziamo il nostro straordinario viaggio.

Questo articolo è stato pubblicato come parte del Data Science Blogathon.

Prerequisiti necessari

1) Clonare il repository

git clone "https://github.com/VishalKumar-S/Flight-Delay-Prediction-and-live-Monitoring-with-Azure-Evidently-and-Streamlit-with-MVC-Architecture.git"

2) Creare e attivare l’ambiente virtuale

#crea un ambiente virtualepython3 -m venv venv#Attiva il tuo ambiente virtuale nella cartella del tuo progettosource venv/bin/activate

# Questo comando installa i pacchetti Python elencati nel file requirements.txtpip install -r requirements.txt

4) Installa Streamlit ed Evidently

pip install streamlitpip install evidently

Struttura del progetto:

project_root/│├── assets/│├── data/│   └── Monitoring_data.csv│├── models/│   ├── best_model.pkl│   ├── lightgml_model.pkl│   ├── linear_regression_model.pkl│   ├── random_forest_model.pkl│   ├── ridge_regression.pkl│   ├── svm_model.pkl│   └── xgboost_model.pkl│├── notebooks/│   └── EDA.ipynb│├── src/│   ├── controller/│   │   └── flight_delay_controller.py│   ││   ├── model/│   │   └── flight_delay_model.py│   ││   ├── view/│   │   └── flight_delay_view.py│   ││   ├── data_preprocessing.py│   ├── model_evaluation.py│   └── modeling.py│├── .gitignore├── Dockerfile├── LICENSE├── Readme.md├── app.py└── requirements.txt

Preprocessing dei dati

Recupero dal Cloud

In questo progetto, recupereremo il dataset da Azure. Prima creeremo un contenitore di archiviazione in Azure, quindi uno storage di blob, quindi caricheremo il nostro dataset grezzo lì, lo renderemo accessibile al pubblico e lo utilizzeremo per future operazioni di preprocessing dei dati.

Link del dataset: https://www.kaggle.com/datasets/giovamata/airlinedelaycauses

Ecco lo snippet di codice per recuperare dal cloud:

class DataPreprocessorTemplate:    """    Pattern del metodo template per il preprocessing dei dati con passaggi personalizzabili.    """    def __init__(self, data_url):        """        Inizializza il template DataPreprocessor con l'URL dei dati incluso il token SAS.        Args:            data_url (str): L'URL dei dati con il token SAS.        """        self.data_url = data_url    def fetch_data(self):        """        Recupera i dati da Azure Blob Storage.        Returns:            pd.DataFrame: Il dataset recuperato come DataFrame Pandas.        """        try:            # Recupera il dataset utilizzando l'URL fornito            print("Recupero dei dati dal cloud...")            data = pd.read_csv(self.data_url)            return data        except Exception as e:            raise Exception("Si è verificato un errore durante il recupero dei dati: " + str(e))def main():  # URL dei dati incluso il token SAS  data_url = "https://flightdelay.blob.core.windows.net/flight-delayed-dataset/DelayedFlights.csv"  output_path = "../data/cleaned_flight_delays.csv"  data_preprocessor = DataPreprocessorTemplate(data_url)  data = data_preprocessor.fetch_data()  cleaned_data=data_preprocessor.clean_data(data)  data_preprocessor.save_cleaned_data(cleaned_data, output_path)    

Azure Immagine:

Pulizia e Trasformazione dei Dati

Nel mondo dei dati, la trasformazione dei dati trasforma i diamanti grezzi in quelli lucidati. Qui, procederemo con tutti i passaggi di preelaborazione dei dati, come la rimozione delle caratteristiche non desiderate, la sostituzione dei valori mancanti, la codifica delle colonne categoriche e la rimozione degli outlier. Qui abbiamo implementato la codifica dummy. Quindi, rimuoveremo gli outlier utilizzando il test dello Z-score.

Snippet di codice per la pulizia dei dati:

def clean_data(self, df):        """        Pulisci e preelabora i dati di input.        Args:            df (pd.DataFrame): Il dataset di input.        Returns:            pd.DataFrame: Il dataset pulito e preelaborato.        """        print("Pulizia dei dati...")        df = self.remove_features(df)        df = self.impute_missing_values(df)        df = self.encode_categorical_features(df)        df = self.remove_outliers(df)        return df    def remove_features(self, df):        """        Rimuovi colonne non necessarie dal dataset.        Args:            df (pd.DataFrame): Il dataset di input.        Returns:            pd.DataFrame: Il dataset con le colonne non necessarie rimosse.        """        print("Rimozione delle colonne non necessarie...")        df = df.drop(['Unnamed: 0','Year','CancellationCode','TailNum','Diverted','Cancelled','ArrTime','ActualElapsedTime'], axis=1)        return df    def impute_missing_values(self, df):        """        Sostituisci i valori mancanti nel dataset.        Args:            df (pd.DataFrame): Il dataset di input.        Returns:            pd.DataFrame: Il dataset con i valori mancanti sostituiti.        """        print("Sostituzione dei valori mancanti...")        delay_colns=['CarrierDelay', 'WeatherDelay', 'NASDelay', 'SecurityDelay', 'LateAircraftDelay']        # Sostituisci i valori mancanti con 0 per queste colonne        df[delay_colns]=df[delay_colns].fillna(0)        # Sostituisci i valori mancanti con la mediana per queste colonne        columns_to_impute = ['AirTime', 'ArrDelay', 'TaxiIn','CRSElapsedTime']        df[columns_to_impute]=df[columns_to_impute].fillna(df[columns_to_impute].median())        return df    def encode_categorical_features(self, df):        """        Codifica le caratteristiche categoriche nel dataset.        Args:            df (pd.DataFrame): Il dataset di input.        Returns:            pd.DataFrame: Il dataset con le caratteristiche categoriche codificate.        """        print("Codifica delle caratteristiche categoriche...")        df=pd.get_dummies(df, columns=['UniqueCarrier', 'Origin', 'Dest'], drop_first=True)        return df    def remove_outliers(self, df):        """        Rimuovi gli outlier dal dataset.        Args:            df (pd.DataFrame): Il dataset di input.        Returns:            pd.DataFrame: Il dataset con gli outlier rimossi.        """        print("Rimozione degli outlier...")        z_threshold=3        z_scores=np.abs(stats.zscore(df[self.numerical_columns]))        outliers=np.where(z_scores>z_threshold)        df_no_outliers=df[(z_scores<=z_threshold).all(axis=1)]        print("Forma dopo la pulizia dei dati:", df_no_outliers.shape)        return df_no_outliers

Quindi, salveremo il dataset pulito per i nostri futuri scopi di addestramento e valutazione del modello. Utilizzeremo joblib per salvare il dataset pulito.

Ecco lo snippet di codice:

def save_cleaned_data(self, cleaned_data, output_path):    """    Salva i dati puliti in un file CSV.    Args:        cleaned_data (pd.DataFrame): Il dataset pulito.        output_path (str): Il percorso per salvare i dati puliti.    """    print("Salvataggio dei dati puliti...")                cleaned_data.to_csv(output_path, index=False)

Formazione e Valutazione

Dopo la pulizia dei dati, divideremo il nostro dataset in 2 componenti: il set di addestramento e il set di test. Quindi, addestreremo più modelli di regressione come la regressione lineare, il regressore Random Forest, xgboost, la regressione ridge e i modelli lightgbm. Quindi, salveremo tutti i file come file .pkl utilizzando joblib, che riduce il tempo e ottimizza l’utilizzo di risorse aggiuntive.

Ora, possiamo utilizzare questo file di modello addestrato per scopi di valutazione e previsione. Quindi, valuteremo il modello in base a metriche di valutazione come il punteggio R2, il valore MAE (Errore Assoluto Medio) e il valore RMSE (Errore Quadrato Medio). Quindi, salva il modello che ha prestazioni migliori per usarlo per la distribuzione.

Snippet di codice per l’addestramento del modello:

# Funzione per creare modelli di machine learningdef create_model(model_name):    if model_name == "random_forest":        return RandomForestRegressor(n_estimators=50, random_state=42)    elif model_name == "linear_regression":        return LinearRegression()    elif model_name == "xgboost":        return xgb.XGBRegressor()    elif model_name == "ridge_regression":        return Ridge(alpha=1.0)  # Regolare alpha secondo necessità    elif model_name == "lightgbm":        return lgb.LGBMRegressor()# Carica il dataset pulitoprint("Inizio caricamento del modello...")cleaned_data = pd.read_csv("../data/cleaned_flight_delays.csv")print("Caricamento del modello completato")# Definisci la variabile target (ArrDelay) e le caratteristiche (X)target_variable = "ArrDelay"X = cleaned_data.drop(columns=[target_variable])y = cleaned_data[target_variable]# Dividi i dati in set di addestramento e testprint("Divisone dei dati in set di addestramento e test...")X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)print("Divisone dei dati completata.")

# Funzione per addestrare e salvare un modellodef train_and_save_model(model_name, X_train, y_train):    model = create_model(model_name)    print(f"Addestramento del modello {model_name}...")    start_time = time.time()    model.fit(X_train, y_train)    print("Addestramento del modello completato...")    end_time = time.time()    elapsed_time = end_time - start_time    print(f"Tempo di addestramento impiegato: {elapsed_time:.2f} secondi")    # Salva il modello addestrato per un uso successivo    joblib.dump(model, f"../models/{model_name}_model.pkl")    print(f"Modello {model_name} salvato come {model_name}_model.pkl")# Crea ed addestra il modello Random Foresttrain_and_save_model("random_forest", X_train, y_train)# Addestra il modello di regressione linearetrain_and_save_model("linear_regression", X_train, y_train)# Crea ed addestra il modello XGBoosttrain_and_save_model("xgboost", X_train, y_train)# Crea ed addestra il modello di regressione ridge train_and_save_model("ridge_regression", X_train, y_train)# Crea ed addestra il modello lightgbmtrain_and_save_model("lightgbm", X_train, y_train)

Snippet di codice per la valutazione del modello

# Carica il dataset pulitocleaned_data = pd.read_csv("../data/cleaned_flight_delays.csv")# Carica i modelli di machine learning addestratirandom_forest_model = joblib.load("../models/random_forest_model.pkl")linear_regression_model = joblib.load("../models/linear_regression_model.pkl")xgboost_model = joblib.load("../models/xgboost_model.pkl")ridge_regression_model = joblib.load("../models/ridge_regression_model.pkl")lightgbm_model = joblib.load("../models/lightgbm_model.pkl")# Definisci la variabile target (ArrDelay) e le caratteristiche (X)target_variable = "ArrDelay"X = cleaned_data.drop(columns=[target_variable])y = cleaned_data[target_variable]# Dividi i dati in set di addestramento e testX_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)# Definisci una funzione per valutare i modellify_pred = model.predict(X_test) mae = mean_absolute_error(y_test, y_pred) mse = mean_squared_error(y_test, y_pred) r2 = r2_score(y_test, y_pred) return mae, mse, r2# Crea un dizionario di modelli da valutaremodels = {    "Random Forest": random_forest_model,    "Regressione Lineare": linear_regression_model,    "XGBoost": xgboost_model,    "Ridge Regression": ridge_regression_model,    "LightGBM": lightgbm_model,}# Valuta ogni modello e memorizza le metrichemetrics = {}for model_name, model in models.items():    mae, mse, r2 = evaluate_model(model, X_test, y_test)    metrics[model_name] = {"MAE": mae, "MSE": mse, "R2": r2}# Stampa le metriche di valutazione per tutti i modellifor model_name, model_metrics in metrics.items():    print(f"Metriche per {model_name}:")    print(f"Errore Assoluto Medio (MAE): {model_metrics['MAE']:.2f}")    print(f"Errore Quadratico Medio (MSE): {model_metrics['MSE']:.2f}")    print(f"R^2 Score: {model_metrics['R2']:.2f}")    print()

Dopo la valutazione, sceglieremo il miglior modello di distribuzione.

Snippet di codice per salvare e stampare il miglior modello:

# Trova il miglior modello in base al punteggio R2best_model = max(metrics, key=lambda model: metrics[model]["R2"])# Stampa i risultatiprint(f"Il miglior modello tra tutti i modelli addestrati è {best_model} con le seguenti metriche:")print(f"Errore assoluto medio (MAE): {metrics[best_model]['MAE']}")print(f"Errore quadratico medio (MSE): {metrics[best_model]['MSE']}")print(f"Punteggio R-quadrato (R2): {metrics[best_model]['R2']}")# Salva il miglior modello per un uso futurojoblib.dump(models[best_model], "../models/best_model.pkl")print("Miglior modello salvato come best_model.pkl")

Output:

A quanto pare: per il monitoraggio dei dati e del modello

Nell’ambiente di produzione, possono verificarsi vari problemi con il corretto funzionamento del modello. Alcune delle considerazioni principali sono:

  1. Sfasamento tra formazione e servizio: Ciò accade quando c’è una differenza significativa tra i dati che utilizziamo per la formazione e gli esperimenti.
  2. Problemi di qualità e integrità dei dati: Potrebbero esserci problemi di elaborazione dei dati come – pipeline interrotte, problemi di infrastruttura, modifiche allo schema dei dati o altri problemi dati provenienti dalla fonte.
  3. Modello precedente non funzionante: Nell’ambiente di produzione, i modelli spesso formano una catena, in cui l’input di un modello dipende dall’output dell’altro. Quindi, eventuali problemi nell’output di un modello influenzeranno la previsione complessiva del modello.

4. Cambiamento graduale dei concetti: Nel tempo, potrebbero verificarsi cambiamenti nel concetto su cui stiamo lavorando (o) le variabili target cambiano, quindi è necessario il monitoraggio. Potrebbero esserci anche situazioni impreviste in cui il monitoraggio è cruciale e le nostre previsioni del modello possono essere errate. Ad esempio, catastrofi/natural calamities.

Per valutare la qualità dei dati e del modello, considereremo 2 set di dati: il set di dati di riferimento e il set di dati attuale.

Set di dati di riferimento: questo set di dati è un punto di riferimento per le metriche di qualità del set di dati attuale. Anche se Evidently sceglie i valori di soglia predefiniti, basandosi sul nostro set di dati di riferimento, possiamo anche fornire valori di soglia delle metriche personalizzate in base alle nostre esigenze specifiche.

Set di dati attuale: rappresenta i dati sconosciuti e in tempo reale utilizzati per la valutazione.

Calcoleremo gli eports di drift dei dati, drift degli obiettivi, qualità dei dati e delle prestazioni del modello con questi due set di dati.

Le relazioni copriranno gli eports di drift dei dati, drift degli obiettivi, qualità dei dati e delle prestazioni del modello. Di solito, il monitoraggio avviene a intervalli specifici in batch.

Aspetti da considerare prima di riassegnare il modello:

1. Controlla l’eventuale drift dei dati: Se viene rilevato uno drift dei dati, è consigliabile controllare prima la qualità dei dati e verificare se ci sono fattori esterni che influenzano lo drift, come pandemie e calamità naturali.

2. Valuta le prestazioni del modello: Considera le prestazioni del modello dopo aver affrontato i problemi di drift dei dati. Se i rapporti sui dati e sul modello mostrano del drift, potrebbe essere una buona idea riassegnare il modello. Prima di prendere questa decisione, considera il terzo punto.

3. Considerazioni sulla riassegnazione: La riassegnazione non è sempre la soluzione. Non avremo abbastanza nuovi dati per riassegnare il modello in molte situazioni. Sii prudente nella formazione con nuovi dati poiché ci sono anche possibilità che i dati siano instabili e sbagliati per motivi specifici.

4. Impostare avvisi per lo drift dei dati: Prima di impostare avvisi per gli drift dei dati, analizza l’importanza di quel dato/caratteristica specifico sulla previsione. Non tutti gli drift dei dati sono importanti e richiedono azioni. Analizza sempre l’importanza dell’influenza di ciascuna caratteristica sulla previsione.

I report possono essere generati in vari formati, come HTML, JPEG, JSON, ecc. Vediamo insieme lo snippet di codice per generare i report.

Snippet di codice per il report delle performance del modello

# Creazione del report delle performance di regressione
regression_performance_report = Report(metrics=[RegressionPreset()])

# Esecuzione del report delle performance di regressione
regression_performance_report.run(
    reference_data=reference,  # Dataset di riferimento per il confronto
    current_data=current.loc[CUR_WEEK_START:CUR_WEEK_END],  # Dataset corrente per l'analisi
    column_mapping=column_mapping  # Mappatura tra le colonne nei dataset di riferimento e corrente
)

# Specifica del percorso per salvare il report delle performance del modello in formato HTML
model_performance_report_path = reports_dir / 'model_performance.html'

# Salvataggio del report delle performance di regressione come file HTML
regression_performance_report.save_html(model_performance_report_path)

Snippet di codice per il target drift

# Creazione del report per il target drift
target_drift_report = Report(metrics=[TargetDriftPreset()])

# Esecuzione del report per il target drift
target_drift_report.run(
    reference_data=reference,  # Dataset di riferimento per il confronto
    current_data=current.loc[CUR_WEEK_START:CUR_WEEK_END],  # Dataset corrente per l'analisi
    column_mapping=column_mapping  # Mappatura tra le colonne nei dataset di riferimento e corrente
)

# Specifica del percorso per salvare il report per il target drift in formato HTML
target_drift_report_path = reports_dir / 'target_drift.html'

# Salvataggio del report per il target drift come file HTML
target_drift_report.save_html(target_drift_report_path)

Data Drift

# Creazione di un oggetto per la mappatura delle colonne
column_mapping = ColumnMapping()
column_mapping.numerical_features = numerical_features  # Definizione delle features numeriche per la mappatura

# Creazione del report per il data drift
data_drift_report = Report(metrics=[DataDriftPreset()])

# Esecuzione del report per il data drift
data_drift_report.run(
    reference_data=reference,  # Dataset di riferimento per il confronto
    current_data=current.loc[CUR_WEEK_START:CUR_WEEK_END],  # Dataset corrente per l'analisi
    column_mapping=column_mapping  # Mappatura tra le features numeriche nei dataset di riferimento e corrente
)

# Specifica del percorso per salvare il report per il data drift in formato HTML
data_drift_report_path = reports_dir / 'data_drift.html'

# Salvataggio del report per il data drift come file HTML
data_drift_report.save_html(data_drift_report_path)

# Creazione di un oggetto per la mappatura delle colonne
column_mapping = ColumnMapping()
column_mapping.numerical_features = numerical_features
data_drift_report = Report(metrics=[DataDriftPreset()])
data_drift_report.run(
    reference_data=reference,
    current_data=current.loc[CUR_WEEK_START:CUR_WEEK_END],
    column_mapping=column_mapping
)
data_drift_report_path = reports_dir / 'data_drift.html'
data_drift_report.save_html(data_drift_report_path)

Snippet di codice per la data quality

# Creazione di un oggetto per la mappatura delle colonne
column_mapping = ColumnMapping()
column_mapping.numerical_features = numerical_features  # Definizione delle features numeriche per la mappatura

# Creazione del report per la data quality
data_quality_report = Report(metrics=[DataQualityPreset()])

# Esecuzione del report per la data quality
data_quality_report.run(
    reference_data=reference,  # Dataset di riferimento per il confronto
    current_data=current.loc[CUR_WEEK_START:CUR_WEEK_END],  # Dataset corrente per l'analisi
    column_mapping=column_mapping  # Mappatura tra le features numeriche nei dataset di riferimento e corrente
)

# Specifica del percorso per salvare il report per la data quality in formato HTML
data_quality_report_path = reports_dir / 'data_quality.html'

# Salvataggio del report per la data quality come file HTML
data_quality_report.save_html(data_quality_report_path)

Esplora l’architettura Model-View-Controller (MVC)

In questa sezione impareremo l’architettura Model-View-Controller (MVC):

L’architettura Model-View-Controller (MVC) è un pattern di design utilizzato nelle applicazioni web. Serve a semplificare la complessità del codice e migliorare la leggibilità. Vediamo i suoi componenti.

Modello: La Logica

Il componente Modello rappresenta la logica principale della nostra applicazione. Si occupa dell’elaborazione dei dati e delle interazioni con i modelli di machine learning. Lo script del Modello si trova nella directory src/model/.

Vista: Creazione delle Interfacce Utente

Il componente Vista è responsabile della creazione dell’interfaccia utente. Interagisce con l’utente e visualizza le informazioni. Lo script della Vista si trova nella directory src/view/.

Controller: L’Orchestratore

Il componente Controller funge da ponte intermedio tra i componenti Modello e Vista. Gestisce gli input e le richieste dell’utente. Lo script del Controller si trova nella directory src/controller/.

Diagramma MVC:

Di seguito è riportata una rappresentazione visiva dell’architettura MVC:

Vediamo il frammento di codice per prevedere ritardi nell’architettura MVC:

1) Modello (flight_delay_model.py):

# Importa le librerie e i moduli necessarimport pandas as pdimport joblibimport xgboost as xgbfrom typing import Dictclass FlightDelayModel:    def __init__(self, model_file="models/best_model.pkl"):        """        Inizializza il FlightDelayModel.        Args:            model_file (str): Percorso del file del modello addestrato.        """        # Carica il modello preaddestrato dal file fornito        self.model = joblib.load(model_file)    def predict_delay(self, input_data: Dict):        """        Prevedi il ritardo del volo basandoti sui dati in input.        Args:            input_data (Dict): Un dizionario contenente le caratteristiche in input per la previsione.        Returns:            float: Il ritardo del volo previsto.        """        # Converte il dizionario dei dati in input in un DataFrame per la previsione        input_df = pd.DataFrame([input_data])        # Utilizza il modello preaddestrato per effettuare una previsione        prediction = self.model.predict(input_df)        return prediction

2) Vista (flight_delay_view.py):

import streamlit as stfrom typing import Dictclass FlightDelayView:    def display_input_form(self):        """        Mostra il modulo di input nella barra laterale Streamlit per permettere agli utenti di inserire i dati.        """        st.sidebar.write("Valori di input:")        # Parte di codice per creare gli elementi del modulo di input    def display_selected_inputs(self, selected_data: Dict):        """        Mostra i valori di input selezionati in base all'input dell'utente.        Args:            selected_data (Dict): Un dizionario contenente i valori di input selezionati.        Returns:            Dict: Lo stesso dizionario con i valori selezionati per riferimento.        """        # Parte di codice per visualizzare i valori di input selezionati        # Mostra i valori di input selezionati, come slider, input numerici e select box        return selected_data    def display_predicted_delay(self, flight_delay):        """        Mostra il ritardo del volo previsto all'utente.        Args:            flight_delay: Il valore del ritardo del volo previsto.        """        # Parte di codice per mostrare il ritardo previsto        # Mostra il valore del ritardo del volo previsto all'utente

3) Controller (flight_delay_controller.py):

import streamlit as stfrom src.view.flight_delay_view import FlightDelayViewfrom src.model.flight_delay_model import FlightDelayModelfrom typing import Dictclass FlightDelayController:    def __init__(self):        self.model = FlightDelayModel()        self.view = FlightDelayView()        self.selected_data = self.model.selected_data()    def run_prediction(self):        # Mostra il modulo di input, raccoglie i dati inseriti dall'utente e mostra i valori selezionati        self.view.display_input_form()        input_data = self.get_user_inputs()        self.view.display_selected_inputs(input_data)        if st.button("Prevedi ritardo del volo"):            # Quando viene cliccato il pulsante di previsione, prevedi il ritardo del volo e mostra il risultato            flight_delay = self.model.predict_delay(input_data)            self.view.display_predicted_delay(flight_delay)    def get_user_inputs(self):        # Parte di codice per raccogliere i dati inseriti dall'utente dalla barra laterale di Streamlit.        user_inputs = {}        # Crea un dizionario vuoto per memorizzare i dati inseriti dall'utente        # Puoi utilizzare i widget della barra laterale di Streamlit per raccogliere i dati inseriti dall'utente, ad esempio st.sidebar.slider, st.sidebar.selectbox, ecc.        # Qui puoi aggiungere il codice per raccogliere i dati inseriti dall'utente e popolare il dizionario 'user_inputs'.        # Esempio:        # user_inputs['selected_feature'] = st.sidebar.slider("Seleziona caratteristica", min_value, max_value, default_value)        # Ripeti questo per ogni input utente che desideri raccogliere.        return user_inputs        # Restituisce il dizionario contenente i dati inseriti dall'utente

Integrazione di previsione e monitoraggio con Streamlit

Qui integreremo il monitoraggio di Evidently con la previsione di Streamlit per consentire agli utenti di fare previsioni e monitorare i dati e il modello.

Questo approccio consente agli utenti di effettuare previsioni, monitorare o entrambi, scritti in modo coerente, seguendo il pattern di progettazione dell’architettura MVC.

Codice:

Frammento di codice per selezionare il dataset di riferimento e corrente, implementato in src/flight_delay_controller.py

# Importazione delle librerie necessarieimport streamlit as stimport pandas as pdimport timeclass FlightDelayController:    def run_monitoring(self):        # Titolo dell'applicazione Streamlit e introduzione        st.title("App di monitoraggio dati e modelli")        st.write("Ti trovi nell'App di monitoraggio dati e modelli. Seleziona l'intervallo di date e mesi dalla barra laterale e clicca 'Invia' per avviare l'addestramento e il monitoraggio del modello.")        # Permetti all'utente di scegliere l'intervallo di date preferito        new_start_month = st.sidebar.selectbox("Mese di inizio", range(1, 12), 1)        new_end_month = st.sidebar.selectbox("Mese di fine", range(1, 12), 1)        new_start_day = st.sidebar.selectbox("Giorno di inizio", range(1, 32), 1)        new_end_day = st.sidebar.selectbox("Giorno di fine", range(1, 32), 30)        # Se l'utente clicca il pulsante "Invia"        if st.button("Invia"):            st.write("Recupero dei tuoi dati del lotto corrente...")            # Misura il tempo impiegato per recuperare i dati            data_start = time.time()            df = pd.read_csv("data/Monitoring_data.csv")            data_end = time.time()            time_taken = data_end - data_start            st.write(f"Dati recuperati in {time_taken:.2f} secondi")            # Filtra i dati in base all'intervallo di date selezionato            date_range = (                (df['Mese'] >= new_start_month) & (df['Giorno'] >= new_start_day) &                (df['Mese'] <= new_end_month) & (df['Giorno'] <= new_end_day)            )            # Crea il dataset di riferimento e corrente dall'intervallo di date.            dati_di_riferimento = df[~date_range]            dati_correnti = df[date_range]

Dopo aver scelto i dataset di riferimento e correnti, genereremo rapporti per la deriva dei dati, la qualità dei dati, la qualità del modello e la deriva del target. Il codice per la generazione dei rapporti è diviso in 3 parti secondo la progettazione dell’architettura MVC. Vediamo il codice in questi 3 file.

Snippet di codice per flight_delay_Controller.py

import streamlit as stfrom src.view.flight_delay_view import FlightDelayViewfrom src.model.flight_delay_model import FlightDelayModelimport numpy as npimport pandas as pdfrom scipy import statsimport time# Controllerclass FlightDelayController:    """    Il componente Controller per l'app Flight Delay Prediction.    Questa classe coordina l'interazione tra i componenti Model e View.    """    def __init__(self):        # Inizializza il controller creando istanze del Model e View.        self.model = FlightDelayModel()        # Crea un'istanza del FlightDelayModel.        self.view = FlightDelayView()        # Crea un'istanza del FlightDelayView.        self.selected_data = self.model.selected_data()        # Ottieni i dati selezionati dal modello.        self.categorical_options = self.model.categorical_features()        # Ottieni le caratteristiche categoriche dal modello.    def run_monitoring(self):        # Funzione per eseguire l'applicazione di monitoraggio.        # Imposta il titolo e una breve descrizione.        st.title("Data & Model Monitoring App")        st.write("Ti trovi nell'app di monitoraggio dei dati e del modello. Seleziona la data e l'intervallo di mesi dalla barra laterale e clicca su 'Invia' per avviare l'addestramento e il monitoraggio del modello.")        # Seleziona quali rapporti generare utilizzando le caselle di controllo.        st.subheader("Seleziona i rapporti da generare")        generate_model_report = st.checkbox("Genera rapporto di performance del modello")        generate_target_drift = st.checkbox("Genera rapporto di deriva del target")        generate_data_drift = st.checkbox("Genera rapporto di deriva dei dati")        generate_data_quality = st.checkbox("Genera rapporto di qualità dei dati")        if st.button("Invia"):            # 'date_range' e 'df' non sono mostrati qui in quanto sono già stati mostrati nei frammenti di codice precedenti            # Dati di riferimento senza l'intervallo di date selezionato.            reference_data = df[~date_range]            # Dati correnti all'interno dell'intervallo di date selezionato.            current_data = df[date_range]            self.view.display_monitoring(reference_data, current_data)  # Mostra i dati di monitoraggio.            self.model.train_model(reference_data, current_data)  # Addestra il modello.            # Genera i rapporti selezionati e mostrali.            if generate_model_report:                st.write("### Rapporto di performance del modello")                st.write("Generazione del rapporto di performance del modello...")                performance_report = self.model.performance_report(reference_data, current_data)                self.view.display_report(performance_report, "Rapporto di performance del modello")            if generate_target_drift:                st.write("### Rapporto di deriva del target")                st.write("Generazione del rapporto di deriva del target...")                target_report = self.model.target_report(reference_data, current_data)                self.view.display_report(target_report, "Rapporto di deriva del target")            if generate_data_drift:                st.write("### Rapporto di deriva dei dati")                st.write("Generazione del rapporto di deriva dei dati...")                data_drift_report = self.model.data_drift_report(reference_data, current_data)                self.view.display_report(data_drift_report, "Rapporto di deriva dei dati")            if generate_data_quality:                st.write("### Rapporto di qualità dei dati")                st.write("Generazione del rapporto di qualità dei dati...")                data_quality_report = self.model.data_quality_report(reference_data, current_data)                self.view.display_report(data_quality_report, "Rapporto di qualità dei dati")

Codice per Flight_delay_model.py

import pandas as pdimport joblibimport xgboost as xgbfrom evidently.pipeline.column_mapping import ColumnMappingfrom evidently.report import Reportfrom evidently.metric_preset import DataDriftPresetfrom evidently.metric_preset import TargetDriftPresetfrom evidently.metric_preset import DataQualityPresetfrom evidently.metric_preset.regression_performance import RegressionPresetimport timeimport streamlit as stfrom typing import Dict# Modelclass FlightDelayModel:    """    Il componente Model per l'app Flight Delay Prediction.    Questa classe gestisce il caricamento dei dati, il caricamento del modello e le predizioni di ritardo.    """    def __init__(self, model_file="models/best_model.pkl"):        # Inizializza la classe FlightDelayModel        # Definisci il mapping delle colonne per l'analisi dei dati        self.column_mapping = ColumnMapping()        self.column_mapping.target = self.target        self.column_mapping.prediction = 'prediction'        self.column_mapping.numerical_features = self.numerical_features    # Rapporto di performance del modello    def performance_report(self, reference_data: pd.DataFrame, current_data: pd.DataFrame):        """        Genera un rapporto di performance per le predizioni del modello.        Args:            reference_data (pd.DataFrame): Dataset di riferimento per il confronto.            current_data (pd.DataFrame): Dataset corrente con le predizioni.        Returns:            Report: Un rapporto contenente le metriche di performance della regressione.        """        regression_performance_report = Report(metrics=[RegressionPreset()])        regression_performance_report.run(            reference_data=reference_data,            current_data=current_data,            column_mapping=self.column_mapping        )        return regression_performance_report    def target_report(self, reference_data: pd.DataFrame, current_data: pd.DataFrame):        """        Genera un rapporto per l'analisi della deriva del target.        Args:            reference_data (pd.DataFrame): Dataset di riferimento per il confronto.            current_data (pd.DataFrame): Dataset corrente con le predizioni.        Returns:            Report: Un rapporto contenente le metriche di deriva del target.        """        target_drift_report = Report(metrics=[TargetDriftPreset()])        target_drift_report.run(            reference_data=reference_data,            current_data=current_data,            column_mapping=self.column_mapping        )        return target_drift_report    def data_drift_report(self, reference_data: pd.DataFrame, current_data: pd.DataFrame):        """        Genera un rapporto per l'analisi della deriva dei dati.        Args:            reference_data (pd.DataFrame): Dataset di riferimento per il confronto.            current_data (pd.DataFrame): Dataset corrente con le predizioni.        Returns:            Report: Un rapporto contenente le metriche di deriva dei dati.        """        data_drift_report = Report(metrics=[DataDriftPreset()])        data_drift_report.run(            reference_data=reference_data,            current_data=current_data,            column_mapping=self.column_mapping        )        return data_drift_report    def data_quality_report(self, reference_data: pd.DataFrame, current_data: pd.DataFrame):        """        Genera un rapporto di qualità dei dati (nota: potrebbe richiedere circa 10 minuti).        Args:            reference_data (pd.DataFrame): Dataset di riferimento per il confronto.            current_data (pd.DataFrame): Dataset corrente con le predizioni.        Returns:            Report: Un rapporto contenente le metriche di qualità dei dati.        """        st.write("Generare il Rapporto di Qualità dei Dati richiederà più tempo, circa 10 minuti, a causa dell'analisi approfondita. Puoi aspettare o esplorare altri rapporti se hai poco tempo.")        data_quality_report = Report(metrics=[DataQualityPreset()])        data_quality_report.run(            reference_data=reference_data,            current_data=current_data,            column_mapping=self.column_mapping        )        return data_quality_report

Codice flight_delay_view.py

# Importa le librerie necessarie
import streamlit as st
import pandas as pd

# Definisci una classe per la visualizzazione dei ritardi dei voli
class FlightDelayView:
    """
    Componente di visualizzazione per l'applicazione di previsione dei ritardi dei voli.
    Questa classe gestisce la visualizzazione dell'applicazione web di Streamlit.
    """

    @staticmethod
    def display_input_form():
        """
        Visualizza il modulo di input sull'applicazione di Streamlit.
        """
        st.title("App di previsione dei ritardi dei voli")
        st.write("Questa app prevede l'estensione del ritardo dei voli in minuti.")
        st.sidebar.header("Inserimento utente")

    @staticmethod
    def display_monitoring(reference_data, current_data):
        """
        Visualizza informazioni di monitoraggio.
        Args:
            reference_data (DataFrame): Dataset di riferimento.
            current_data (DataFrame): Dataset corrente.
        """
        st.write("Si prega di scorrere verso il basso per vedere il tuo report")
        st.write("Forma Dataset di riferimento:", reference_data.shape)
        st.write("Forma Dataset Corrente:", current_data.shape)
        
        # Informazioni di addestramento del modello
        st.write("### Il modello sta addestrando...")

    @staticmethod
    def display_selected_inputs(selected_data):
        """
        Visualizza gli input utente selezionati.
        Args:
            selected_data (dict): Dati di input forniti dall'utente.
        """
        input_data = pd.DataFrame([selected_data])
        st.write("Input selezionati:")
        st.write(input_data)
        return input_data

    @staticmethod
    def display_predicted_delay(flight_delay):
        """
        Visualizza il ritardo previsto dei voli.
        Args:
            flight_delay (float): Ritardo previsto dei voli in minuti.
        """
        st.write("Ritardo di volo previsto (in minuti):", round(flight_delay[0], 2))

    @staticmethod
    def display_report(report, report_name: str):
        """
        Visualizza un report generato da Evidently.
        Args:
            report (Report): Il report di Evidently da visualizzare.
            report_name (str): Nome del report (ad esempio, "Rapporto delle prestazioni del modello").
        """
        st.write(f"{report_name}")
        # Visualizza il report di Evidently come HTML con lo scrolling abilitato
        st.components.v1.html(report.get_html(), height=1000, scrolling=True)

Ora, l’applicazione finale Streamlit è arrivata, in cui abbiamo integrato sia la previsione che il monitoraggio.

app.py

import streamlit as st
import pandas as pd
from src.controller.flight_delay_controller import FlightDelayController

def main():
    st.set_page_config(page_title="App di previsione dei ritardi dei voli", layout="wide")
    
    # Inizializza il controller
    controller = FlightDelayController()
    
    # Crea l'applicazione Streamlit
    st.sidebar.title("App per la previsione dei ritardi dei voli e il monitoraggio dei dati e del modello")
    choice = st.sidebar.radio("Seleziona un'opzione:", ("Effettua previsioni", "Monitora dati e modello"))
    
    if choice == "Effettua previsioni":
        controller.run_prediction()
    elif choice == "Monitora dati e modello":
        controller.run_monitoring()

if __name__ == '__main__':
    main()

Per eseguire l’applicazione Streamlit, esegui il seguente comando:

# Per eseguire l'applicazione, esegui il seguente comando
streamlit run app.py

Visita http://localhost:8501 nel tuo browser per utilizzare l’applicazione.

Dashboard di previsione:

Dashboard di monitoraggio:

Schiudere le intuizioni con i rapporti di Evidently

Rapporto di Deriva dei Dati:

Qui possiamo vedere il rapporto di deriva dei dati per il nostro progetto. Possiamo vedere che in questo caso ci sono 5 colonne derivate. Quindi, il nostro prossimo passo sarebbe analizzare le possibili cause di questa deriva delle caratteristiche con gli esperti di dominio corrispondenti.

Deriva del Target:

Qui, possiamo vedere lo spostamento del target; qui non viene rilevato alcuno spostamento.

Report sulle prestazioni del modello

Qui, possiamo vedere tutte le metriche di performance del nostro modello dopo aver analizzato il nuovo set di dati in blocco. Possiamo prendere le decisioni necessarie in base alle metriche.

Report sulla qualità dei dati

In generale, utilizziamo i report sulla qualità dei dati per i dati grezzi e non elaborati. Possiamo vedere tutte le metriche relative ai dati, come il numero di colonne, la correlazione, i valori duplicati, ecc. Possiamo anche implementarlo per effettuare un’analisi esplorativa dei dati.

Integrazione di Docker per il deployment:

Comprensione di Docker e la sua importanza:

È importante dockerizzare il nostro progetto per eseguirlo su qualsiasi ambiente senza problemi di dipendenza. Docker è uno strumento essenziale per il confezionamento e la distribuzione delle applicazioni. Ecco i passaggi per configurare ed utilizzare Docker per questo progetto.

Dockerfile:

Il Dockerfile nella nostra directory di progetto contiene le istruzioni per la creazione di un’immagine Docker. Scrivi il Dockerfile con la sintassi corretta.

Struttura del progetto Docker file:

Scrivere un Dockerfile efficiente

È essenziale avere una dimensione dell’immagine Docker il più ridotta possibile. Possiamo utilizzare tecniche come la multi-staging in Docker per ridurre la dimensione dell’immagine e utilizzare un’immagine di base molto leggera per Python.

Codice:

# Utilizza una versione ufficiale di Python come immagine principaleFROM python:3.9-slim# Imposta la directory di lavoro su /appWORKDIR /app# Crea le directory necessarieRUN mkdir -p /app/data /app/models /app/src/controller /app/src/model /app/src/view# Copia i file dalla tua macchina host nel containerCOPY app.py /app/COPY src/controller/flight_delay_controller.py /app/src/controller/COPY src/model/flight_delay_model.py /app/src/model/COPY src/view/flight_delay_view.py /app/src/view/COPY requirements.txt /app/# Crea ed attiva l'ambiente virtualeRUN python -m venv venvRUN /bin/bash -c "source venv/bin/activate"# Installa i pacchetti necessari specificati in requirements.txtRUN pip install -r requirements.txt# Installa wgetRUN apt-get update && apt-get install -y wget# Scarica il file del dataset utilizzando wgetRUN wget -O /app/data/DelayedFlights.csv https://flightdelay.blob.core.windows.net/flight-delayed-dataset/DelayedFlights.csv# Scarica il file del miglior modello utilizzando wgetRUN wget -O /app/models/best_model.pkl https://flightdelay.blob.core.windows.net/flight-delayed-dataset/best_model.pkl# Rendi la porta 8501 disponibile al mondo esterno al containerEXPOSE 8501# Definisci il comando predefinito per eseguire l'applicazione StreamlitCMD ["streamlit", "run", "app.py"]

Costruzione ed esecuzione dei container Docker

Segui questi passaggi per creare l’immagine Docker ed eseguire un container nel terminale dopo aver scritto il Dockerfile.

docker build -t flight-delay-prediction .docker run -p 8501:8501 flight-delay-prediction

Condivisione della nostra app Streamlit con Streamlit Sharing:

Dopo aver costruito la nostra applicazione Streamlit da condividere con gli altri, possiamo utilizzare Streamlit Sharing per ospitare gratuitamente le nostre applicazioni. Ecco i passaggi da seguire:

1) Organizzare il progetto: Assicurarsi di avere un file app.py nella directory principale.

2) Definire le dipendenze: Creare un file requirements.txt in modo che Streamlit Sharing installi tutti i pacchetti necessari menzionati in questo file.

3) Utilizzare GitHub: Caricare il repository su GitHub per integrarlo senza problemi con Streamlit Sharing.

Successivamente, registrati in Streamlit sharing, incolla l’url del tuo repository su GitHub e clicca su “deploy”, ora verrà generato l’URL del tuo progetto. Puoi condividerlo con gli altri.

Conclusione

Questo guida ci ha insegnato come integrare strumenti come Streamlit, Azure, Docker ed Evidently per creare straordinarie applicazioni basate sui dati. Concludendo questa guida, avrai sufficiente conoscenza per creare applicazioni web con Streamlit, applicazioni portabili tramite Docker e garantire la qualità dei dati e del modello tramite Evidently. Tuttavia, questa guida si tratta di leggere e applicare questa conoscenza nei tuoi prossimi progetti di data science. Cerca di sperimentare, innovare ed esplorare ulteriori miglioramenti che possono essere fatti. Grazie per esserti unito a me fino alla fine della guida. Continua a imparare, continua a fare e continua a crescere!

Punti chiave

  • È essenziale dockerizzare il nostro progetto di Machine Learning in modo che possa essere eseguito in qualsiasi ambiente senza problemi di dipendenza.
  • Per ridurre la dimensione dell’immagine Docker, considera l’utilizzo del multi-staging.
  • L’implementazione dell’architettura MVC nel codice riduce la complessità e migliora la leggibilità del codice per le applicazioni web complesse.
  • L’integrazione ci aiuta a monitorare la qualità dei dati e del modello nell’ambiente di produzione.
  • Dopo aver analizzato tutti i report sui dati e sul modello, è necessario prendere le opportune azioni.

Domande frequenti

Repository GitHub: https://github.com/VishalKumar-S/Flight-Delay-Prediction-and-live-Monitoring-with-Azure-Evidently-and-Streamlit-with-MVC-Architecture