KNN per la regressione e i suoi limiti di scalabilità
Applicherà KNeighborsRegressor a un target continuo, quindi misurerà il tempo di previsione su dataset di grandi dimensioni per comprendere il costo d'inferenza O(n) di KNN.
KNN per la regressione e i suoi limiti di scalabilità è una lezione Machine Learning Academy gratuita su CoddyKit. Questa è la lezione 4 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento Machine Learning Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso Machine Learning Academy include 4 lezioni in totale.
KNN per la regressione: calcolare la media dei vicini
KNN non è limitato alla classificazione: può anche prevedere valori continui. Nella regressione KNN, la previsione per un nuovo punto è la media dei valori target dei suoi k vicini più prossimi. Ad esempio, per prevedere il prezzo di una casa, KNN individua le k case più simili nel set di addestramento e calcola la media dei loro prezzi. In questo modo si ottiene un modello di regressione locale non parametrico, capace di catturare schemi complessi senza assumere una forma funzionale specifica per la relazione tra caratteristiche e target.
import numpy as np
# Training data: house sizes (sqm) -> prices (thousands)
X_train = np.array([[50], [70], [90], [110], [130]])
y_train = np.array([150, 200, 260, 310, 380])
# Query: predict price for 80 sqm house
x_new = np.array([[80]])
# k=3: find 3 nearest neighbors
dists = np.abs(X_train - x_new).flatten()
nearest_idx = np.argsort(dists)[:3]
neighbor_prices = y_train[nearest_idx]
prediction = neighbor_prices.mean()
print('Neighbor prices:', neighbor_prices)
print('KNN regression prediction:', prediction)KNeighborsRegressor in scikit-learn
KNeighborsRegressor di scikit-learn implementa KNN per target continui con la stessa API del classificatore. Supporta gli stessi parametri: n_neighbors, metric, weights e algorithm. La regressione pesata sulla distanza (weights='distance') è spesso vantaggiosa: i vicini più prossimi contribuiscono maggiormente al valore previsto rispetto a quelli più lontani, il che è particolarmente utile ai margini della distribuzione dei dati di addestramento, dove un vicino distante potrebbe introdurre un bias significativo.
from sklearn.neighbors import KNeighborsRegressor
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
from sklearn.datasets import fetch_california_housing
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error
import numpy as np
X, y = fetch_california_housing(return_X_y=True)
X_tr, X_te, y_tr, y_te = train_test_split(X, y, test_size=0.2, random_state=42)
pipe = Pipeline([
('sc', StandardScaler()),
('knn', KNeighborsRegressor(n_neighbors=10, weights='distance'))
])
pipe.fit(X_tr, y_tr)
rmse = mean_squared_error(y_te, pipe.predict(X_te), squared=False)
print('RMSE:', rmse.round(3))Scegliere k per la regressione
La stessa logica bias-varianza si applica alla regressione KNN: k piccolo = varianza elevata, previsioni irregolari; k grande = bias elevato, previsioni eccessivamente smussate. Può visualizzare questo effetto tracciando la funzione prevista su un intervallo di input unidimensionale. Con k=1, la linea delle previsioni raggiunge il valore esatto di ciascun punto di addestramento. All'aumentare di k, la linea diventa più uniforme. Il valore ottimale di k minimizza l'RMSE (o MAE) calcolato con la convalida incrociata. Nella regressione non esiste il problema della risoluzione dei pareggi, quindi anche i valori pari di k vanno bene.
from sklearn.neighbors import KNeighborsRegressor
from sklearn.model_selection import cross_val_score
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
import numpy as np
best_k, best_score = 1, float('inf')
for k in range(1, 31):
pipe = Pipeline([
('sc', StandardScaler()),
('knn', KNeighborsRegressor(n_neighbors=k))
])
scores = -cross_val_score(pipe, X_tr, y_tr, cv=5, scoring='neg_root_mean_squared_error')
mean_rmse = scores.mean()
if mean_rmse < best_score:
best_score, best_k = mean_rmse, k
print(f'Best k={best_k} with CV RMSE={best_score:.3f}')Tempo di previsione di KNN: O(N * d) per query
A differenza dei modelli parametrici addestrati (regressione lineare, reti neurali), che effettuano previsioni in tempo O(d) usando i parametri memorizzati, KNN deve analizzare tutti i punti di addestramento al momento dell'inferenza. Ogni previsione richiede il calcolo delle distanze rispetto a ogni campione di addestramento: un'operazione O(N * d). Per N=1,000,000 e d=100, si tratta di 100 milioni di operazioni per previsione. Se ogni operazione richiede 1 millisecondo, una singola previsione richiede 100 secondi. Di conseguenza, il KNN ingenuo è del tutto inadatto ai sistemi di produzione in tempo reale con set di addestramento di grandi dimensioni.
import numpy as np
import time
np.random.seed(42)
for N in [1000, 10000, 100000, 1000000]:
X_big = np.random.randn(N, 10)
query = np.random.randn(1, 10)
start = time.time()
dists = np.linalg.norm(X_big - query, axis=1)
_ = np.argsort(dists)[:5]
elapsed = time.time() - start
print(f'N={N:>8}: {elapsed*1000:.1f} ms')
# Prediction time scales linearly with NVicini più prossimi approssimati: KD-Tree e Ball Tree
Scikit-learn offre due strutture di indicizzazione spaziale per velocizzare la ricerca dei vicini. Un KD-Tree suddivide ricorsivamente lo spazio delle caratteristiche lungo la dimensione con la varianza maggiore, consentendo ricerche dei vicini in O(log N) per dati a bassa dimensionalità. Un Ball Tree suddivide i dati in ipersfere annidate, risultando più efficiente per dati ad alta dimensionalità o con metriche non euclidee. Entrambe riducono significativamente il tempo medio di previsione. Imposti il parametro algorithm di KNeighborsClassifier su 'kd_tree', 'ball_tree' o 'auto' (sceglie scikit-learn).
from sklearn.neighbors import KNeighborsClassifier
import time, numpy as np
X = np.random.randn(50000, 5)
y = (X[:, 0] > 0).astype(int)
algorithms = ['brute', 'kd_tree', 'ball_tree']
for alg in algorithms:
knn = KNeighborsClassifier(n_neighbors=5, algorithm=alg)
knn.fit(X, y)
start = time.time()
knn.predict(X[:100])
print(f'{alg:10}: {(time.time()-start)*1000:.1f} ms for 100 predictions')Requisiti di memoria di KNN
KNN deve conservare in memoria l'intero set di addestramento in ogni momento, perché le previsioni richiedono l'accesso ai campioni di addestramento. Per N=1 milione di campioni con d=100 caratteristiche float64, la sola matrice dei dati richiede 800 MB di RAM. Con N=10 milioni, sono 8 GB: una quantità eccessiva per molti ambienti di distribuzione. I modelli parametrici, come la regressione lineare o le reti neurali, comprimono N campioni in un numero fisso di parametri, risultando molto più efficienti in termini di memoria durante l'inferenza. Il costo in memoria di KNN è O(N * d), indipendentemente dalla complessità del problema.
import numpy as np
def memory_mb(N, d, dtype=np.float64):
bytes_per_value = np.dtype(dtype).itemsize
total_bytes = N * d * bytes_per_value
return total_bytes / (1024**2)
for N in [1000, 10000, 100000, 1000000]:
mb = memory_mb(N, d=100)
print(f'N={N:>8}, d=100: {mb:.1f} MB')
# 1,000: 0.8 MB (fine)
# 1,000,000: 762.9 MB (borderline)
# A linear model: same O(d) parameters regardless of NFAISS: vicini più prossimi approssimati su larga scala
Per i casi d'uso di produzione su larga scala, le librerie per la ricerca dei vicini più prossimi approssimati (ANN) riducono drasticamente il tempo di ricerca, al costo di non individuare occasionalmente il vero vicino più prossimo. FAISS (Facebook AI Similarity Search) può interrogare un miliardo di vettori in pochi millisecondi usando strutture di indicizzazione accelerate dalla GPU. Annoy (Spotify) costruisce una foresta di alberi a proiezione casuale per le ricerche approssimate. I grafi HNSW (Hierarchical Navigable Small World) consentono query in meno di un millisecondo. Queste librerie vengono usate nei sistemi di raccomandazione e nella ricerca semantica su scala di produzione.
# Conceptual FAISS usage (requires: pip install faiss-cpu)
import numpy as np
# import faiss # not available in standard envs
# Conceptual workflow:
# N = 1_000_000 # 1 million vectors
# d = 128 # dimensionality
# X = np.random.randn(N, d).astype('float32')
# index = faiss.IndexFlatL2(d) # Exact L2 search
# index.add(X) # Index all vectors
# Query 10 vectors
# query = np.random.randn(10, d).astype('float32')
# distances, indices = index.search(query, k=5)
# print(indices.shape) # (10, 5)Quando KNN è pratico e quando usare alternative
KNN è pratico quando: N < 100,000, le previsioni vengono eseguite in batch (non in tempo reale) ed è necessaria l'interpretabilità (può mostrare gli esempi simili effettivi). KNN presenta difficoltà quando: N è molto grande, sono necessarie previsioni in tempo reale (latenza <100ms) oppure lo spazio delle caratteristiche è ad alta dimensionalità (>50 caratteristiche). Tra le alternative migliori per valori elevati di N figurano Random Forest e Gradient Boosting per i dati tabulari, e le reti neurali per immagini e testo. KNN rimane un solido modello di riferimento per i sistemi di raccomandazione e il rilevamento delle anomalie quando il dataset entra comodamente in memoria.
# Decision guide: KNN vs alternatives
def should_use_knn(N, d, latency_ms_required):
if N > 500_000:
return 'Too large for KNN -- use Random Forest or XGBoost'
elif d > 50:
return 'Too high-dimensional -- apply PCA first or use tree models'
elif latency_ms_required < 50:
return 'Too strict latency -- use parametric model'
else:
return 'KNN is suitable as a baseline'
print(should_use_knn(10000, 10, 500)) # KNN is suitable
print(should_use_knn(1000000, 10, 500)) # Too large
print(should_use_knn(10000, 100, 500)) # Too high-dimensionalProfilazione di KNN e della regressione lineare
Confrontare KNN e la regressione lineare sullo stesso problema di regressione mette in evidenza il compromesso in termini di scalabilità. La regressione lineare viene addestrata in pochi secondi indipendentemente da N (addestramento O(N*d^2), ma previsione O(d)). L'addestramento di KNN è istantaneo (non richiede calcoli), ma la previsione scala con N. KNN è quindi un modello a calcolo differito: sostiene tutti i costi al momento della previsione. Per un'attività di previsione batch eseguita una sola volta su 100.000 righe, KNN può essere accettabile. Per un'API che gestisce 1000 richieste al secondo, la regressione lineare o una rete neurale è più veloce di diversi ordini di grandezza.
import numpy as np
import time
from sklearn.neighbors import KNeighborsRegressor
from sklearn.linear_model import LinearRegression
X = np.random.randn(50000, 10)
y = X[:, 0] * 3 + np.random.randn(50000)
X_test = np.random.randn(1000, 10)
knn = KNeighborsRegressor(n_neighbors=5)
lr = LinearRegression()
knn.fit(X, y); lr.fit(X, y)
for name, model in [('KNN', knn), ('LinearReg', lr)]:
t0 = time.time()
model.predict(X_test)
dt = (time.time() - t0) * 1000
print(f'{name}: {dt:.1f} ms for 1000 predictions')Usare gli output di KNN nelle pipeline
Anche quando KNN è troppo lento per essere usato direttamente in produzione, le distanze restituite possono fungere da caratteristiche informative per altri modelli. Ad esempio, calcolare la distanza media dai k vicini di addestramento più prossimi per ogni punto di test crea una singola caratteristica che misura quanto il punto sia insolito. I punti insoliti (lontani dai propri vicini) sono potenziali anomalie. Questo approccio, che usa KNN come estrattore di caratteristiche anziché come predittore finale, consente di sfruttare le informazioni sui vicini più prossimi all'interno di modelli ensemble veloci.
from sklearn.neighbors import KNeighborsClassifier
import numpy as np
X_train = np.random.randn(500, 10)
y_train = (X_train[:, 0] > 0).astype(int)
X_test = np.random.randn(50, 10)
knn = KNeighborsClassifier(n_neighbors=5)
knn.fit(X_train, y_train)
# Extract neighbor distances as an anomaly score
dists, _ = knn.kneighbors(X_test)
avg_dist = dists.mean(axis=1)
print('Average neighbor distances (anomaly score):')
print(avg_dist.round(2))
# High values indicate potential anomaliesRiduzione della dimensionalità prima di KNN
Per rendere KNN pratico sui dati ad alta dimensionalità, applichi PCA prima di KNeighborsRegressor, così da ridurre la dimensionalità preservando la maggior parte della varianza. In questo modo affronta simultaneamente due problemi: riduce il tempo di previsione (meno dimensioni = calcolo delle distanze più rapido) e attenua la maledizione della dimensionalità (le distanze diventano più significative nello spazio a dimensionalità ridotta). PCA + KNN all'interno di un'unica Pipeline mantiene la pre-elaborazione priva di data leakage durante la convalida incrociata.
from sklearn.pipeline import Pipeline
from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler
from sklearn.neighbors import KNeighborsRegressor
from sklearn.model_selection import cross_val_score
import numpy as np
X_high_d = np.random.randn(1000, 100) # 100 features
y = X_high_d[:, :5].sum(axis=1) # Only first 5 matter
pipe = Pipeline([
('sc', StandardScaler()),
('pca', PCA(n_components=10)), # Reduce to 10 components
('knn', KNeighborsRegressor(n_neighbors=5))
])
scores = -cross_val_score(pipe, X_high_d, y, cv=5,
scoring='neg_root_mean_squared_error')
print('CV RMSE with PCA:', scores.mean().round(3))Verifica rapida
Verifichi la Sua comprensione dei concetti di Machine Learning con Python presentati in questa lezione.
Riepilogo della lezione
In questa lezione ha imparato: come la regressione KNN prevede target continui calcolando la media dei valori dei vicini, il fondamentale costo di previsione O(N * d) che limita la scalabilità di KNN e come KD-Tree, Ball Tree e FAISS velocizzano la ricerca dei vicini per i dataset più grandi. Nella prossima lezione esploreremo gli alberi decisionali, un approccio fondamentalmente diverso che apprende regole esplicite attraverso il partizionamento ricorsivo dei dati.
Impara Python con un tutor IA — gratis
Scrivi ed esegui vero codice nel tuo browser, ricevi aiuto istantaneo da un tutor IA disponibile 24/7, e riprendi da dove hai lasciato sul web o nell'app.
- Corsi
- 30
- Lezioni
- 120
Domande Frequenti
La lezione «KNN per la regressione e i suoi limiti di scalabilità» è gratuita?
Sì — il testo completo di «KNN per la regressione e i suoi limiti di scalabilità» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso Machine Learning Academy, passa a CoddyKit PRO. Il corso Machine Learning Academy include 4 lezioni in totale.
Cosa imparerò in «KNN per la regressione e i suoi limiti di scalabilità»?
Applicherà KNeighborsRegressor a un target continuo, quindi misurerà il tempo di previsione su dataset di grandi dimensioni per comprendere il costo d'inferenza O(n) di KNN. Eserciti Machine Learning Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.
Ho bisogno di esperienza per iniziare Machine Learning Academy?
Non è richiesta alcuna esperienza precedente. Machine Learning Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 4 di 4.
Quanto tempo richiede la lezione «KNN per la regressione e i suoi limiti di scalabilità»?
La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.
Posso scrivere ed eseguire codice in questa lezione Machine Learning Academy?
Sì. Ogni lezione Machine Learning Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.
Tutte le lezioni di questo corso
- Come funziona KNN: distanza, vicini e voti
- Scegliere k: metodo del gomito e curve di validazione
- Metriche di distanza: euclidea, Manhattan e Minkowski
- KNN per la regressione e i suoi limiti di scalabilità