This commit is contained in:
Giuseppe Nucifora 2024-10-31 19:28:53 +01:00
parent c0081cf86e
commit 1da59d68df
6 changed files with 13163 additions and 170 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -299,51 +299,6 @@ scaler_temporal = joblib.load('./models/oli_transformer/scaler_temporal.joblib')
scaler_static = joblib.load('./models/oli_transformer/scaler_static.joblib') scaler_static = joblib.load('./models/oli_transformer/scaler_static.joblib')
scaler_y = joblib.load('./models/oli_transformer/scaler_y.joblib') scaler_y = joblib.load('./models/oli_transformer/scaler_y.joblib')
def prepare_monthly_weather_stats(weather_data):
"""Prepara le statistiche mensili dal weather_data."""
monthly_stats = weather_data.groupby(['year', 'month']).agg({
'temp': 'mean',
'precip': 'sum',
'solarradiation': 'sum' # useremo questo come proxy per solar_energy_sum
}).reset_index()
monthly_stats.columns = ['year', 'month', 'temp_mean', 'precip_sum', 'solar_energy_sum']
return monthly_stats
def prepare_static_features(variety_info, hectares):
"""Prepara le feature statiche nello stesso formato usato durante il training."""
# Inizializza un array con il numero di ettari
static_features = [hectares]
# Aggiungi le feature della varietà
variety_name = variety_info['Varietà di Olive'].lower().replace(" ", "_").replace("'", "")
technique = variety_info['Tecnica di Coltivazione'].lower()
# Feature di base della varietà
variety_features = {
f'{variety_name}_prod_t_ha': variety_info['Produzione (tonnellate/ettaro)'],
f'{variety_name}_oil_prod_t_ha': variety_info['Produzione Olio (tonnellate/ettaro)'],
f'{variety_name}_oil_prod_l_ha': variety_info['Produzione Olio (litri/ettaro)'],
f'{variety_name}_min_yield_pct': variety_info['Min % Resa'],
f'{variety_name}_max_yield_pct': variety_info['Max % Resa'],
f'{variety_name}_min_oil_prod_l_ha': variety_info['Min Produzione Olio (litri/ettaro)'],
f'{variety_name}_max_oil_prod_l_ha': variety_info['Max Produzione Olio (litri/ettaro)'],
f'{variety_name}_avg_oil_prod_l_ha': variety_info['Media Produzione Olio (litri/ettaro)'],
f'{variety_name}_l_per_t': variety_info['Litri per Tonnellata'],
f'{variety_name}_min_l_per_t': variety_info['Min Litri per Tonnellata'],
f'{variety_name}_max_l_per_t': variety_info['Max Litri per Tonnellata'],
f'{variety_name}_avg_l_per_t': variety_info['Media Litri per Tonnellata']
}
# Aggiungi le feature binarie per le tecniche di coltivazione
for tech in ['tradizionale', 'intensiva', 'superintensiva']:
variety_features[f'{variety_name}_{tech}'] = 1 if technique == tech else 0
# Converti il dizionario in lista mantenendo l'ordine usato durante il training
static_features.extend([variety_features[key] for key in sorted(variety_features.keys())])
return np.array(static_features)
def clean_column_name(name): def clean_column_name(name):
# Rimuove caratteri speciali e spazi, converte in snake_case e abbrevia # Rimuove caratteri speciali e spazi, converte in snake_case e abbrevia
name = re.sub(r'[^a-zA-Z0-9\s]', '', name) # Rimuove caratteri speciali name = re.sub(r'[^a-zA-Z0-9\s]', '', name) # Rimuove caratteri speciali
@ -367,52 +322,21 @@ def clean_column_name(name):
return name return name
# Funzioni di supporto per la dashboard # Funzioni di supporto per la dashboard
def prepare_prediction_data(weather_data, varieties_info, percentages, hectares): def prepare_static_features_multiple(varieties_info, percentages, hectares, all_varieties):
"""
Prepara i dati per la predizione con multiple varietà.
Args:
weather_data: DataFrame con i dati meteorologici
varieties_info: Lista di Series con le informazioni delle varietà selezionate
percentages: Lista con le percentuali per ogni varietà
hectares: Numero di ettari totali
"""
# Prepara dati temporali
monthly_stats = weather_data.groupby(['year', 'month']).agg({
'temp': 'mean',
'precip': 'sum',
'solarradiation': 'sum'
}).reset_index()
temporal_features = ['temp_mean', 'precip_sum', 'solar_energy_sum']
temporal_data = monthly_stats.rename(columns={
'temp': 'temp_mean',
'precip': 'precip_sum',
'solarradiation': 'solar_energy_sum'
})[temporal_features].values[-41:] # Ultimi 41 timestep come nel training
temporal_data = scaler_temporal.transform(temporal_data)
temporal_data = np.expand_dims(temporal_data, axis=0)
# Prepara dati statici per tutte le varietà
static_data = prepare_static_features_multiple(varieties_info, percentages, hectares)
static_data = np.expand_dims(static_data, axis=0)
static_data = scaler_static.transform(static_data)
return {'temporal': temporal_data, 'static': static_data}
def prepare_static_features_multiple(varieties_info, percentages, hectares):
""" """
Prepara le feature statiche per multiple varietà seguendo la struttura esatta della simulazione. Prepara le feature statiche per multiple varietà seguendo la struttura esatta della simulazione.
Args: Args:
varieties_info: Lista di Series con le informazioni delle varietà selezionate varieties_info (list): Lista di dizionari contenenti le informazioni sulle varietà selezionate
percentages: Lista con le percentuali per ogni varietà percentages (list): Lista delle percentuali corrispondenti a ciascuna varietà selezionata
hectares: Numero di ettari totali hectares (float): Numero di ettari totali
all_varieties (list): Lista di tutte le possibili varietà nel dataset originale
Returns:
np.array: Array numpy contenente tutte le feature statiche
""" """
# Inizializza un dizionario per tutte le varietà possibili # Inizializza un dizionario per tutte le varietà possibili
variety_data = {clean_column_name(variety): { variety_data = {variety: {
'tech': '',
'pct': 0, 'pct': 0,
'prod_t_ha': 0, 'prod_t_ha': 0,
'oil_prod_t_ha': 0, 'oil_prod_t_ha': 0,
@ -426,12 +350,8 @@ def prepare_static_features_multiple(varieties_info, percentages, hectares):
'min_l_per_t': 0, 'min_l_per_t': 0,
'max_l_per_t': 0, 'max_l_per_t': 0,
'avg_l_per_t': 0, 'avg_l_per_t': 0,
'olive_prod': 0, 'tech': ''
'min_oil_prod': 0, } for variety in all_varieties}
'max_oil_prod': 0,
'avg_oil_prod': 0,
'water_need': 0
} for variety in olive_varieties['Varietà di Olive'].unique()}
# Aggiorna i dati per le varietà selezionate # Aggiorna i dati per le varietà selezionate
for variety_info, percentage in zip(varieties_info, percentages): for variety_info, percentage in zip(varieties_info, percentages):
@ -453,7 +373,6 @@ def prepare_static_features_multiple(varieties_info, percentages, hectares):
) / 4 * percentage/100 * hectares ) / 4 * percentage/100 * hectares
variety_data[variety_name].update({ variety_data[variety_name].update({
'tech': technique,
'pct': percentage/100, 'pct': percentage/100,
'prod_t_ha': variety_info['Produzione (tonnellate/ettaro)'], 'prod_t_ha': variety_info['Produzione (tonnellate/ettaro)'],
'oil_prod_t_ha': variety_info['Produzione Olio (tonnellate/ettaro)'], 'oil_prod_t_ha': variety_info['Produzione Olio (tonnellate/ettaro)'],
@ -467,31 +386,36 @@ def prepare_static_features_multiple(varieties_info, percentages, hectares):
'min_l_per_t': variety_info['Min Litri per Tonnellata'], 'min_l_per_t': variety_info['Min Litri per Tonnellata'],
'max_l_per_t': variety_info['Max Litri per Tonnellata'], 'max_l_per_t': variety_info['Max Litri per Tonnellata'],
'avg_l_per_t': variety_info['Media Litri per Tonnellata'], 'avg_l_per_t': variety_info['Media Litri per Tonnellata'],
'olive_prod': annual_prod, 'tech': technique
'min_oil_prod': min_oil_prod,
'max_oil_prod': max_oil_prod,
'avg_oil_prod': avg_oil_prod,
'water_need': base_water_need
}) })
# Crea il vettore delle feature nell'ordine esatto # Crea il vettore delle feature nell'ordine esatto
static_features = [hectares] # Inizia con gli ettari static_features = [hectares] # Inizia con gli ettari
# Lista delle feature per ogni varietà
variety_features = ['pct', 'prod_t_ha', 'oil_prod_t_ha', 'oil_prod_l_ha', 'min_yield_pct', 'max_yield_pct',
'min_oil_prod_l_ha', 'max_oil_prod_l_ha', 'avg_oil_prod_l_ha', 'l_per_t', 'min_l_per_t',
'max_l_per_t', 'avg_l_per_t']
# Appiattisci i dati delle varietà mantenendo l'ordine esatto # Appiattisci i dati delle varietà mantenendo l'ordine esatto
flattened_variety_data = { for variety in all_varieties:
f'{variety}_{key}': value # Feature esistenti
for variety, data in sorted(variety_data.items()) # Ordina per nome varietà for feature in variety_features:
for key, value in sorted(data.items()) # Ordina per nome feature static_features.append(variety_data[variety][feature])
}
# Aggiungi le feature nell'ordine corretto # Feature binarie per le tecniche di coltivazione
static_features.extend([flattened_variety_data[key] for key in sorted(flattened_variety_data.keys())]) for technique in ['tradizionale', 'intensiva', 'superintensiva']:
static_features.append(1 if variety_data[variety]['tech'] == technique else 0)
return np.array(static_features) print(f"lunghezza features {len(static_features)} ")
return np.array(static_features).reshape(1, -1)
def make_prediction(weather_data, varieties_info, percentages, hectares): def make_prediction(weather_data, varieties_info, percentages, hectares):
"""Effettua una predizione usando il modello.""" """Effettua una predizione usando il modello."""
try: try:
print("Inizio della funzione make_prediction")
# Prepara i dati meteorologici mensili # Prepara i dati meteorologici mensili
monthly_stats = weather_data.groupby(['year', 'month']).agg({ monthly_stats = weather_data.groupby(['year', 'month']).agg({
'temp': 'mean', 'temp': 'mean',
@ -505,17 +429,42 @@ def make_prediction(weather_data, varieties_info, percentages, hectares):
'solarradiation': 'solar_energy_sum' 'solarradiation': 'solar_energy_sum'
}) })
# Prendi gli ultimi 41 mesi di dati print(f"Shape dei dati meteorologici mensili: {monthly_stats.shape}")
temporal_data = monthly_stats[['temp_mean', 'precip_sum', 'solar_energy_sum']].values[-41:]
# Definisci la dimensione della finestra temporale
window_size = 41
# Prendi gli ultimi window_size mesi di dati
if len(monthly_stats) >= window_size:
temporal_data = monthly_stats[['temp_mean', 'precip_sum', 'solar_energy_sum']].values[-window_size:]
else:
raise ValueError(f"Non ci sono abbastanza dati meteorologici. Necessari almeno {window_size} mesi.")
print(f"Shape dei dati temporali prima della trasformazione: {temporal_data.shape}")
temporal_data = scaler_temporal.transform(temporal_data) temporal_data = scaler_temporal.transform(temporal_data)
print(f"Shape dei dati temporali dopo la trasformazione: {temporal_data.shape}")
temporal_data = np.expand_dims(temporal_data, axis=0) temporal_data = np.expand_dims(temporal_data, axis=0)
print(f"Shape finale dei dati temporali: {temporal_data.shape}")
all_varieties = olive_varieties['Varietà di Olive'].unique()
varieties = [clean_column_name(variety) for variety in all_varieties]
# Prepara i dati statici # Prepara i dati statici
static_data = prepare_static_features_multiple(varieties_info, percentages, hectares) print("Preparazione dei dati statici")
static_data = np.expand_dims(static_data, axis=0) static_data = prepare_static_features_multiple(varieties_info, percentages, hectares,varieties)
# Verifica che il numero di feature statiche sia corretto
if static_data.shape[1] != scaler_static.n_features_in_:
print("ATTENZIONE: Il numero di feature statiche non corrisponde a quello atteso dallo scaler!")
print(f"Feature generate: {static_data.shape[1]}, Feature attese: {scaler_static.n_features_in_}")
static_data = scaler_static.transform(static_data) static_data = scaler_static.transform(static_data)
print(f"Shape dei dati statici dopo la trasformazione: {static_data.shape}")
# Effettua la predizione # Effettua la predizione
print("Effettuazione della predizione")
prediction = model.predict({'temporal': temporal_data, 'static': static_data}) prediction = model.predict({'temporal': temporal_data, 'static': static_data})
prediction = scaler_y.inverse_transform(prediction)[0] prediction = scaler_y.inverse_transform(prediction)[0]
@ -551,6 +500,10 @@ def make_prediction(weather_data, varieties_info, percentages, hectares):
except Exception as e: except Exception as e:
print(f"Errore durante la preparazione dei dati o la predizione: {str(e)}") print(f"Errore durante la preparazione dei dati o la predizione: {str(e)}")
print(f"Tipo di errore: {type(e).__name__}")
import traceback
print("Traceback completo:")
print(traceback.format_exc())
raise e raise e
# Definizione del layout della dashboard # Definizione del layout della dashboard
@ -783,65 +736,6 @@ app.layout = dbc.Container([
]) ])
], fluid=True) ], fluid=True)
def prepare_static_features_multiple(varieties_info, percentages, hectares):
"""Prepara le feature statiche per multiple varietà."""
static_features = [hectares] # Inizia con gli ettari totali
# Dizionario per tenere traccia delle feature per ogni varietà possibile
all_varieties = olive_varieties['Varietà di Olive'].unique()
variety_features = {}
# Inizializza tutte le feature a 0 per tutte le varietà possibili
for variety in all_varieties:
variety_name = variety.lower().replace(" ", "_").replace("'", "")
# Feature base
variety_features[f'{variety_name}_pct'] = 0
variety_features[f'{variety_name}_prod_t_ha'] = 0
variety_features[f'{variety_name}_oil_prod_t_ha'] = 0
variety_features[f'{variety_name}_oil_prod_l_ha'] = 0
variety_features[f'{variety_name}_min_yield_pct'] = 0
variety_features[f'{variety_name}_max_yield_pct'] = 0
variety_features[f'{variety_name}_min_oil_prod_l_ha'] = 0
variety_features[f'{variety_name}_max_oil_prod_l_ha'] = 0
variety_features[f'{variety_name}_avg_oil_prod_l_ha'] = 0
variety_features[f'{variety_name}_l_per_t'] = 0
variety_features[f'{variety_name}_min_l_per_t'] = 0
variety_features[f'{variety_name}_max_l_per_t'] = 0
variety_features[f'{variety_name}_avg_l_per_t'] = 0
# Feature tecniche
variety_features[f'{variety_name}_tradizionale'] = 0
variety_features[f'{variety_name}_intensiva'] = 0
variety_features[f'{variety_name}_superintensiva'] = 0
# Aggiorna le feature per le varietà selezionate
for variety_info, percentage in zip(varieties_info, percentages):
if variety_info is not None and percentage > 0:
variety_name = variety_info['Varietà di Olive'].lower().replace(" ", "_").replace("'", "")
technique = variety_info['Tecnica di Coltivazione'].lower()
# Aggiorna le feature della varietà
variety_features[f'{variety_name}_pct'] = percentage / 100
variety_features[f'{variety_name}_prod_t_ha'] = variety_info['Produzione (tonnellate/ettaro)']
variety_features[f'{variety_name}_oil_prod_t_ha'] = variety_info['Produzione Olio (tonnellate/ettaro)']
variety_features[f'{variety_name}_oil_prod_l_ha'] = variety_info['Produzione Olio (litri/ettaro)']
variety_features[f'{variety_name}_min_yield_pct'] = variety_info['Min % Resa']
variety_features[f'{variety_name}_max_yield_pct'] = variety_info['Max % Resa']
variety_features[f'{variety_name}_min_oil_prod_l_ha'] = variety_info['Min Produzione Olio (litri/ettaro)']
variety_features[f'{variety_name}_max_oil_prod_l_ha'] = variety_info['Max Produzione Olio (litri/ettaro)']
variety_features[f'{variety_name}_avg_oil_prod_l_ha'] = variety_info['Media Produzione Olio (litri/ettaro)']
variety_features[f'{variety_name}_l_per_t'] = variety_info['Litri per Tonnellata']
variety_features[f'{variety_name}_min_l_per_t'] = variety_info['Min Litri per Tonnellata']
variety_features[f'{variety_name}_max_l_per_t'] = variety_info['Max Litri per Tonnellata']
variety_features[f'{variety_name}_avg_l_per_t'] = variety_info['Media Litri per Tonnellata']
# Aggiorna la tecnica
variety_features[f'{variety_name}_{technique}'] = 1
# Converti il dizionario in lista mantenendo l'ordine
static_features.extend([variety_features[key] for key in sorted(variety_features.keys())])
return np.array(static_features)
# Callback per la gestione delle percentuali e abilitazione dei campi # Callback per la gestione delle percentuali e abilitazione dei campi
@app.callback( @app.callback(
[Output('technique-2-dropdown', 'disabled'), [Output('technique-2-dropdown', 'disabled'),

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long