ตัวชี้วัดระยะทาง: ยุคลิด แมนฮัตตัน และมินคอฟสกี
ผู้เรียนจะเปรียบเทียบตัวชี้วัดระยะทาง เข้าใจว่าเมื่อใดระยะทางแมนฮัตตันให้ผลดีกว่ายุคลิด และส่งตัวชี้วัดแบบกำหนดเองให้กับ KNeighborsClassifier
ตัวชี้วัดระยะทาง: ยุคลิด แมนฮัตตัน และมินคอฟสกี เป็นบทเรียน Machine Learning Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Machine Learning Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Machine Learning Academy มีบทเรียนทั้งหมด 4 บทเรียน
เหตุใดตัววัดระยะห่างจึงสำคัญใน KNN
KNN กำหนด เพื่อนบ้านที่ใกล้ที่สุด ด้วย ตัววัดระยะห่าง — ฟังก์ชันทางคณิตศาสตร์ที่วัดว่าจุดสองจุดอยู่ห่างกันเพียงใดในปริภูมิคุณลักษณะ การเลือกตัววัดส่งผลโดยตรงต่อเพื่อนบ้านที่จะถูกเลือก และส่งผลต่อสิ่งที่โมเดลทำนายด้วย ตัววัดแต่ละแบบตั้งสมมติฐานเกี่ยวกับเรขาคณิตของข้อมูลแตกต่างกัน ระยะห่างแบบยุคลิดถือว่าการเคลื่อนที่แนวทแยงมุมทำได้ ระยะห่างแบบแมนฮัตตันอนุญาตเฉพาะการเคลื่อนที่ตามแนวแกน ส่วนความคล้ายคลึงแบบโคไซน์ไม่สนใจขนาด แต่เน้นทิศทาง ไม่มีตัววัดใดดีที่สุดสำหรับทุกกรณี — ตัวเลือกที่เหมาะสมขึ้นอยู่กับโครงสร้างของปัญหา
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ระยะห่างแบบยุคลิด: นอร์ม L2
ระยะห่างแบบยุคลิด (เรียกอีกอย่างว่าระยะห่าง L2 หรือนอร์ม L2) วัดระยะเส้นตรงระหว่างจุดสองจุด ในสองมิติจะเป็นไปตามทฤษฎีบทพีทาโกรัส: sqrt(dx^2 + dy^2) ใน n มิติ: sqrt(sum of squared differences) นี่เป็นตัววัดที่เข้าใจได้ง่ายที่สุด และเป็นค่าเริ่มต้นในตัวจำแนก KNeighborsClassifier ระยะห่างแบบยุคลิดทำงานได้ดีเมื่อคุณลักษณะเป็นค่าต่อเนื่อง อยู่ในมาตราส่วนใกล้เคียงกัน และแนวคิดเรื่องความใกล้ในแนวทแยงมีความหมายทางกายภาพ เช่น พิกัดภูมิศาสตร์หรือค่าที่อ่านได้จากเซนเซอร์
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]))ระยะห่างแบบแมนฮัตตัน: นอร์ม L1
ระยะห่างแบบแมนฮัตตัน (นอร์ม L1 ระยะห่างแบบบล็อกเมือง หรือระยะห่างแบบแท็กซี่) หาผลรวมของ ผลต่างสัมบูรณ์ ตามแต่ละแกน: sum(|a_i - b_i|) ชื่อนี้มาจากผังถนนแบบตารางของแมนฮัตตัน — คุณเดินทางได้ตามแนวบล็อกเท่านั้น ไม่สามารถเดินทางแบบทแยงมุมได้ ระยะห่างแบบแมนฮัตตัน ทนต่อค่าผิดปกติได้ดีกว่า แบบยุคลิด เพราะใช้ค่าสัมบูรณ์แทนการยกกำลังสอง มักเลือกใช้กับข้อมูลหลายมิติ และคุณลักษณะที่แทนจำนวน คะแนน หรือปริมาณอื่น ๆ ซึ่งการเคลื่อนที่แนวทแยงไม่มีความหมายทางกายภาพ
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]))ระยะห่างแบบมิงคอฟสกี: การรวม L1 และ L2 ให้เป็นกรณีทั่วไป
ระยะห่างแบบมิงคอฟสกี เป็นกรณีทั่วไปที่รวมระยะห่างแบบยุคลิดและแมนฮัตตันไว้ในสูตรเดียว: (sum(|a_i - b_i|^p))^(1/p) เมื่อ p=1 จะเท่ากับระยะห่างแบบแมนฮัตตัน เมื่อ p=2 จะเท่ากับระยะห่างแบบยุคลิด เมื่อ p → infinity จะเข้าใกล้ระยะห่างแบบเชบีเชฟ (ผลต่างสูงสุดตามแกนใดแกนหนึ่ง) ในไซคิต-เลิร์น ตัวจำแนก KNeighborsClassifier ใช้ระยะห่างแบบมิงคอฟสกีโดยมี p=2 เป็นค่าเริ่มต้น คุณสามารถทดลองใช้ค่า p อื่นเป็นไฮเปอร์พารามิเตอร์ได้ แม้ในทางปฏิบัติค่า p ที่ไม่ใช่ 1 และ 2 จะไม่ค่อยถูกใช้
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))การส่งตัววัดไปยัง KNeighborsClassifier
ไซคิต-เลิร์นอนุญาตให้ระบุตัววัดระยะห่างผ่านพารามิเตอร์ metric ตัวเลือกข้อความที่พบบ่อย ได้แก่ 'euclidean', 'manhattan', 'minkowski' (พร้อมพารามิเตอร์ p เพิ่มเติม), 'chebyshev' และ 'cosine' นอกจากนี้ยังส่งฟังก์ชันไพธอนที่เรียกใช้งานได้เพื่อสร้างตัววัดแบบกำหนดเองได้ เมื่อใช้ตัววัดที่ไม่ใช่มาตรฐาน ให้ตั้งค่า algorithm='ball_tree' หรือ algorithm='kd_tree' เพื่อค้นหาเพื่อนบ้านอย่างมีประสิทธิภาพ หรือใช้ algorithm='brute' เพื่อการค้นหาแบบครบถ้วนที่รับประกันความถูกต้องแต่ช้ากว่า
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')ยุคลิดกับแมนฮัตตัน: การเปรียบเทียบในทางปฏิบัติ
เมื่อเปรียบเทียบแบบยุคลิดกับแบบแมนฮัตตันจากข้อมูลจริง ความแตกต่างจะเห็นได้ชัดที่สุดเมื่อมีคุณลักษณะที่เป็นค่าผิดปกติ แบบยุคลิดยกกำลังสองของผลต่าง ทำให้ค่าผิดปกติขนาดใหญ่เพียงค่าเดียวครอบงำระยะห่างทั้งหมด แบบแมนฮัตตันหาผลรวมของค่าสัมบูรณ์ จึงให้น้ำหนักกับความเบี่ยงเบนทั้งหมดตามสัดส่วน ในทางปฏิบัติ สำหรับข้อมูลภาพหรือการวัดทางกายภาพแบบต่อเนื่อง แบบยุคลิดมักให้ผลดีกว่า สำหรับข้อมูลกระจัดกระจายหลายมิติ (ข้อความ คะแนนผู้ใช้-รายการ หรือจำนวน) แบบแมนฮัตตันมักเสถียรกว่า เพราะไม่ขยายผลของมิติใดมิติหนึ่งมากเกินไป
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}')ความคล้ายคลึงแบบโคไซน์สำหรับข้อมูลข้อความ
ความคล้ายคลึงแบบโคไซน์ วัดมุมระหว่างเวกเตอร์สองตัวแทนขนาดของเวกเตอร์ เอกสารสองฉบับถือว่าคล้ายกันหากชี้ไปในทิศทางเดียวกันในปริภูมิคุณลักษณะ ไม่ว่าเอกสารจะมีความยาวเท่าใด ระยะห่างแบบโคไซน์ = 1 - ความคล้ายคลึงแบบโคไซน์ ตัววัดนี้เหมาะที่สุดสำหรับ การจำแนกข้อความด้วยเวกเตอร์ TF-IDF ซึ่งเอกสารสองฉบับอาจมีความยาวต่างกันมาก แต่ใช้คำศัพท์เดียวกันในสัดส่วนใกล้เคียงกัน โปรดทราบว่าระยะห่างแบบโคไซน์ไม่ใช่ตัววัดที่แท้จริง (ละเมิดอสมการสามเหลี่ยม) แต่ใช้งานได้ดีในทางปฏิบัติสำหรับ KNN กับข้อความ
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ระยะห่างแบบแฮมมิงสำหรับคุณลักษณะเชิงหมวดหมู่และไบนารี
ระยะห่างแบบแฮมมิง นับจำนวนตำแหน่งที่เวกเตอร์สองตัวมีค่าแตกต่างกัน เหมาะอย่างยิ่งสำหรับ คุณลักษณะแบบไบนารีหรือเชิงหมวดหมู่ ซึ่งแนวคิดเรื่องความแตกต่างของขนาดไม่มีความหมาย ตัวอย่างเช่น เมื่อเปรียบเทียบประวัติผู้ป่วยสองรายการที่เข้ารหัสเป็นเวกเตอร์อาการแบบไบนารี (1=มีอาการ, 0=ไม่มีอาการ) ระยะห่างแบบแฮมมิงจะนับจำนวนอาการที่แตกต่างกัน ในไซคิต-เลิร์น ให้ส่ง metric='hamming' ไปยัง KNeighborsClassifier ระยะห่างแบบแฮมมิงยังใช้เปรียบเทียบลำดับ DNA ตรวจจับข้อผิดพลาดในรหัสไบนารี และระบุลายนิ้วมือทางพันธุกรรมด้วย
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')คำสาปแห่งมิติและระยะห่าง
เมื่อจำนวนคุณลักษณะ (มิติ) เพิ่มขึ้น วิธีการทั้งหมดที่อาศัยระยะห่างจะประสบกับ คำสาปแห่งมิติ กล่าวคือ ในปริภูมิที่มีมิติสูง ระยะห่างระหว่างจุดสุ่มสองจุดใด ๆ จะเข้าใกล้ค่าเดียวกัน ทำให้จุดทั้งหมดดูเหมือนอยู่ห่างเท่า ๆ กัน เมื่อไม่สามารถแยกแยะระยะห่างได้ แนวคิดเรื่อง “เพื่อนบ้านที่ใกล้ที่สุด” ก็สูญเสียความหมาย นี่จึงเป็นเหตุผลที่โดยทั่วไป KNN ทำงานได้ดีที่สุดกับชุดข้อมูลที่มีคุณลักษณะน้อยกว่า 20–50 รายการ และเหตุใดจึงมักใช้ การลดจำนวนมิติ (PCA, การคัดเลือกคุณลักษณะ) ก่อนใช้ KNN ในกรณีที่มีมิติสูง
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การเลือกเมตริก: คู่มือเชิงปฏิบัติ
ต่อไปนี้คือแนวทางสำหรับเลือกเมตริกระยะห่าง: ใช้ Euclidean (L2) กับคุณลักษณะต่อเนื่องที่มีสเกลใกล้เคียงกัน (หลังใช้ StandardScaler); ใช้ Manhattan (L1) กับข้อมูลเบาบางหรือข้อมูลที่มีมิติสูง และเมื่อต้องการความทนทานต่อค่าผิดปกติ; ใช้ Cosine กับเวกเตอร์ข้อความ/TF-IDF ที่ไม่ควรให้ขนาดของเวกเตอร์มีผล; ใช้ Hamming กับคุณลักษณะแบบไบนารีหรือแบบจัดหมวดหมู่; ใช้ Minkowski with custom p เฉพาะเมื่อมีความรู้เฉพาะด้านที่บ่งชี้ว่าควรใช้เรขาคณิตแบบใดแบบหนึ่งโดยเฉพาะ ในทางปฏิบัติ ให้ลองใช้ Euclidean และ Manhattan ก่อน โดยใช้การตรวจสอบไขว้ แล้วเลือกวิธีที่ให้ผลดีที่สุด
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การรวมเมตริกในการค้นหาแบบกริด
คุณสามารถรวมพารามิเตอร์ metric ไว้ใน GridSearchCV เพื่อค้นหาชุดค่าที่ดีที่สุดของ k และเมตริกระยะห่างไปพร้อมกันได้ วิธีนี้ช่วยหลีกเลี่ยงการลองผิดลองถูกด้วยตนเองระหว่างเมตริกต่าง ๆ เมื่อค้นหาเมตริกที่ต้องใช้พารามิเตอร์เพิ่มเติม (เช่น p ของ Minkowski) ให้รวมพารามิเตอร์เหล่านั้นไว้ในกริดพารามิเตอร์ด้วย เมตริกที่ดีที่สุดขึ้นอยู่กับข้อมูล และมักไม่สามารถระบุได้อย่างชัดเจนจากความรู้เฉพาะด้านเพียงอย่างเดียว การให้การตรวจสอบไขว้เป็นผู้ตัดสินจึงเป็นทั้งวิธีที่มีหลักการและใช้ได้จริง
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_)ตรวจสอบความเข้าใจอย่างรวดเร็ว
ทดสอบความเข้าใจแนวคิด Machine Learning with Python จากบทเรียนนี้
สรุปบทเรียน
ในบทเรียนนี้ คุณได้เรียนรู้ว่า ระยะห่างแบบ Euclidean, Manhattan และ Minkowski แตกต่างกันทางคณิตศาสตร์อย่างไร และแต่ละแบบเหมาะกับกรณีใด รวมถึง ความคล้ายคลึงแบบโคไซน์สำหรับข้อมูลข้อความ และ Hamming สำหรับคุณลักษณะแบบไบนารี ตลอดจน คำสาปแห่งมิติ ที่ทำให้ระยะห่างทั้งหมดเข้าใกล้ค่าเดียวกันในปริภูมิที่มีมิติสูง บทถัดไป เราจะสำรวจ KNN สำหรับงานการถดถอยและข้อจำกัดด้านการขยายขนาดเมื่อใช้กับชุดข้อมูลขนาดใหญ่
เรียนรู้ Python ด้วย AI tutor — ฟรี
เขียนและเรียกใช้โค้ดจริงในเบราว์เซอร์ของคุณ รับความช่วยเหลือทันทีจาก AI tutor 24/7 และเรียนรู้ต่อจากที่คุณหยุดบนเว็บหรือในแอป
- คอร์ส
- 30
- บทเรียน
- 120
คำถามที่พบบ่อย
บทเรียน “ตัวชี้วัดระยะทาง: ยุคลิด แมนฮัตตัน และมินคอฟสกี” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “ตัวชี้วัดระยะทาง: ยุคลิด แมนฮัตตัน และมินคอฟสกี” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Machine Learning Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Machine Learning Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “ตัวชี้วัดระยะทาง: ยุคลิด แมนฮัตตัน และมินคอฟสกี”
ผู้เรียนจะเปรียบเทียบตัวชี้วัดระยะทาง เข้าใจว่าเมื่อใดระยะทางแมนฮัตตันให้ผลดีกว่ายุคลิด และส่งตัวชี้วัดแบบกำหนดเองให้กับ KNeighborsClassifier คุณปฏิบัติ Machine Learning Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Machine Learning Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน Machine Learning Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน
บทเรียน “ตัวชี้วัดระยะทาง: ยุคลิด แมนฮัตตัน และมินคอฟสกี” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน Machine Learning Academy นี้ได้ไหม
ได้ บทเรียน Machine Learning Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- KNN ทำงานอย่างไร: ระยะทาง เพื่อนบ้าน และคะแนนโหวต
- การเลือก k: วิธีข้อศอกและเส้นโค้งการตรวจสอบ
- ตัวชี้วัดระยะทาง: ยุคลิด แมนฮัตตัน และมินคอฟสกี
- KNN สำหรับการถดถอยและข้อจำกัดด้านการขยายขนาด