1. 程式人生 > 實用技巧 >《統計學習方法》第3章 K鄰近法

《統計學習方法》第3章 K鄰近法

目錄

對於新的例項,根據其 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)\)

中根據分類決策規則(如多數表決)決定 x 的類別 y

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