有監督學習--分類模型--K 近鄰(kNN)0.引入依賴1.數據的加載和預處理2.核心算法實現3.測試4.自動化測試python
import numpy as np # 數值計算、矩陣運算、向量運算
import pandas as pd # 數值分析、科學計算
# 這裏直接引入 sklearn 裏的數據集 --> iris 鳶尾花
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split # 切分數據集爲訓練集和測試集
from sklearn.metrics import accuracy_score # 計算分類預測的準確率
iris = load_iris()
# iris # 字典
# type(iris) # sklearn.utils.Bunch
df = pd.DataFrame(data=iris.data, columns=iris.feature_names)
# print(df)
df['class'] = iris.target
df['class'] = df['class'].map({0: iris.target_names[0], 1: iris.target_names[1], 2: iris.target_names[2]})
# df
df.describe()
輸出結果以下:算法
小測試:數組
x = iris.data
# x # x 是二維數組
# y = iris.target
# y # y 是一維數組,須要轉成二維數組
y = iris.target.reshape(-1, 1) # 變成 n 行 1 列的列向量
# y
print(x.shape, y.shape) # (150, 4) (150, 1)
輸出結果:app
(150, 4) (150, 1)
劃分訓練集和測試集:dom
# 劃分訓練集和測試集,第三個參數咱們選取簡單交叉驗證,第四個參數表示隨機劃分,第五個參數表示按照 y 的分佈等比例分割
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.3, random_state=35, stratify=y)
print(x_train.shape, y_train.shape)
print(x_test.shape, y_test.shape)
# 測試
# x_test = x_test[0].reshape(1, -1) # 將一維數組 x.test[0] 變爲 二維數組
# x_test.shape # (1, 4)
# print(x_train)
# print(x_test)
# np.sum(np.abs(x_train - x_test), axis=1)
# distances = np.array([2, 1, 5, 4, 3, 11, 15, 20, 9, 110])
# print(np.argsort(distances)) # [1 0 4 3 2 8 5 6 7 9]
# nn_index = np.argsort(distances)
# print(nn_index[0:3]) # [1 0 4]
# nn_y = y_train[nn_index[0:3]].ravel()
# print(nn_y) # [2 1 1]
# print(np.bincount(nn_y)) # [0 2 1]
# print(np.argmax(np.bincount(nn_y))) # 1
輸出結果:函數
(105, 4) (105, 1)
(45, 4) (45, 1)
# 定義距離函數
# 曼哈頓距離的平方
def l1_distance(a, b): # 這裏要求:a 能夠是矩陣,b 必須是向量,且是行向量
return np.sum(np.abs(a - b), axis=1) # axis=1 表示將 sum 的運算結果保存成 1 列
# 歐式距離
def l2_distance(a, b):
return np.sqrt(np.sum((a - b) ** 2, axis=1))
# 分類器實現
class kNN(object):
# 定義一個初始化方法,形式是 __init__ 是類的構造方法
def __init__(self, n_neighbors=1, dist_func=l1_distance):
self.n_neighbors = n_neighbors
self.dist_func = dist_func
# 定義模型的訓練方法
def fix(self, x, y):
self.x_train = x
self.y_train = y
# 定義模型的預測方法
def predict(self, x):
# 初始化預測分類數組
y_pred = np.zeros((x.shape[0], 1), dtype=self.y_train.dtype)
# 遍歷輸入的 x 數據點,取出每個數據點的序號 i 和數據 x_test
for i, x_test in enumerate(x):
# 計算 x_test 與各個訓練數據之間的距離
distances = self.dist_func(self.x_train, x_test)
# 獲得的距離按照由近到遠排序,取的是索引值
nn_index = np.argsort(distances)
# 選取最近的 k 個點,保存它們對應的分類類別
nn_y = self.y_train[nn_index[0:self.n_neighbors]].ravel()
# 統計類別中出現頻率最高的那個,賦值給 y_pred[i]
y_pred[i] = np.argmax(np.bincount(nn_y))
return y_pred
# 定義一個 kNN 的實例
knn = kNN(n_neighbors=3)
# 訓練模型
knn.fix(x_train, y_train)
# 測試模型
y_pred = knn.predict(x_test)
# 求出預測的準確率
accuracy = accuracy_score(y_test, y_pred)
print('預測準確率:', accuracy)
輸出結果:學習
預測準確率: 0.9333333333333333
# 定義一個 kNN 的實例
knn = kNN()
# 訓練模型
knn.fix(x_train, y_train)
# 保存結果 list
result_list = []
# 針對不一樣的參數選取作預測
for p in [1, 2]:
knn.dist_func = l1_distance if p == 1 else l2_distance
# 考慮不一樣的 k 取值
for k in range(1, 10, 2): # 1, 3, 5, 7, 9 注意:二元分類中咱們選取 k 爲奇數,可是本題中是三元分類,效果不明顯
knn.n_neighbors = k
# 傳入測試數據,測試模型
y_pred = knn.predict(x_test)
# 求出預測的準確率
accuracy = accuracy_score(y_test, y_pred)
result_list.append([k, 'l1_distance' if p == 1 else 'l2_distance', accuracy])
df = pd.DataFrame(result_list, columns=['k', '距離函數', '預測正確率'])
df
輸出結果以下:測試