🚫 COPIA BLOCCATA
# FASE 2: DATABASE MEDICALE MYSQL
print("\n" + "=" * 80)
print("FASE 2: PROGETTAZIONE E IMPLEMENTAZIONE DATABASE")
print("=" * 80)
import mysql.connector
from mysql.connector import Error
import pandas as pd
from datetime import datetime, date
import json
import pickle
class MedicalDatabase:
"""Database per sistema diagnostico cardiaco"""
def __init__(self, host='localhost', user='root', password='', database='heart_disease_db'):
self.host = host
self.user = user
self.password = password
self.database = database
self.connection = None
def connect(self, create_if_not_exists=True):
"""Connette al database, creandolo se necessario"""
try:
# Prima connessione senza database specificato
initial_conn = mysql.connector.connect(
host=self.host,
user=self.user,
password=self.password
)
cursor = initial_conn.cursor()
# Crea database se non esiste
if create_if_not_exists:
cursor.execute(f"CREATE DATABASE IF NOT EXISTS {self.database}")
print(f"✅ Database '{self.database}' creato/verificato")
cursor.close()
initial_conn.close()
# Connessione al database specifico
self.connection = mysql.connector.connect(
host=self.host,
user=self.user,
password=self.password,
database=self.database
)
print(f"✅ Connesso a database: {self.database}")
return True
except Error as e:
print(f"❌ Errore connessione database: {e}")
return False
def create_tables(self):
"""Crea tutte le tabelle del sistema medicale"""
if not self.connection:
print("❌ Non connesso al database")
return False
cursor = self.connection.cursor()
# 1. Tabella pazienti
patients_table = """
CREATE TABLE IF NOT EXISTS pazienti (
id INT AUTO_INCREMENT PRIMARY KEY,
codice_fiscale VARCHAR(16) UNIQUE NOT NULL,
nome VARCHAR(100) NOT NULL,
cognome VARCHAR(100) NOT NULL,
data_nascita DATE NOT NULL,
sesso ENUM('M', 'F') NOT NULL,
indirizzo VARCHAR(255),
telefono VARCHAR(20),
email VARCHAR(255),
gruppo_sanguigno ENUM('A+', 'A-', 'B+', 'B-', 'AB+', 'AB-', '0+', '0-'),
allergie TEXT,
note_mediche TEXT,
data_creazione TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
data_aggiornamento TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_cognome (cognome),
INDEX idx_data_nascita (data_nascita),
INDEX idx_sesso (sesso)
)
"""
# 2. Tabella esami clinici
exams_table = """
CREATE TABLE IF NOT EXISTS esami_clinici (
id INT AUTO_INCREMENT PRIMARY KEY,
paziente_id INT NOT NULL,
data_esame DATE NOT NULL,
tipo_dolore_toracico ENUM('0', '1', '2', '3') COMMENT '0=tipico angina, 1=atipico, 2=non-angina, 3=asintomatico',
pressione_riposo INT COMMENT 'mmHg',
colesterolo INT COMMENT 'mg/dl',
glicemia_digiuno BOOLEAN COMMENT '> 120 mg/dl',
risultato_ecg ENUM('0', '1', '2'),
frequenza_cardiaca_max INT,
angina_esercizio BOOLEAN,
depressione_st DECIMAL(3,1),
pendenza_st ENUM('0', '1', '2'),
vasi_principali INT CHECK (vasi_principali BETWEEN 0 AND 3),
thalassemia ENUM('1', '2', '3') COMMENT '1=normale, 2=fisso, 3=reversibile',
medico_referente VARCHAR(100),
struttura VARCHAR(100),
note TEXT,
data_inserimento TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (paziente_id) REFERENCES pazienti(id) ON DELETE CASCADE,
INDEX idx_paziente_data (paziente_id, data_esame),
INDEX idx_data_esame (data_esame),
INDEX idx_colesterolo (colesterolo),
INDEX idx_pressione (pressione_riposo)
)
"""
# 3. Tabella diagnosi
diagnoses_table = """
CREATE TABLE IF NOT EXISTS diagnosi (
id INT AUTO_INCREMENT PRIMARY KEY,
paziente_id INT NOT NULL,
data_diagnosi DATE NOT NULL,
tipo_malattia ENUM('cardiopatia_iscemica', 'ipertensione', 'aritmia', 'altro'),
severita INT CHECK (severita BETWEEN 0 AND 4) COMMENT '0=nessuna, 4=massima',
confermata_da_test BOOLEAN DEFAULT FALSE,
medico_diagnosta VARCHAR(100),
note_cliniche TEXT,
trattamento_prescritto TEXT,
data_inserimento TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (paziente_id) REFERENCES pazienti(id) ON DELETE CASCADE,
INDEX idx_paziente_malattia (paziente_id, tipo_malattia),
INDEX idx_data_diagnosi (data_diagnosi),
INDEX idx_severita (severita)
)
"""
# 4. Tabella modelli AI (per storage modelli addestrati)
ai_models_table = """
CREATE TABLE IF NOT EXISTS modelli_ai (
id INT AUTO_INCREMENT PRIMARY KEY,
nome_modello VARCHAR(100) NOT NULL,
tipo_modello ENUM('albero', 'foresta', 'rete_neurale', 'svm') NOT NULL,
algoritmo VARCHAR(100),
versione VARCHAR(20) DEFAULT '1.0',
modello_binario LONGBLOB,
parametri_addestramento JSON,
accuracy_training DECIMAL(5,4),
precision_training DECIMAL(5,4),
recall_training DECIMAL(5,4),
f1_score_training DECIMAL(5,4),
data_addestramento DATETIME NOT NULL,
dati_addestramento_inizio DATE,
dati_addestramento_fine DATE,
numero_campioni_training INT,
features_usate JSON,
stato ENUM('attivo', 'deprecato', 'testing') DEFAULT 'testing',
note TEXT,
data_creazione TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX idx_tipo_modello (tipo_modello),
INDEX idx_data_addestramento (data_addestramento),
INDEX idx_stato (stato),
INDEX idx_accuracy (accuracy_training)
)
"""
# 5. Tabella predizioni AI
predictions_table = """
CREATE TABLE IF NOT EXISTS predizioni_ai (
id INT AUTO_INCREMENT PRIMARY KEY,
paziente_id INT NOT NULL,
esame_id INT,
modello_ai_id INT NOT NULL,
data_predizione DATETIME DEFAULT CURRENT_TIMESTAMP,
probabilita_malattia DECIMAL(5,4) COMMENT '0-1, probabilità malattia',
classe_predetta ENUM('sano', 'malato') NOT NULL,
threshold_usato DECIMAL(3,2) DEFAULT 0.5,
features_input JSON NOT NULL,
spiegazione_predizione JSON COMMENT 'Feature importance, SHAP values',
accuratezza_effettiva BOOLEAN COMMENT 'NULL=non ancora verificato, TRUE=corretta, FALSE=errata',
data_verifica DATE,
note TEXT,
FOREIGN KEY (paziente_id) REFERENCES pazienti(id) ON DELETE CASCADE,
FOREIGN KEY (esame_id) REFERENCES esami_clinici(id) ON DELETE SET NULL,
FOREIGN KEY (modello_ai_id) REFERENCES modelli_ai(id) ON DELETE CASCADE,
INDEX idx_paziente_predizione (paziente_id, data_predizione),
INDEX idx_modello_predizione (modello_ai_id, data_predizione),
INDEX idx_classe_predetta (classe_predetta),
INDEX idx_probabilita (probabilita_malattia),
INDEX idx_accuratezza (accuratezza_effettiva)
)
"""
# 6. Tabella audit log (tracciamento operazioni)
audit_log_table = """
CREATE TABLE IF NOT EXISTS audit_log (
id INT AUTO_INCREMENT PRIMARY KEY,
utente VARCHAR(100),
azione VARCHAR(50) NOT NULL COMMENT 'CREATE, READ, UPDATE, DELETE, PREDICTION',
tabella VARCHAR(50),
record_id INT,
dati_prima JSON,
dati_dopo JSON,
ip_address VARCHAR(45),
user_agent VARCHAR(255),
data_operazione TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX idx_azione (azione),
INDEX idx_tabella (tabella),
INDEX idx_data_operazione (data_operazione),
INDEX idx_utente (utente)
)
"""
tables = [
('pazienti', patients_table),
('esami_clinici', exams_table),
('diagnosi', diagnoses_table),
('modelli_ai', ai_models_table),
('predizioni_ai', predictions_table),
('audit_log', audit_log_table)
]
print("\n🏗️ CREAZIONE TABELLE DATABASE:")
print("-" * 40)
for table_name, table_sql in tables:
try:
cursor.execute(table_sql)
print(f"✅ Tabella '{table_name}' creata/verificata")
except Error as e:
print(f"❌ Errore creazione tabella '{table_name}': {e}")
# Viste per reporting
print("\n📊 CREAZIONE VISTE REPORTING:")
# Vista: Pazienti a rischio (probabilità > 70%)
risk_view = """
CREATE OR REPLACE VIEW vw_pazienti_rischio AS
SELECT
p.id as paziente_id,
p.codice_fiscale,
p.nome,
p.cognome,
p.data_nascita,
TIMESTAMPDIFF(YEAR, p.data_nascita, CURDATE()) as eta,
p.sesso,
pa.probabilita_malattia,
pa.classe_predetta,
pa.data_predizione,
m.nome_modello,
m.accuracy_training
FROM pazienti p
JOIN predizioni_ai pa ON p.id = pa.paziente_id
JOIN modelli_ai m ON pa.modello_ai_id = m.id
WHERE pa.probabilita_malattia > 0.7
AND pa.data_predizione >= DATE_SUB(CURDATE(), INTERVAL 30 DAY)
AND m.stato = 'attivo'
ORDER BY pa.probabilita_malattia DESC
"""
# Vista: Performance modelli
performance_view = """
CREATE OR REPLACE VIEW vw_performance_modelli AS
SELECT
m.nome_modello,
m.tipo_modello,
m.accuracy_training,
m.precision_training,
m.recall_training,
m.f1_score_training,
m.data_addestramento,
COUNT(pa.id) as numero_predizioni,
AVG(CASE WHEN pa.accuratezza_effettiva = TRUE THEN 1
WHEN pa.accuratezza_effettiva = FALSE THEN 0
ELSE NULL END) * 100 as percentuale_corrette
FROM modelli_ai m
LEFT JOIN predizioni_ai pa ON m.id = pa.modello_ai_id
WHERE m.stato = 'attivo'
GROUP BY m.id
ORDER BY m.data_addestramento DESC
"""
views = [
('vw_pazienti_rischio', risk_view),
('vw_performance_modelli', performance_view)
]
for view_name, view_sql in views:
try:
cursor.execute(view_sql)
print(f"✅ Vista '{view_name}' creata/aggiornata")
except Error as e:
print(f"⚠️ Errore creazione vista '{view_name}': {e}")
# Stored Procedure: Calcola statistiche paziente
procedures_sql = """
DELIMITER $$
CREATE PROCEDURE IF NOT EXISTS sp_statistiche_paziente(
IN p_paziente_id INT
)
BEGIN
-- Statistiche base paziente
SELECT
p.*,
TIMESTAMPDIFF(YEAR, p.data_nascita, CURDATE()) as eta_attuale,
COUNT(DISTINCT e.id) as numero_esami,
COUNT(DISTINCT d.id) as numero_diagnosi,
MAX(e.data_esame) as ultimo_esame,
MAX(d.data_diagnosi) as ultima_diagnosi
FROM pazienti p
LEFT JOIN esami_clinici e ON p.id = e.paziente_id
LEFT JOIN diagnosi d ON p.id = d.paziente_id
WHERE p.id = p_paziente_id
GROUP BY p.id;
-- Ultime predizioni AI
SELECT
pa.*,
m.nome_modello,
m.accuracy_training
FROM predizioni_ai pa
JOIN modelli_ai m ON pa.modello_ai_id = m.id
WHERE pa.paziente_id = p_paziente_id
ORDER BY pa.data_predizione DESC
LIMIT 5;
END$$
DELIMITER ;
"""
try:
cursor.execute(procedures_sql)
print("✅ Stored procedure 'sp_statistiche_paziente' creata")
except Error as e:
print(f"⚠️ Errore creazione stored procedure: {e}")
cursor.close()
self.connection.commit()
print(f"\n✅ DATABASE COMPLETAMENTE CONFIGURATO")
print(f"• 6 tabelle principali")
print(f"• 2 viste analitiche")
print(f"• 1 stored procedure")
print(f"• Relazioni e vincoli implementati")
return True
def insert_sample_data(self):
"""Inserisce dati di esempio per testing"""
if not self.connection:
print("❌ Non connesso al database")
return False
cursor = self.connection.cursor()
print("\n📥 INSERIMENTO DATI DI ESEMPIO:")
print("-" * 40)
# 1. Inserimento pazienti di esempio
patients_data = [
('RSSMRA80A01H501U', 'Mario', 'Rossi', '1980-01-01', 'M', 'Roma', '3331234567', 'mario.rossi@email.com', 'A+', 'Penicillina', 'Iperteso leggero'),
('BNCLRA75B42H501V', 'Laura', 'Bianchi', '1975-02-12', 'F', 'Milano', '3337654321', 'laura.bianchi@email.com', '0-', 'Nessuna', 'Controllo annuale'),
('VRDGSP70C12H501W', 'Giuseppe', 'Verdi', '1970-03-22', 'M', 'Napoli', '3339876543', 'giuseppe.verdi@email.com', 'B+', 'Aspirina', 'Fumatore'),
('NRRNNA85D04H501X', 'Anna', 'Neri', '1985-04-04', 'F', 'Torino', '3334567890', 'anna.neri@email.com', 'AB+', 'Nessuna', 'Sportiva'),
('GLLLCA90E15H501Y', 'Luca', 'Gialli', '1990-05-25', 'M', 'Bologna', '3330987654', 'luca.gialli@email.com', '0+', 'Noci', 'Controllo routine')
]
insert_patient = """
INSERT INTO pazienti
(codice_fiscale, nome, cognome, data_nascita, sesso, indirizzo, telefono, email, gruppo_sanguigno, allergie, note_mediche)
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
"""
patient_ids = []
for patient in patients_data:
try:
cursor.execute(insert_patient, patient)
patient_ids.append(cursor.lastrowid)
except Error as e:
print(f"⚠️ Errore inserimento paziente: {e}")
self.connection.commit()
print(f"✅ {len(patient_ids)} pazienti inseriti")
# 2. Inserimento esami clinici
if patient_ids:
exams_data = []
for i, patient_id in enumerate(patient_ids):
# Ogni paziente ha 1-3 esami
num_exams = np.random.randint(1, 4)
for j in range(num_exams):
exam_date = date(2023, np.random.randint(1, 13), np.random.randint(1, 28))
exam = (
patient_id,
exam_date,
str(np.random.choice(['0', '1', '2', '3'])),
np.random.randint(120, 180),
np.random.randint(180, 300),
np.random.choice([True, False]),
str(np.random.choice(['0', '1', '2'])),
np.random.randint(140, 190),
np.random.choice([True, False]),
round(np.random.uniform(0, 4), 1),
str(np.random.choice(['0', '1', '2'])),
np.random.randint(0, 4),
str(np.random.choice(['1', '2', '3'])),
'Dr. Smith',
'Ospedale Civile'
)
exams_data.append(exam)
insert_exam = """
INSERT INTO esami_clinici
(paziente_id, data_esame, tipo_dolore_toracico, pressione_riposo, colesterolo,
glicemia_digiuno, risultato_ecg, frequenza_cardiaca_max, angina_esercizio,
depressione_st, pendenza_st, vasi_principali, thalassemia, medico_referente, struttura)
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
"""
try:
cursor.executemany(insert_exam, exams_data)
print(f"✅ {cursor.rowcount} esami clinici inseriti")
except Error as e:
print(f"⚠️ Errore inserimento esami: {e}")
self.connection.commit()
# 3. Inserimento modelli AI di esempio
models_data = [
('Heart Disease RF v1', 'foresta', 'RandomForest', '1.0',
pickle.dumps({'dummy': 'model'}), # Modello dummy serializzato
'{"n_estimators": 100, "max_depth": 10}', 0.85, 0.82, 0.87, 0.84,
datetime.now(), '2023-01-01', '2023-12-01', 1000,
'["age", "sex", "cp", "trestbps", "chol"]', 'attivo'),
('Heart Disease NN v1', 'rete_neurale', 'NeuralNetwork', '1.0',
pickle.dumps({'dummy': 'model'}),
'{"layers": [64, 32], "activation": "relu"}', 0.88, 0.85, 0.90, 0.87,
datetime.now(), '2023-01-01', '2023-12-01', 1000,
'["age", "sex", "cp", "trestbps", "chol", "thalach"]', 'testing')
]
insert_model = """
INSERT INTO modelli_ai
(nome_modello, tipo_modello, algoritmo, versione, modello_binario,
parametri_addestramento, accuracy_training, precision_training,
recall_training, f1_score_training, data_addestramento,
dati_addestramento_inizio, dati_addestramento_fine,
numero_campioni_training, features_usate, stato)
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
"""
model_ids = []
for model in models_data:
try:
cursor.execute(insert_model, model)
model_ids.append(cursor.lastrowid)
except Error as e:
print(f"⚠️ Errore inserimento modello AI: {e}")
self.connection.commit()
print(f"✅ {len(model_ids)} modelli AI inseriti")
# 4. Inserimento predizioni di esempio
if patient_ids and model_ids:
predictions_data = []
for patient_id in patient_ids:
for model_id in model_ids:
prediction_date = datetime.now()
probability = round(np.random.uniform(0.1, 0.9), 4)
predicted_class = 'malato' if probability > 0.5 else 'sano'
prediction = (
patient_id,
None, # esame_id (opzionale)
model_id,
prediction_date,
probability,
predicted_class,
0.5,
json.dumps({'age': 45, 'sex': 'M', 'cp': 1}),
json.dumps({'feature_importance': {'age': 0.3, 'chol': 0.4}}),
np.random.choice([True, False, None]),
date.today() if np.random.random() > 0.5 else None
)
predictions_data.append(prediction)
insert_prediction = """
INSERT INTO predizioni_ai
(paziente_id, esame_id, modello_ai_id, data_predizione, probabilita_malattia,
classe_predetta, threshold_usato, features_input, spiegazione_predizione,
accuratezza_effettiva, data_verifica)
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
"""
try:
cursor.executemany(insert_prediction, predictions_data)
print(f"✅ {cursor.rowcount} predizioni AI inserite")
except Error as e:
print(f"⚠️ Errore inserimento predizioni: {e}")
self.connection.commit()
cursor.close()
print("\n📋 RIEPILOGO DATI INSERITI:")
print(f"• Pazienti: {len(patient_ids)}")
print(f"• Esami clinici: {len(exams_data) if 'exams_data' in locals() else 0}")
print(f"• Modelli AI: {len(model_ids)}")
print(f"• Predizioni: {len(predictions_data) if 'predictions_data' in locals() else 0}")
return True
def query_database(self):
"""Esegue query di esempio per dimostrare funzionalità"""
if not self.connection:
print("❌ Non connesso al database")
return
cursor = self.connection.cursor(dictionary=True)
print("\n🔍 QUERY DIMOSTRATIVE:")
print("-" * 40)
# 1. Conta pazienti per sesso
print("\n1️⃣ PAZIENTI PER SESSO:")
cursor.execute("""
SELECT sesso, COUNT(*) as conteggio
FROM pazienti
GROUP BY sesso
ORDER BY conteggio DESC
""")
for row in cursor.fetchall():
sesso = 'Maschio' if row['sesso'] == 'M' else 'Femmina'
print(f" • {sesso}: {row['conteggio']} pazienti")
# 2. Pazienti con rischio alto (probabilità > 70%)
print("\n2️⃣ PAZIENTI AD ALTO RISCHIO:")
cursor.execute("""
SELECT
p.nome, p.cognome, p.data_nascita,
pa.probabilita_malattia,
pa.classe_predetta,
m.nome_modello
FROM vw_pazienti_rischio pa
JOIN pazienti p ON pa.paziente_id = p.id
JOIN modelli_ai m ON pa.nome_modello = m.nome_modello
WHERE pa.probabilita_malattia > 0.7
ORDER BY pa.probabilita_malattia DESC
LIMIT 5
""")
for row in cursor.fetchall():
eta = (date.today() - row['data_nascita']).days // 365
print(f" • {row['nome']} {row['cognome']} ({eta} anni)")
print(f" Probabilità: {row['probabilita_malattia']*100:.1f}%")
print(f" Predizione: {row['classe_predetta']}")
print(f" Modello: {row['nome_modello']}")
print()
# 3. Performance modelli
print("\n3️⃣ PERFORMANCE MODELLI AI:")
cursor.execute("SELECT * FROM vw_performance_modelli")
for row in cursor.fetchall():
print(f" • {row['nome_modello']} ({row['tipo_modello']})")
print(f" Accuracy: {row['accuracy_training']:.3f}")
print(f" Precision: {row['precision_training']:.3f}")
print(f" Recall: {row['recall_training']:.3f}")
print(f" Predizioni: {row['numero_predizioni']}")
if row['percentuale_corrette']:
print(f" Accuratezza reale: {row['percentuale_corrette']:.1f}%")
print()
# 4. Statistiche esami
print("\n4️⃣ STATISTICHE ESAMI CLINICI:")
cursor.execute("""
SELECT
MIN(pressione_riposo) as pressione_min,
MAX(pressione_riposo) as pressione_max,
AVG(pressione_riposo) as pressione_media,
MIN(colesterolo) as colesterolo_min,
MAX(colesterolo) as colesterolo_max,
AVG(colesterolo) as colesterolo_media,
COUNT(*) as totale_esami
FROM esami_clinici
""")
stats = cursor.fetchone()
if stats:
print(f" • Pressione: {stats['pressione_min']}-{stats['pressione_max']} mmHg")
print(f" Media: {stats['pressione_media']:.1f} mmHg")
print(f" • Colesterolo: {stats['colesterolo_min']}-{stats['colesterolo_max']} mg/dl")
print(f" Media: {stats['colesterolo_media']:.1f} mg/dl")
print(f" • Esami totali: {stats['totale_esami']}")
cursor.close()
print("\n✅ QUERY COMPLETATE")
print("Il database è operativo e pronto per integrazione AI!")
def export_to_dataframe(self, table_name, limit=1000):
"""Esporta dati da tabella a DataFrame pandas"""
if not self.connection:
print("❌ Non connesso al database")
return pd.DataFrame()
query = f"SELECT * FROM {table_name} LIMIT {limit}"
try:
df = pd.read_sql(query, self.connection)
print(f"✅ Esportati {len(df)} record da '{table_name}'")
return df
except Error as e:
print(f"❌ Errore esportazione: {e}")
return pd.DataFrame()
def close(self):
"""Chiude connessione database"""
if self.connection and self.connection.is_connected():
self.connection.close()
print("🔌 Connessione database chiusa")
# DEMOSTRAZIONE DATABASE
print("\n🚀 IMPLEMENTAZIONE DATABASE MEDICALE")
print("=" * 60)
# Crea istanza database (modifica credenziali se necessario)
medical_db = MedicalDatabase(
host='localhost',
user='root',
password='password',
database='heart_disease_final'
)
# 1. Connetti e crea database
if medical_db.connect():
# 2. Crea tabelle
medical_db.create_tables()
# 3. Inserisci dati di esempio (commenta se non vuoi dati fake)
medical_db.insert_sample_data()
# 4. Esegui query dimostrative
medical_db.query_database()
# 5. Esporta dati per analisi AI
print("\n📤 ESPORTAZIONE DATI PER ANALISI AI:")
print("-" * 40)
# Esporta pazienti
patients_df = medical_db.export_to_dataframe('pazienti')
if not patients_df.empty:
print(f"• Pazienti: {patients_df.shape[0]} record, {patients_df.shape[1]} colonne")
# Esporta esami clinici
exams_df = medical_db.export_to_dataframe('esami_clinici')
if not exams_df.empty:
print(f"• Esami: {exams_df.shape[0]} record, {exams_df.shape[1]} colonne")
# 6. Chiudi connessione
medical_db.close()
print("\n" + "=" * 80)
print("✅ FASE 2 COMPLETATA: DATABASE IMPLEMENTATO")
print("=" * 80)
print("\n🎯 PROSSIMA FASE: Sviluppo Modelli Machine Learning")