# =============================================================
# Ingegneria delle caratteristiche:
# Selezione delle feature più informative con SelectKBest e chi2
# =============================================================

import pandas as pd
from sklearn.feature_selection import SelectKBest, chi2

# ---------------------------------------------------------------
# Creazione del dataset di esempio
# ---------------------------------------------------------------
# Simuliamo un piccolo dataset che descrive dieci studenti tramite
# tre caratteristiche numeriche non negative (ore di studio, numero
# di esercizi svolti, numero di assenze) e l'esito finale (promosso
# o non promosso). Il test chi-quadro richiede valori non negativi,
# quindi tutte le feature sono state scelte rispettando questo vincolo.
data = pd.DataFrame({
    'Ore_Studio':      [2, 4, 6, 8, 3, 7, 5, 9, 1, 6],
    'Numero_Esercizi': [1, 1, 2, 3, 2, 4, 3, 5, 0, 3],
    'Assenze':         [8, 6, 4, 1, 7, 2, 5, 0, 9, 3],
    'Promosso':        [0, 0, 1, 1, 0, 1, 1, 1, 0, 1]
})

print("Dataset originale:")
print(data)

# ---------------------------------------------------------------
# Separazione tra feature (X) e target (y)
# ---------------------------------------------------------------
# X contiene le variabili indipendenti, y la variabile da prevedere.
# Questo passo è comune a qualunque tecnica di selezione delle feature.
X = data[['Ore_Studio', 'Numero_Esercizi', 'Assenze']]
y = data['Promosso']

# ---------------------------------------------------------------
# Selezione delle feature migliori con SelectKBest e chi2
# ---------------------------------------------------------------
# SelectKBest mantiene solo le k feature con il punteggio più alto
# secondo la funzione di scoring indicata. Qui usiamo il test
# chi-quadro (chi2), adatto a feature numeriche non negative.
selector = SelectKBest(score_func=chi2, k=2)
X_new = selector.fit_transform(X, y)

# ---------------------------------------------------------------
# Analisi dei punteggi e delle feature selezionate
# ---------------------------------------------------------------
# Recuperiamo i punteggi chi-quadro, i p-value e la maschera booleana
# che indica quali feature sono state effettivamente mantenute.
punteggi = selector.scores_
p_values = selector.pvalues_
feature_selezionate = X.columns[selector.get_support()]

riepilogo_punteggi = pd.DataFrame({
    'Feature': X.columns,
    'Punteggio_Chi2': punteggi,
    'P_value': p_values,
    'Selezionata': selector.get_support()
}).sort_values(by='Punteggio_Chi2', ascending=False)

print("\nPunteggi Chi-quadro per ciascuna feature:")
print(riepilogo_punteggi)

# ---------------------------------------------------------------
# Costruzione del dataset ridotto
# ---------------------------------------------------------------
# Ricostruiamo un DataFrame con i soli nomi delle feature selezionate,
# pronto per essere utilizzato nell'addestramento di un modello.
X_new_df = pd.DataFrame(X_new, columns=feature_selezionate)

print("\nFeature selezionate:", list(feature_selezionate))
print("\nDataset ridotto:")
print(X_new_df)