EDI+VA · Esercizio di Programmazione

EP07_01 — 🟢 Classificatore k-NN Passo dopo Passo

7.18.1 EP07_01 🟢 Classificatore k-NN Passo dopo Passo

Il KNeighborsClassifier di scikit-learn, utilizzato nel corso del capitolo, nasconde dietro una singola chiamata (.fit / .predict) una regola decisionale piuttosto semplice: per ogni nuova osservazione, calcolare la distanza rispetto a tutti gli esempi di addestramento, selezionare i \(k\) più vicini e votare per la classe di maggioranza tra di essi.

Prima di fare affidamento sulla libreria, ti è stato affidato il compito di implementare questa regola da zero, per uno spazio delle caratteristiche bidimensionale, esattamente come fa internamente il simulatore interattivo della frontiera decisionale del capitolo a ogni clic dell’utente.

7.18.1.1 📋 Linee Guida di Implementazione

  1. Quantità e parametro: Leggere l’intero \(N\) (numero di esempi di addestramento) e l’intero dispari \(k\) (numero di vicini).
  2. Esempi di addestramento: Per ciascuno degli \(N\) esempi, leggere tre valori: le coordinate \(x\) e \(y\) (reali) e l’etichetta \(r\) (intero, \(0\) o \(1\)).
  3. Query: Leggere l’intero \(Q\) (numero di punti di query) e successivamente le coordinate \(x_q\), \(y_q\) (reali) di ciascuna query.
  4. Distanza: Per ogni query, calcolare la distanza euclidea rispetto a tutti gli esempi di addestramento: \[ d(x_q, x_i) = \sqrt{(x_q - x_i)^2 + (y_q - y_i)^2}. \]
  5. Selezione dei vicini: Ordinare gli esempi per distanza crescente e selezionare i primi \(k\). In caso di parità di distanza al confine del k-esimo vicino, risolvere a favore dell’esempio letto per primo nell’input (ordine di lettura stabile).
  6. Votazione di maggioranza: Contare i voti di ciascuna classe tra i \(k\) vicini selezionati. In caso di pareggio nella votazione (possibile solo quando \(k\) è pari, cosa che non dovrebbe verificarsi per la direttiva del punto 1, ma gestire in modo difensivo), assegnare la classe del vicino più prossimo tra le classi in parità.
  7. Output: Per ogni query, nell’ordine di input, stampare la classe prevista. Alla fine, stampare il totale delle query classificate come classe 1.

7.18.1.2 📌 Vincoli Computazionali

  • Metrica fissa: utilizzare esclusivamente la distanza euclidea (non la distanza al quadrato) per l’ordinamento, sebbene il risultato del confronto sia lo stesso.
  • k sempre dispari: l’input garantisce \(k\) dispari e \(k \le N\); ciononostante, implementare il pareggio del punto 6 per robustezza.
  • Stabilità: nell’ordinamento per distanza, preservare l’ordine relativo degli esempi con la stessa distanza (ordinamento stabile).

7.18.1.3 🧠 Fondamenti Teorici

Elemento Ruolo nel k-NN
Spazio delle caratteristiche Insieme di tutti i vettori \((x, y)\) possibili
Distanza euclidea Misura di similarità tra osservazioni
\(k\) piccolo Frontiera irregolare, alta varianza
\(k\) grande Frontiera regolare, alto bias
Votazione di maggioranza Regola decisionale \(\hat y = \operatorname{moda}\{y_i : x_i \in N_k(x)\}\)

7.18.1.4 📦 Specifica di Input e Output (VPL)

Input:

  • Riga 1: Interi \(N\) e \(k\), separati da spazio.
  • Prossime \(N\) righe: tre valori per riga — \(x\), \(y\) (reali) e \(r\) (intero \(\in \{0,1\}\)), separati da spazio.
  • Riga successiva: intero \(Q\).
  • Prossime \(Q\) righe: due valori per riga — \(x_q\), \(y_q\) (reali), separati da spazio.

Output:

  • \(Q\) righe, ciascuna con la classe prevista (0 o 1) per la rispettiva query, nell’ordine di input.
  • Ultima riga: Totale classe 1: X.

7.18.1.5 📌 Esempi

Input Output Osservazione
4 3
0 0 0
1 0 0
5 5 1
6 5 1
1
1 1
0
Totale classe 1: 0
Query vicina al gruppo di classe 0.
4 1
0 0 0
1 0 0
5 5 1
6 5 1
2
0.9 0.1
5.5 5.1
0
1
Totale classe 1: 1
Con \(k=1\), ogni query eredita la classe del vicino più prossimo.
🎮 Simulatore EP07_01: Classificatore k-NN Passo dopo Passo Voto di Maggioranza
Regola k e osserva quali esempi di addestramento (ordinati per distanza) partecipano al voto per la query fissa (★ in x = 3, y = 3).
–
Figura 7.21: Simulatore EP07_01: Classificatore k-NN Passo a Passo
%%writefile EP07_01.py
# Codice Python
Overwriting EP07_01.py
TestSuite("EP07_01.py").run()
✔️ EP07_01.cases esiste già in casos/
📋 5 caso/i caricato/i da casos/EP07_01.cases

🔍 Test di Python: EP07_01.py
⚠️ EP07_01.py: file vuoto (meno di 3 righe). Test saltati.