Machine Learning Academy · Lektion

Afstandsmål: Euklidisk, Manhattan og Minkowski

Sammenlign afstandsmål, forstå, hvornår Manhattan-afstand overgår euklidisk afstand, og videregiv brugerdefinerede mål til KNeighborsClassifier.

Lektion 3 af 413 trin

Afstandsmål: Euklidisk, Manhattan og Minkowski er en gratis Machine Learning Academy-lektion på CoddyKit. Dette er lektion 3 af 4. Du kan læse hele lektionen gratis nedenfor — og derefter øve dig praktisk i browseren med en indbygget kodeeditor og en AI-vejleder, der er tilgængelig døgnet rundt. Den er en del af læringsforløbet i Machine Learning Academy, og dine fremskridt synkroniseres på tværs af nettet og CoddyKit-appen. Machine Learning Academy-kurset indeholder 4 lektioner i alt.

Hvorfor afstandsmål er vigtige i KNN

KNN definerer nærmeste naboer ved hjælp af et afstandsmål — en matematisk funktion, der kvantificerer, hvor langt to punkter ligger fra hinanden i feature-rummet. Valget af mål påvirker direkte, hvilke naboer der vælges, og dermed hvad modellen forudsiger. Forskellige mål bygger på forskellige antagelser om dataenes geometri. Euklidisk afstand antager, at diagonal bevægelse er gyldig; Manhattan-afstand tillader kun bevægelse langs akserne; cosinuslighed ignorerer størrelsen og fokuserer på retningen. Intet enkelt mål er universelt bedst — det rigtige valg afhænger af problemets struktur.

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)  # 4

Euklidisk afstand: L2-norm

Euklidisk afstand (også kaldet L2-afstand eller L2-norm) måler den rette linje-afstand mellem to punkter. I 2D følger den Pythagoras' sætning: sqrt(dx^2 + dy^2). I n dimensioner: sqrt(sum of squared differences). Det er det mest intuitive afstandsmål og er standardværdien i KNeighborsClassifier. Euklidisk afstand fungerer godt, når features er kontinuerte, ligger på en lignende skala, og når diagonal nærhed giver fysisk mening — f.eks. for geografiske koordinater eller sensormålinger.

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]))

Manhattan-afstand: L1-norm

Manhattan-afstand (L1-norm, karréafstand, taxameterafstand) summerer de absolutte forskelle langs hver akse: sum(|a_i - b_i|). Navnet stammer fra Manhattans gitterformede gader — du kan kun bevæge dig langs karréerne, ikke diagonalt. Manhattan-afstand er mere robust over for outliers end euklidisk afstand, fordi den bruger absolutte værdier i stedet for kvadrater. Den foretrækkes ofte til data med mange dimensioner og til features, der repræsenterer antal, bedømmelser eller andre størrelser, hvor diagonal bevægelse ikke har nogen fysisk betydning.

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]))

Minkowski-afstand: Generalisering af L1 og L2

Minkowski-afstand er en generalisering, der samler euklidisk afstand og Manhattan-afstand i én formel: (sum(|a_i - b_i|^p))^(1/p). Når p=1, er den lig med Manhattan-afstand. Når p=2, er den lig med euklidisk afstand. Når p → infinity, nærmer den sig Chebyshev-afstand (den største forskel langs en enkelt akse). I scikit-learn bruger KNeighborsClassifier Minkowski-afstand med p=2 som standard. Du kan afprøve andre værdier af p som hyperparameter — selvom andre p-værdier end 1 og 2 sjældent bruges i praksis.

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))

Angivelse af afstandsmål til KNeighborsClassifier

Scikit-learn lader dig angive afstandsmålet via parameteren metric. Almindelige strengværdier omfatter 'euclidean', 'manhattan', 'minkowski' (med den ekstra parameter p), 'chebyshev' og 'cosine'. Du kan også angive en kaldbar Python-funktion som et brugerdefineret mål. Når du bruger ikke-standardiserede mål, skal du angive algorithm='ball_tree' eller algorithm='kd_tree' for effektiv opslag af naboer eller algorithm='brute' for en garanteret korrekt, men langsommere udtømmende søgning.

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')

Euklidisk afstand over for Manhattan-afstand: En praktisk sammenligning

Når du sammenligner euklidisk afstand og Manhattan-afstand empirisk, ses forskellen tydeligst, når der findes outlier-features. Euklidisk afstand kvadrerer forskellene, så én stor afvigelse dominerer den samlede afstand. Manhattan-afstand summerer absolutte værdier og behandler alle afvigelser proportionalt. I praksis klarer euklidisk afstand sig ofte bedst ved billeddata eller kontinuerte fysiske målinger. Ved højdimensionelle, sparsomme data (tekst, bruger-element-bedømmelser og antal) er Manhattan-afstand typisk mere stabil, fordi den ikke forstærker effekten af en enkelt dimension.

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}')

Cosinuslighed til tekstdata

Cosinuslighed måler vinklen mellem to vektorer i stedet for deres størrelse. To dokumenter betragtes som ens, hvis de peger i samme retning i feature-rummet, uanset dokumenternes længde. Cosinusafstand = 1 - cosinuslighed. Dette er det foretrukne mål til tekstklassifikation med TF-IDF-vektorer, hvor to dokumenter kan have meget forskellig længde, men bruge det samme ordforråd i lignende forhold. Bemærk, at cosinusafstand ikke er et ægte metrisk mål (den overholder ikke trekantsuligheden), men fungerer godt i praksis til KNN på tekst.

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))  # larger

Hammingafstand for kategoriske og binære features

Hammingafstand tæller antallet af positioner, hvor to vektorer er forskellige. Den er ideel til binære eller kategoriske features, hvor begrebet forskel i størrelse ikke giver mening. Hvis du for eksempel sammenligner to patientjournaler, der er kodet som binære symptomvektorer (1=til stede, 0=ikke til stede), tæller Hammingafstanden, hvor mange symptomer der er forskellige. I scikit-learn skal du angive metric='hamming' til KNeighborsClassifier. Hammingafstand bruges også til sammenligning af DNA-sekvenser, fejldetektion i binære koder og genetisk fingerprinting.

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')

Dimensionsforbandelsen og afstand

Efterhånden som antallet af features (dimensioner) vokser, påvirkes alle afstandsbaserede metoder af dimensionsforbandelsen: i høje dimensioner konvergerer afstanden mellem to vilkårlige punkter mod den samme værdi, så alle punkter ser ud til at ligge lige langt væk. Når afstandene ikke længere kan skelnes fra hinanden, mister begrebet »nærmeste nabo« sin betydning. Derfor fungerer KNN typisk bedst på datasæt med færre end 20-50 features, og derfor anvendes dimensionsreduktion (PCA, feature-udvælgelse) ofte før KNN i situationer med mange dimensioner.

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 indistinguishable

Valg af mål: en praktisk vejledning

Her er en vejledning til valg af afstandsmål: brug Euclidean (L2) til kontinuerte features på samme skala (efter StandardScaler); brug Manhattan (L1) til sparsomme data eller data med mange dimensioner, samt når der er behov for robusthed over for outliers; brug Cosine til tekst- og TF-IDF-vektorer, hvor størrelsen ikke bør have betydning; brug Hamming til binære eller kategoriske features; brug kun Minkowski med en tilpasset p-værdi, hvis du har domæneviden, der peger på en bestemt geometri. I praksis bør du først prøve Euclidean og Manhattan ved hjælp af krydsvalidering og vælge den bedste.

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)) # euclidean

Inkludering af mål i netsøgning

Du kan inkludere parameteren metric i din GridSearchCV for at finde den bedste kombination af k og afstandsmål samtidig. Det eliminerer behovet for manuel prøve-og-fejl på tværs af mål. Når du søger blandt mål, der kræver yderligere parametre (som Minkowskis p), skal du også inkludere dem i parametergitteret. Det bedste mål afhænger af dataene og er ofte ikke indlysende ud fra domæneviden alene — det er både principielt og praktisk at lade krydsvalideringen afgøre det.

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_)

Hurtigt tjek

Test din forståelse af begreberne inden for Machine Learning with Python fra denne lektion.

Opsummering af lektionen

I denne lektion lærte du: hvordan Euclidean-, Manhattan- og Minkowski-afstande adskiller sig matematisk, og hvornår hver af dem er passende, cosinuslighed til tekstdata og Hammingafstand til binære features samt dimensionsforbandelsen, der får alle afstande til at konvergere i rum med mange dimensioner. Dernæst undersøger vi KNN til regressionsopgaver og metodens begrænsninger med hensyn til skalerbarhed på store datasæt.

Gratis at komme i gang

Lær Python med en AI-underviser — gratis

Skriv og kør rigtig kode i din browser, få øjeblikkelig hjælp fra en AI-underviser døgnet rundt, og fortsæt, hvor du slap, på web eller i appen.

Kurser
30
Lektioner
120

Ofte stillede spørgsmål

Er lektionen “Afstandsmål: Euklidisk, Manhattan og Minkowski” gratis?

Ja — hele teksten til “Afstandsmål: Euklidisk, Manhattan og Minkowski” kan læses gratis her på nettet. Hvis du vil øve dig interaktivt med en indbygget kodeeditor og en AI-vejleder døgnet rundt og få adgang til resten af Machine Learning Academy-kurset, skal du opgradere til CoddyKit PRO. Machine Learning Academy-kurset indeholder 4 lektioner i alt.

Hvad lærer jeg i “Afstandsmål: Euklidisk, Manhattan og Minkowski”?

Sammenlign afstandsmål, forstå, hvornår Manhattan-afstand overgår euklidisk afstand, og videregiv brugerdefinerede mål til KNeighborsClassifier. Du øver dig i Machine Learning Academy med praktisk kode, som du kører direkte i browseren, og en AI-vejleder døgnet rundt besvarer dine spørgsmål, mens du arbejder dig gennem lektionen.

Skal jeg have erfaring for at begynde på Machine Learning Academy?

Der kræves ingen tidligere erfaring. Machine Learning Academy på CoddyKit er tilrettelagt for både begyndere og øvede, så du kan starte her eller fra begyndelsen og lære i dit eget tempo. Dette er lektion 3 af 4.

Hvor lang tid tager lektionen “Afstandsmål: Euklidisk, Manhattan og Minkowski”?

De fleste CoddyKit-lektioner tager cirka 5–10 minutter. Hver lektion er kort og interaktiv, så du gør løbende fremskridt og kan fortsætte, hvor du slap – på både web og app.

Kan jeg skrive og køre kode i denne Machine Learning Academy-lektion?

Ja. Alle Machine Learning Academy-lektioner har en indbygget kodeeditor, så du kan skrive og køre rigtig kode direkte i din browser og få øjeblikkelig feedback fra AI – uden lokal opsætning.

Alle lektioner i dette kursus

  1. Sådan fungerer KNN: Afstande, naboer og stemmer
  2. Valg af k: Albue-metoden og valideringskurver
  3. Afstandsmål: Euklidisk, Manhattan og Minkowski
  4. KNN til regression og metodens skaleringsbegrænsninger
← Tilbage til Machine Learning Academy