Metriche di distanza: euclidea, Manhattan e Minkowski
Confronterà le metriche di distanza, comprenderà quando la distanza Manhattan supera quella euclidea e passerà metriche personalizzate a KNeighborsClassifier.
Metriche di distanza: euclidea, Manhattan e Minkowski è una lezione Machine Learning Academy gratuita su CoddyKit. Questa è la lezione 3 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.
Perché le metriche di distanza sono importanti in KNN
KNN definisce i vicini più prossimi usando una metrica di distanza — una funzione matematica che quantifica la distanza tra due punti nello spazio delle feature. La scelta della metrica determina direttamente quali vicini vengono selezionati e, di conseguenza, le predizioni del modello. Metr iche diverse implicano ipotesi diverse sulla geometria dei dati. La distanza euclidea presuppone che lo spostamento diagonale sia valido; la distanza Manhattan consente solo spostamenti paralleli agli assi; la similarità coseno ignora la magnitudine e si concentra sulla direzione. Nessuna metrica è universalmente migliore: la scelta corretta dipende dalla struttura del problema.
import numpy as np
A = np.array([0, 0])
B = np.array([3, 4])
# Euclidean: straight-line distance
euclidean = np.sqrt(np.sum((A - B)**2))
print('Euclidean:', euclidean) # 5.0
# Manhattan: sum of absolute differences
manhattan = np.sum(np.abs(A - B))
print('Manhattan:', manhattan) # 7
# Chebyshev: maximum single-axis difference
chebyshev = np.max(np.abs(A - B))
print('Chebyshev:', chebyshev) # 4Distanza euclidea: norma L2
La distanza euclidea (chiamata anche distanza L2 o norma L2) misura la distanza in linea retta tra due punti. In 2D segue il teorema di Pitagora: sqrt(dx^2 + dy^2). In n dimensioni: sqrt(sum of squared differences). È la metrica più intuitiva ed è quella predefinita in KNeighborsClassifier. La distanza euclidea funziona bene quando le feature sono continue, hanno una scala simile e la nozione di prossimità diagonale ha senso dal punto di vista fisico, ad esempio nel caso di coordinate geografiche o letture di sensori.
import numpy as np
def euclidean(a, b):
return np.sqrt(np.sum((np.array(a) - np.array(b))**2))
# 2D example
print('2D:', euclidean([0, 0], [3, 4])) # 5.0
# 3D example
print('3D:', euclidean([1, 2, 3], [4, 6, 3]).round(2)) # 5.0
# Using scipy for efficiency
from scipy.spatial.distance import euclidean as sp_euclidean
print('scipy:', sp_euclidean([0, 0], [3, 4]))Distanza Manhattan: norma L1
La distanza Manhattan (norma L1, distanza a blocchi o distanza del taxi) somma le differenze assolute lungo ciascun asse: sum(|a_i - b_i|). Il nome deriva dalla disposizione a griglia delle strade di Manhattan: è possibile spostarsi solo lungo i blocchi, non in diagonale. La distanza Manhattan è più robusta rispetto agli outlier di quella euclidea perché utilizza valori assoluti anziché quadrati. È spesso preferita per i dati ad alta dimensionalità e per le feature che rappresentano conteggi, valutazioni o altre quantità per le quali lo spostamento diagonale non ha un significato fisico.
import numpy as np
def manhattan(a, b):
return np.sum(np.abs(np.array(a) - np.array(b)))
print('Manhattan (0,0)-(3,4):', manhattan([0,0], [3,4])) # 7
print('Euclidean (0,0)-(3,4):', np.linalg.norm([3,4])) # 5.0
# Manhattan treats 3+4=7 units of travel
# Euclidean takes the diagonal shortcut = 5.0
# In a grid city, only Manhattan is physically achievable
from scipy.spatial.distance import cityblock
print('scipy cityblock:', cityblock([0,0], [3,4]))Distanza di Minkowski: generalizzazione di L1 e L2
La distanza di Minkowski è una generalizzazione che unifica la distanza euclidea e quella Manhattan in un'unica formula: (sum(|a_i - b_i|^p))^(1/p). Quando p=1, equivale alla distanza Manhattan. Quando p=2, equivale alla distanza euclidea. Quando p → infinity, tende alla distanza di Chebyshev (la massima differenza lungo un singolo asse). In scikit-learn, KNeighborsClassifier utilizza Minkowski con p=2 per impostazione predefinita. Può esplorare altri valori di p come iperparametro, anche se nella pratica i valori di p diversi da 1 e 2 vengono usati raramente.
import numpy as np
def minkowski(a, b, p):
a, b = np.array(a), np.array(b)
return np.sum(np.abs(a - b)**p)**(1/p)
a, b = [0, 0], [3, 4]
for p in [1, 2, 3, 10, 100]:
d = minkowski(a, b, p)
print(f'p={p}: {d:.4f}')
# p=1 -> 7.0 (Manhattan)
# p=2 -> 5.0 (Euclidean)
# p->inf -> 4.0 (Chebyshev = max(3,4))Passare le metriche a KNeighborsClassifier
Scikit-learn consente di specificare la metrica di distanza tramite il parametro metric. Tra le opzioni testuali comuni figurano 'euclidean', 'manhattan', 'minkowski' (con l'ulteriore parametro p), 'chebyshev' e 'cosine'. È anche possibile passare una funzione Python richiamabile come metrica personalizzata. Quando utilizza metriche non standard, imposti algorithm='ball_tree' o algorithm='kd_tree' per una ricerca efficiente dei vicini, oppure algorithm='brute' per una ricerca esaustiva garantita corretta ma più lenta.
from sklearn.neighbors import KNeighborsClassifier
# Euclidean (default)
knn_l2 = KNeighborsClassifier(n_neighbors=5, metric='euclidean')
# Manhattan
knn_l1 = KNeighborsClassifier(n_neighbors=5, metric='manhattan')
# Minkowski with p=1.5
knn_mk = KNeighborsClassifier(n_neighbors=5, metric='minkowski', p=1.5)
# Chebyshev
knn_ch = KNeighborsClassifier(n_neighbors=5, metric='chebyshev')
# Cosine similarity (for text/angle-based)
knn_cos = KNeighborsClassifier(n_neighbors=5, metric='cosine',
algorithm='brute')Euclidea e Manhattan: un confronto pratico
Confrontando empiricamente la distanza euclidea e quella Manhattan, la differenza emerge più chiaramente in presenza di feature con outlier. La distanza euclidea eleva al quadrato le differenze, facendo sì che una deviazione elevata domini la distanza totale. La distanza Manhattan somma i valori assoluti, trattando tutte le deviazioni in modo proporzionale. Nella pratica, per i dati delle immagini o le misurazioni fisiche continue, spesso prevale la distanza euclidea. Per i dati sparsi ad alta dimensionalità (testo, valutazioni utente-elemento, conteggi), la distanza Manhattan tende a essere più stabile perché non amplifica l'effetto di una singola dimensione.
from sklearn.neighbors import KNeighborsClassifier
from sklearn.model_selection import cross_val_score
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.datasets import load_wine
X, y = load_wine(return_X_y=True)
for metric in ['euclidean', 'manhattan', 'chebyshev']:
pipe = Pipeline([
('sc', StandardScaler()),
('knn', KNeighborsClassifier(n_neighbors=5, metric=metric))
])
score = cross_val_score(pipe, X, y, cv=10).mean()
print(f'{metric:12}: {score:.3f}')Similarità coseno per i dati testuali
La similarità coseno misura l'angolo tra due vettori anziché la loro magnitudine. Due documenti sono considerati simili se puntano nella stessa direzione nello spazio delle caratteristiche, indipendentemente dalla lunghezza del documento. Distanza coseno = 1 - similarità coseno. Questa è la metrica preferita per la classificazione del testo con vettori TF-IDF, dove due documenti possono avere lunghezze molto diverse ma usare lo stesso vocabolario in proporzioni simili. Si noti che la distanza coseno non è una vera metrica (viola la disuguaglianza triangolare), ma funziona bene nella pratica per KNN sul testo.
import numpy as np
def cosine_distance(a, b):
a, b = np.array(a, dtype=float), np.array(b, dtype=float)
cos_sim = np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b))
return 1 - cos_sim
# Long and short documents with same topic should be close
doc1 = [2, 1, 0, 3] # counts of words: 'python', 'ml', 'java', 'data'
doc2 = [4, 2, 0, 6] # same proportions, longer document
doc3 = [0, 0, 5, 1] # different topic
print('doc1 vs doc2 (same topic):', cosine_distance(doc1, doc2).round(3)) # near 0
print('doc1 vs doc3 (diff topic):', cosine_distance(doc1, doc3).round(3)) # largerDistanza di Hamming per caratteristiche categoriche e binarie
La distanza di Hamming conta il numero di posizioni in cui due vettori differiscono. È ideale per le caratteristiche binarie o categoriche, per le quali il concetto di differenza di magnitudine non è significativo. Ad esempio, confrontando due cartelle cliniche codificate come vettori binari dei sintomi (1=presente, 0=assente), la distanza di Hamming conta quanti sintomi differiscono. In scikit-learn, passi metric='hamming' a KNeighborsClassifier. La distanza di Hamming viene usata anche per confrontare sequenze di DNA, rilevare errori nei codici binari e analizzare le impronte genetiche.
import numpy as np
def hamming(a, b):
a, b = np.array(a), np.array(b)
return np.sum(a != b) / len(a)
# Binary symptom vectors: [fever, cough, headache, fatigue]
patient1 = [1, 1, 0, 1]
patient2 = [1, 1, 1, 1] # only headache differs
patient3 = [0, 0, 1, 0] # very different
print('p1 vs p2:', hamming(patient1, patient2)) # 0.25
print('p1 vs p3:', hamming(patient1, patient3)) # 0.75
# sklearn usage
from sklearn.neighbors import KNeighborsClassifier
knn = KNeighborsClassifier(n_neighbors=3, metric='hamming')La maledizione della dimensionalità e la distanza
All'aumentare del numero di caratteristiche (dimensioni), tutti i metodi basati sulla distanza risentono della maledizione della dimensionalità: in dimensioni elevate, la distanza tra due punti casuali qualsiasi converge allo stesso valore, facendo apparire tutti i punti equidistanti. Quando le distanze diventano indistinguibili, il concetto di "vicino più prossimo" perde significato. Per questo KNN in genere offre le prestazioni migliori su dataset con meno di 20-50 caratteristiche e per questo, in contesti ad alta dimensionalità, prima di KNN si applica spesso la riduzione della dimensionalità (PCA, selezione delle caratteristiche).
import numpy as np
np.random.seed(42)
for d in [2, 10, 50, 100, 500]:
# Random points in d-dimensional unit hypercube
X = np.random.rand(1000, d)
query = np.random.rand(d)
dists = np.linalg.norm(X - query, axis=1)
# High-dimensional: max/min ratio -> 1 (all distances similar)
ratio = dists.max() / dists.min()
print(f'd={d:3}: min={dists.min():.2f}, max={dists.max():.2f}, ratio={ratio:.2f}')
# As d grows, ratio approaches 1: distances become indistinguishableScegliere una metrica: guida pratica
Ecco una guida per scegliere la metrica della distanza: usi Euclidea (L2) per caratteristiche continue su scale simili (dopo StandardScaler); usi Manhattan (L1) per dati sparsi o ad alta dimensionalità e quando è necessaria robustezza rispetto agli outlier; usi Coseno per vettori di testo/TF-IDF, quando la magnitudine non dovrebbe contare; usi Hamming per caratteristiche binarie o categoriche; usi Minkowski con p personalizzato solo se dispone di conoscenze del dominio che suggeriscono una geometria specifica. Nella pratica, provi prima Euclidea e Manhattan usando la convalida incrociata e scelga quella con i risultati migliori.
def recommend_metric(data_type, is_sparse, has_outliers):
if data_type == 'text':
return 'cosine'
elif data_type == 'binary' or data_type == 'categorical':
return 'hamming'
elif is_sparse or has_outliers:
return 'manhattan'
else:
return 'euclidean' # default, safe choice
print(recommend_metric('text', False, False)) # cosine
print(recommend_metric('binary', False, False)) # hamming
print(recommend_metric('continuous', True, False)) # manhattan
print(recommend_metric('continuous', False, False)) # euclideanIncludere la metrica nella ricerca a griglia
Può includere il parametro metric in GridSearchCV per trovare simultaneamente la combinazione migliore di k e metrica della distanza. In questo modo evita di provare manualmente le diverse metriche per tentativi. Quando cerca tra metriche che richiedono parametri aggiuntivi (come p di Minkowski), includa anche questi parametri nella griglia. La metrica migliore dipende dai dati e spesso non è evidente basandosi solo sulle conoscenze del dominio: lasciare che sia la convalida incrociata a decidere è sia rigoroso sia pratico.
from sklearn.model_selection import GridSearchCV
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.neighbors import KNeighborsClassifier
pipe = Pipeline([('sc', StandardScaler()), ('knn', KNeighborsClassifier())])
param_grid = [
{'knn__n_neighbors': [3, 5, 7, 11],
'knn__metric': ['euclidean', 'manhattan'],
'knn__weights': ['uniform', 'distance']},
{'knn__n_neighbors': [3, 5, 7],
'knn__metric': ['minkowski'],
'knn__p': [1, 1.5, 2, 3]}
]
grid = GridSearchCV(pipe, param_grid, cv=10, scoring='accuracy', n_jobs=-1)
grid.fit(X_train, y_train)
print('Best params:', grid.best_params_)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: in che modo le distanze euclidea, Manhattan e Minkowski differiscono matematicamente e quando è opportuno usare ciascuna di esse, la similarità coseno per i dati testuali e la distanza di Hamming per le caratteristiche binarie, nonché la maledizione della dimensionalità, che fa convergere tutte le distanze negli spazi ad alta dimensionalità. Nella prossima lezione esploreremo KNN per i problemi di regressione e i suoi limiti di scalabilità sui dataset di grandi dimensioni.
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 «Metriche di distanza: euclidea, Manhattan e Minkowski» è gratuita?
Sì — il testo completo di «Metriche di distanza: euclidea, Manhattan e Minkowski» è 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 «Metriche di distanza: euclidea, Manhattan e Minkowski»?
Confronterà le metriche di distanza, comprenderà quando la distanza Manhattan supera quella euclidea e passerà metriche personalizzate a KNeighborsClassifier. 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 3 di 4.
Quanto tempo richiede la lezione «Metriche di distanza: euclidea, Manhattan e Minkowski»?
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à