import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import MinMaxScaler
from tensorflow.keras.models import Sequential, load_model
from tensorflow.keras.layers import Dense, Dropout, LSTM, Input
from tensorflow.keras.callbacks import EarlyStopping, ModelCheckpoint, ReduceLROnPlateau, CSVLogger
import tensorflow as tf
import tkinter as tk
from tkinter import messagebox, scrolledtext, simpledialog
from tkinter import ttk
from matplotlib.figure import Figure
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import matplotlib.pyplot as plt
# Definizione dei file delle ruote
file_ruote = {
'BA': 'Bari.txt',
'CA': 'Cagliari.txt',
'FI': 'Firenze.txt',
'GE': 'Genova.txt',
'MI': 'Milano.txt',
'NA': 'Napoli.txt',
'PA': 'Palermo.txt',
'RM': 'Roma.txt',
'TO': 'Torino.txt',
'VE': 'Venezia.txt',
'NZ': 'Nazionale.txt'
}
# Variabili globali
model = None
X_test = None
y_test = None
scaler = None
ruota_data = None
numeri_previsti = None
previsioni_multiple_resultati = None # Aggiunta per salvare le previsioni multiple
# Funzione per caricare i dati della ruota selezionata
def carica_dati(ruota, start_date, end_date, num_estrazioni):
global ruota_data
file_name = file_ruote[ruota]
try:
data = pd.read_csv(file_name, header=None, sep=r'\s+')
mostra_risultati(f"File caricato: {file_name}\n")
if data.empty or data.isin([None, '']).any().any():
mostra_risultati("File vuoto o con valori non validi.\n")
return None, None, None, None
data.columns = ['data'] + [f'num_{i}' for i in range(1, data.shape[1])]
data['data'] = pd.to_datetime(data['data'], format='%Y/%m/%d')
mask = (data['data'] >= start_date) & (data['data'] <= end_date)
data = data.loc[mask]
if data.empty:
mostra_risultati("Nessun dato trovato nel range di date specificato.\n")
return None, None, None, None
mostra_risultati(f"Verifica da {data['data'].iloc[0].date()} a {data['data'].iloc[-1].date()}\n")
numeri = data.iloc[:, 1:].apply(pd.to_numeric, errors='coerce').dropna(axis=1).values
if numeri.size == 0:
mostra_risultati("Non ci sono numeri validi nel file.\n")
return None, None, None, None
scaler = MinMaxScaler(feature_range=(0, 1))
numeri_normalizzati = scaler.fit_transform(numeri.astype(float))
X, y = [], []
for i in range(len(numeri_normalizzati) - num_estrazioni):
X.append(numeri_normalizzati[i:i + num_estrazioni])
y.append(numeri_normalizzati[i + num_estrazioni])
X = np.array(X)
y = np.array(y)
mostra_risultati(f"Dimensione X: {X.shape}, Dimensione y: {y.shape}\n")
if X.shape[0] < 1:
mostra_risultati("Non ci sono dati sufficienti per l'addestramento.\n")
return None, None, None, None
ruota_data = data
return X, y, scaler, data
except Exception as e:
mostra_risultati(f"Errore durante il caricamento dei dati: {e}\n")
return None, None, None, None
# Funzione per creare il modello LSTM
def crea_modello(X_train):
model = Sequential()
model.add(Input(shape=(X_train.shape[1], X_train.shape[2])))
model.add(LSTM(128, return_sequences=True, kernel_regularizer=tf.keras.regularizers.l2(0.01)))
model.add(Dropout(0.3))
model.add(LSTM(64, kernel_regularizer=tf.keras.regularizers.l2(0.05)))
model.add(Dropout(0.2))
model.add(Dense(X_train.shape[2])) # Matching output size to feature number
model.compile(optimizer=tf.keras.optimizers.Adam(learning_rate=0.005), loss='mean_squared_error')
return model
# Funzione per gestire la selezione della ruota
def on_seleziona_ruota(ruota):
global model, X_test, y_test, scaler, numeri_previsti
try:
start_date = pd.to_datetime(entry_start_date.get(), format='%Y/%m/%d')
end_date = pd.to_datetime(entry_end_date.get(), format='%Y/%m/%d')
num_estrazioni = int(entry_num_estrazioni.get())
except ValueError:
mostra_risultati("Inserisci un intervallo di date valido nel formato YYYY/MM/DD e un numero valido per le estrazioni.\n")
return
if start_date > end_date:
mostra_risultati("La data di inizio deve essere precedente alla data di fine.\n")
return
X, y, scaler, ruota_data = carica_dati(ruota, start_date, end_date, num_estrazioni)
if X is not None and y is not None:
if len(X) < 1:
mostra_risultati("Non ci sono dati sufficienti per l'addestramento del modello.\n")
return
if len(X) < 2:
mostra_risultati("Non ci sono dati sufficienti per la suddivisione in training e testing.\n")
return
try:
epochs = int(entry_epochs.get())
mostra_risultati(f"Inizio training del modello per {epochs} epoche...\n")
except ValueError:
mostra_risultati("Inserisci un numero valido per gli epochs.\n")
return
# Chiedi all'utente quale criterio di early stopping utilizzare
stopping_criterion = simpledialog.askstring("Early Stopping", "Scegli il criterio di early stopping:\n1 - Basato su Patience\n2 - Basato sul Rapporto Minimo").strip()
if stopping_criterion == '1':
# Early stopping basato su patience
early_stopping = EarlyStopping(monitor='val_loss', patience=20, restore_best_weights=True)
callbacks = [early_stopping]
elif stopping_criterion == '2':
# Calcola il rapporto tra la perdita (loss) e la perdita di validazione (val_loss)
csv_logger = CSVLogger('training_log.csv', append=False)
callbacks = [csv_logger]
else:
messagebox.showerror("Errore", "Scelta non valida. Seleziona 1 o 2.")
return
# Dividere i dati in train e test
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.5, random_state=42)
# Creare il modello di rete neurale
model = crea_modello(X_train) # Utilizza la funzione di creazione del modello LSTM
# Addestrare il modello
history = model.fit(X_train, y_train, epochs=epochs, batch_size=20, validation_data=(X_test, y_test), callbacks=callbacks)
# Chiamare la funzione per visualizzare la curva di training
visualizza_curva_di_training(history)
test_loss = model.evaluate(X_test, y_test)
mostra_risultati(f"Test Loss: {test_loss}\n")
mostra_risultati(f"Dimensione del set di addestramento: {X_train.shape[0]} campioni\n")
mostra_risultati(f"Dimensione del set di test: {X_test.shape[0]} campioni\n")
mostra_risultati(f"Numero di epoche utilizzate: {epochs}\n")
next_prediction = model.predict(X_test[:1])
numeri_originali = scaler.inverse_transform(next_prediction)
numeri_interi = numeri_originali.round().astype(int).flatten()
mostra_risultati(f"Nella ruota {ruota}, i numeri previsti sono:\n{', '.join(map(str, numeri_interi))}\n")
numeri_previsti = numeri_interi.tolist()
return numeri_interi
else:
mostra_risultati("Impossibile addestrare il modello. Verifica i dati caricati.\n")
return None
# Funzione per visualizzare la curva di training nel frame
def visualizza_curva_di_training(history):
plt.close("all")
fig = Figure(figsize=(10, 6), dpi=100)
ax = fig.add_subplot(111)
ax.plot(history.history['loss'], label='Loss sul set di addestramento')
ax.plot(history.history['val_loss'], label='Loss sul set di test')
ax.set_title('Curva di Training del Modello')
ax.set_xlabel('Epoche')
ax.set_ylabel('Loss')
ax.legend()
ax.grid()
for widget in graph_frame.winfo_children():
widget.destroy()
canvas = FigureCanvasTkAgg(fig, master=graph_frame)
canvas.draw()
canvas.get_tk_widget().pack(fill='both', expand=True)
# Funzione di visualizzazione dei risultati
def mostra_risultati(risultato):
text_area.insert(tk.END, risultato)
text_area.configure(fg='lime', bg='black')
text_area.see(tk.END)
# Funzioni aggiuntive
def salva_modello(model, nome_file):
model.save(nome_file)
mostra_risultati(f"Modello salvato come {nome_file}\n")
def carica_modello(nome_file):
global model
try:
model = load_model(nome_file)
mostra_risultati(f"Modello caricato da {nome_file}\n")
return model
except Exception as e:
mostra_risultati(f"Errore nel caricamento del modello da {nome_file}: {e}\n")
return None
def previsioni_multiple(model, X, scaler, num_previsioni):
previsioni = []
input_data = X[-1:] # Prendi l'ultimo set di dati come input iniziale
for _ in range(num_previsioni):
next_prediction = model.predict(input_data)
previsioni.append(next_prediction[0])
input_data = np.roll(input_data, -1, axis=1)
input_data[0, -1] = next_prediction[0]
previsioni = np.array(previsioni)
numeri_originali = scaler.inverse_transform(previsioni)
return numeri_originali.round().astype(int)
def visualizza_statistiche(data):
if data is None or data.empty:
mostra_risultati("Nessun dato disponibile per visualizzare le statistiche.\n")
return
numeri = data.iloc[:, 1:].apply(pd.to_numeric, errors='coerce').dropna().values.flatten()
numeri = numeri[numeri.astype(int) > 0] # Mantieni solo valori positivi
if len(numeri) == 0:
mostra_risultati("Non ci sono numeri validi per visualizzare le statistiche.\n")
return
fig, ax = plt.subplots(figsize=(12, 6))
ax.hist(numeri.astype(int), bins=90, range=(1, 91), align='left', rwidth=0.8)
ax.set_title('Distribuzione dei numeri estratti')
ax.set_xlabel('Numero')
ax.set_ylabel('Frequenza')
ax.set_xticks(range(1, 91, 5))
plt.tight_layout()
for widget in graph_frame.winfo_children():
widget.destroy()
canvas = FigureCanvasTkAgg(fig, master=graph_frame)
canvas.draw()
canvas.get_tk_widget().pack(fill='both', expand=True)
# Funzione per confrontare previsioni e risultati reali
def confronta_previsioni(previsioni, reali, previsioni_multiple=None):
fig, ax = plt.subplots(figsize=(12, 6))
# Colori forti per i pallini
colore_previsione_single = '#e800ff' # Magenta
colore_reale = '#46ff00' # Verde
# Definizione dei colori per le previsioni multiple
colori_previsioni_multiple = [
'#ff7f00', # Arancione
'#00ffff', # Ciano
'#0000ff', # Blu
'#ffff00', # Giallo
'#ff00ff', # Viola
'#008000', # Verde
]
# Disegna i dati reali
ax.scatter(reali, previsioni, c=colore_previsione_single, alpha=0.5, label='Previsioni Singole', s=100)
if previsioni_multiple is not None:
# Se le previsioni multiple esistono, disegnarle
for i, prev in enumerate(previsioni_multiple):
x_offset = i * 0.1 # Aggiungi spostamento per le previsioni multiple
colore = colori_previsioni_multiple[i % len(colori_previsioni_multiple)] # Usa un colore diverso
ax.scatter(reali + x_offset, prev, c=colore, alpha=0.5, label=f'Previsioni Multiple {i+1}', s=80)
ax.plot([min(reali), max(reali)], [min(reali), max(reali)], 'r--', lw=2, label='Reali vs Previsti')
ax.set_xlabel('Numeri reali')
ax.set_ylabel('Numeri previsti')
ax.set_title('Confronto tra previsioni e risultati reali')
ax.legend()
plt.tight_layout()
for widget in graph_frame.winfo_children():
widget.destroy()
canvas = FigureCanvasTkAgg(fig, master=graph_frame)
canvas.draw()
canvas.get_tk_widget().pack(fill='both', expand=True)
def mostra_previsioni_multiple():
global model, X_test, scaler, previsioni_multiple_resultati
if model is None or X_test is None or scaler is None:
mostra_risultati("Devi prima addestrare o caricare un modello.\n")
return
num_previsioni = simpledialog.askinteger("Input", "Quante previsioni vuoi fare?", minvalue=1, maxvalue=10)
if num_previsioni:
previsioni_multiple_resultati = previsioni_multiple(model, X_test, scaler, num_previsioni) # Salva i risultati
risultato = "Previsioni multiple:\n"
for i, prev in enumerate(previsioni_multiple_resultati, 1):
risultato += f"Previsione {i}: {', '.join(map(str, prev))}\n"
mostra_risultati(risultato)
# Creazione dell'interfaccia grafica
root = tk.Tk()
root.title("Beta 15")
root.geometry("1200x900")
# Creazione di un titolo
title = tk.Label(root, text="Rete Neurale Beta 15", font=('Helvetica', 24, 'bold'), bg='#e0f7fa')
title.pack(pady=10, fill='x')
# Creazione di un frame per i pulsanti
button_frame = tk.Frame(root, bg='#e0f7fa')
button_frame.pack(pady=10)
# Creazione di un frame per i nuovi pulsanti
button_frame2 = tk.Frame(root, bg='#e0f7fa')
button_frame2.pack(pady=10)
btn_salva = ttk.Button(button_frame2, text="Salva Modello", command=lambda: salva_modello(model, 'modello_salvato.keras'))
btn_salva.pack(side=tk.LEFT, padx=5)
btn_carica = ttk.Button(button_frame2, text="Carica Modello", command=lambda: carica_modello('modello_salvato.keras'))
btn_carica.pack(side=tk.LEFT, padx=5)
btn_statistiche = ttk.Button(button_frame2, text="Visualizza Statistiche", command=lambda: visualizza_statistiche(ruota_data))
btn_statistiche.pack(side=tk.LEFT, padx=5)
btn_confronta = ttk.Button(button_frame2, text="Confronta Previsioni", command=lambda: confronta_previsioni(numeri_previsti, y_test[0],
previsioni_multiple_resultati if numeri_previsti is not None else None))
btn_confronta.pack(side=tk.LEFT, padx=5)
btn_previsioni_multiple = ttk.Button(button_frame2, text="Previsioni Multiple", command=mostra_previsioni_multiple)
btn_previsioni_multiple.pack(side=tk.LEFT, padx=5)
# Creazione di pulsanti per selezionare la ruota
for ruota in file_ruote.keys():
btn = ttk.Button(button_frame, text=ruota, command=lambda r=ruota: on_seleziona_ruota(r))
btn.pack(side=tk.LEFT, padx=5)
# Creazione di un frame per l'input delle date
input_frame_dates = tk.Frame(root, bg='#e0f7fa')
input_frame_dates.pack(pady=10)
label_start_date = tk.Label(input_frame_dates, text="Data Inizio (YYYY/MM/DD):", bg='#e0f7fa')
label_start_date.pack(side=tk.LEFT)
entry_start_date = tk.Entry(input_frame_dates)
entry_start_date.pack(side=tk.LEFT, padx=5)
label_end_date = tk.Label(input_frame_dates, text="Data Fine (YYYY/MM/DD):", bg='#e0f7fa')
label_end_date.pack(side=tk.LEFT)
entry_end_date = tk.Entry(input_frame_dates)
entry_end_date.pack(side=tk.LEFT, padx=5)
# Creazione di un frame per l'input numero di estrazioni
input_frame_num_estrazioni = tk.Frame(root, bg='#e0f7fa')
input_frame_num_estrazioni.pack(pady=10)
label_num_estrazioni = tk.Label(input_frame_num_estrazioni, text="Numero Estrazioni:", bg='#e0f7fa')
label_num_estrazioni.pack(side=tk.LEFT)
entry_num_estrazioni = tk.Entry(input_frame_num_estrazioni)
entry_num_estrazioni.pack(side=tk.LEFT, padx=5)
# Creazione di un frame per l'input numero di epoch
input_frame_epochs = tk.Frame(root, bg='#e0f7fa')
input_frame_epochs.pack(pady=10)
label_epochs = tk.Label(input_frame_epochs, text="Inserisci il numero di epoch:", bg='#e0f7fa')
label_epochs.pack(side=tk.LEFT)
entry_epochs = tk.Entry(input_frame_epochs)
entry_epochs.pack(side=tk.LEFT, padx=5)
# Creazione di un box di testo per visualizzare i risultati
text_area = scrolledtext.ScrolledText(root, width=80, height=20, wrap=tk.WORD, bg='black', fg='lime', font=('Arial', 12))
text_area.pack(pady=10, fill='x', expand=True)
# Aggiungi un frame per il grafico
graph_frame = tk.Frame(root, bg='#e0f7fa')
graph_frame.pack(pady=10, fill='both', expand=True)
# Avvio della GUI
root.mainloop()