Python k-NN 練習:距離、投票與縮放
k-NN 是很好的第一個分類器,因為每個決定都看得見:距離、鄰居、投票和評估都能檢查。這些練習讓每一步都可以測試。
只寫一次距離函式
保留一個距離函式,在排序和評估中復用。小函式比散落在迴圈裡的距離邏輯更容易測試。比較點之前要檢查維度是否一致。
def distance(a, b):
return sum((x - y) ** 2 for x, y in zip(a, b)) ** 0.5
print(distance((0, 0), (3, 4)))可復用的度量
帶著標籤排序
按距離排序 (點, 標籤) 對,而不是先排點、之後再查標籤。這樣預測始終和證據綁定,也避免排序後索引錯位。
def distance(a, b):
return sum((x - y) ** 2 for x, y in zip(a, b)) ** 0.5
points = [((1, 1), "a"), ((4, 4), "b"), ((1, 2), "a")]
target = (1, 1.5)
ranked = sorted(points, key=lambda item: distance(target, item[0]))
print(ranked[:2])標籤跟著點走
用確定的平票規則投票
取前 k 個標籤並計數。如果兩個標籤平票,使用明確規則,例如選擇距離最近的平票點。隨機或依賴雜湊順序的平票規則會讓相同輸入產生不同預測。
from collections import Counter
labels = ["a", "b", "a", "c"]
winner = Counter(labels).most_common(1)[0][0]
print(winner)可復現的投票
度量前先縮放
距離把每個單位視為同等重要。收入以千計、年齡以年計時,收入會佔主導。用訓練統計量標準化特徵,再把同一變換應用到驗證集和測試集。
def distance(a, b):
return sum((x - y) ** 2 for x, y in zip(a, b)) ** 0.5
raw = distance((30, 30000), (30, 31000))
scaled = distance((0.3, 0.3), (0.3, 1.0))
print(round(raw, 1), round(scaled, 1))單位改變答案
用留出點評估
在訓練集上預測不是評估。使用訓練/測試劃分,資料很小時可以用留一法。還要報告基線:多數類預測往往出人意料地強。
data = [((0, 0), "a"), ((1, 0), "a"), ((5, 5), "b")]
correct = 0
for i, (point, label) in enumerate(data):
train = data[:i] + data[i + 1:]
nearest = min(train, key=lambda item: (item[0][0] - point[0]) ** 2 + (item[0][1] - point[1]) ** 2)
correct += nearest[1] == label
print(correct, len(data))留一法
你的練習清單
- 排序和評估使用同一個經過測試的距離函式。
- 排序時讓標籤始終跟隨對應的點。
- 評估前確定 k 和確定的平票規則。
- 只在訓練資料上配適縮放參數。
- 與多數類基線比較。
常見問題
k 怎麼選?
二分類可從小奇數開始,再在驗證資料上評估多個值。k 太小雜訊大,k 太大會抹平局部結構。
應該標準化還是歸一化?
兩者都可以。標準化按標準差中心化縮放;最小-最大歸一化映射到固定區間。關鍵是變換隻在訓練資料上配適。
k-NN 計算貴嗎?
預測時要把新點與所有訓練點比較,大資料集需要近似索引或換模型。
練習 k-NN
12 道題,覆蓋距離、鄰居、投票、縮放和留出評估。
繼續閱讀: