《統計學習方法》第3章 K鄰近法
阿新 • • 發佈:2020-10-08
目錄
中根據分類決策規則(如多數表決)決定 x 的類別 y
對於新的例項,根據其 k 個最近鄰的訓練例項的類別的,通過多數表決等方式進行預測
K鄰近法的三個基本要素:
- k 值的選擇
- 距離量度
- 分類決策規則
演算法
輸入:訓練資料集 \(T = \{(x_{1}, y_{1}),(x_{2}, y_{2}),\ldots,(x_{N}, y_{N})\}\)
輸出:例項 x 所屬的類 y
(1)根據給定的距離度量,在訓練集 T 中找出與 x 最鄰近的 k 個點,記作 \(N_{k}(x)\)
(2)在 \(N_{k}(x)\)
K鄰近法沒有學習過程
距離度量
一般使用的距離是歐氏距離,也可以是更一般的 \(L_{p}\) 距離或 Minkowski 距離
\[L_{p}(x_{i},x_{j}) = (\sum_{l=1}^{n}|x_{i}^{(l)}-x_{j}^{(l)}|^{p})^{1/p} \]當 \(p = 2\) 時,稱為歐式距離
當 \(p = 1\) 時,稱為曼哈頓距離
當 \(p = \infty\) 時,是各個座標距離的最大值
k 值的選擇
k 值的減小意味著整體模型變得複雜,容易發生過擬合
分類決策規則
往往是多數表決
程式碼實現
載入庫
import numpy as np
import pandas as pd
from scipy import stats
from sklearn.datasets import load_iris
import matplotlib.pyplot as plt
%matplotlib inline
準備資料
data = load_iris()
iris_df = pd.DataFrame(data.data, columns=data.feature_names)
iris_df['label'] = data.target
iris_df.head()
檢查原始資料
data.target_names sepal_features = ['sepal length (cm)','sepal width (cm)'] setosa = iris_df[iris_df.label == 0][sepal_features] versicolor = iris_df[iris_df.label == 1][sepal_features] plt.scatter(setosa.values[:,0], setosa.values[:,1], label='setosa') plt.scatter(versicolor.values[:,0], versicolor.values[:,1], label='versicolor') plt.xlabel(sepal_features[0]) plt.xlabel(sepal_features[1]) plt.legend()
準備演算法模型
class Model():
def __init__(self, k=3):
self.k = k
def fit(self, X_train, y_train):
self.X = X_train
self.y = y_train
def predict(self, X_pred):
lambda_min_dist = lambda x: np.argsort(np.linalg.norm(X_train - x, ord=2, axis=1))
min_dist_idx = np.apply_along_axis(lambda_min_dist, axis=1, arr=X_pred)
idx_mode = stats.mode(y_train[min_dist_idx[:,:self.k]], axis=1)[0]
return idx_mode.flatten()
準備訓練資料及測試資料
sepal_features = ['sepal length (cm)','sepal width (cm)']
X_train = iris_df[iris_df.label.isin([0,1])][sepal_features].values
y_train = iris_df[iris_df.label.isin([0,1])]['label'].values
X_pred = np.random.rand(20, 2) * [2.5, 1.5] + [4.5, 2.5]
X_pred.shape
訓練及預測
model = Model()
model.fit(X_train, y_train)
y_pred = model.predict(X_pred)
print(y_pred)
檢視結果
sepal_features = ['sepal length (cm)','sepal width (cm)']
setosa = iris_df[iris_df.label == 0][sepal_features]
versicolor = iris_df[iris_df.label == 1][sepal_features]
plt.scatter(X_pred[y_pred==0][:,0], X_pred[y_pred==0][:,1], label='0')
plt.scatter(X_pred[y_pred==1][:,0], X_pred[y_pred==1][:,1], label='1')
plt.scatter(setosa.values[:,0], setosa.values[:,1], label='setosa')
plt.scatter(versicolor.values[:,0], versicolor.values[:,1], label='versicolor')
plt.xlabel(sepal_features[0])
plt.xlabel(sepal_features[1])
plt.legend()