AI工程師成長之路-KNN迴歸演算法實現
阿新 • • 發佈:2018-12-15
本博文是博主在阿里雲大學學習記錄的筆記,未經博主允許禁止隨意轉載。
需要資料集的可以聯絡博主獲取
本實驗將學習如何使用Python實現KNN迴歸演算法。
說明:本實驗的程式檔案與資料在啟動jupyter notebook後,就會在主目錄中顯示,可以直接開啟檢視並執行,但為了增加熟練度,達到最佳的學習效果,建議大家手動輸入。
①匯入程式執行所需的庫。
import numpy as np
import pandas as pd
②載入鳶尾花資料集。並刪除不需要的Id列。然後對資料集進行去重處理。
data = pd.read_csv(r"Iris.csv") # 刪除不需要的ID與Species列(特徵)。因為現在進行迴歸預測,類別資訊就沒有用處了。 data.drop(["Id", "Species"], axis=1, inplace=True) # 刪除重複的記錄 data.drop_duplicates(inplace=True)
③定義KNN類,用於迴歸。並在類中定義初始化方法與訓練與預測方法。
class KNN: """使用Python實現K近鄰演算法。(迴歸預測) 該演算法用於迴歸預測,根據前3個特徵屬性,尋找最近的k個鄰居,然後再根據k個鄰居的第4個特徵 屬性,去預測當前樣本的第4個特徵值。 """ def __init__(self, k): """初始化方法 Parameters ----- k : int 鄰居的個數。 """ self.k = k def fit(self, X, y): """訓練方法。 Parameters ----- X : 類陣列型別(特徵矩陣)。形狀為[樣本數量, 特徵數量] 待訓練的樣本特徵(屬性)。 y : 類陣列型別(目標標籤)。形狀為[樣本數量] 每個樣本的目標值(標籤) """ # 注意,將X與y轉換成ndarray陣列的形式,方便統一進行操作。 self.X = np.asarray(X) self.y = np.asarray(y) def predict(self, X): """根據引數傳遞的X,對樣本資料進行預測。 Paramters: ----- X : 類陣列型別。形狀為[樣本數量, 特徵數量] 待測試的樣本特徵(屬性) Returns ----- result : 陣列型別。 預測的結果值。 """ # 轉換成陣列型別 X = np.asarray(X) # 儲存預測的結果值。 result = [] for x in X: # 計算距離。(計算與訓練集中每個X的距離) dis = np.sqrt(np.sum((x - self.X) ** 2, axis=1)) # 返回陣列排序後,每個元素在原陣列中(排序之前的陣列)的索引。 index = dis.argsort() # 取前k個距離最近的索引(在原陣列中的索引)。 index = index[:self.k] # 計算均值,然後加入到結果列表當中。 result.append(np.mean(self.y[index])) return np.array(result) def predict2(self, X): """根據引數傳遞的X,對樣本資料進行預測。(考慮權重) 權重的計算方式: 使用每個節點(鄰居)距離的倒數 / 所有節點距離倒數之和。 Paramters: ----- X : 類陣列型別。形狀為[樣本數量, 特徵數量] 待測試的樣本特徵(屬性) Returns ----- result : 陣列型別。 預測的結果值。 """ # 轉換成陣列型別 X = np.asarray(X) # 儲存預測的結果值。 result = [] for x in X: # 計算距離。(計算與訓練集中每個X的距離) dis = np.sqrt(np.sum((x - self.X) ** 2, axis=1)) # 返回陣列排序後,每個元素在原陣列中(排序之前的陣列)的索引。 index = dis.argsort() # 取前k個距離最近的索引(在原陣列中的索引)。 index = index[:self.k] # 求所有鄰居節點距離的倒數之和。[注意,最後加上一個很小的值,就是為了避免除數(距離)為0的情況。] s = np.sum(1 / (dis[index] + 0.001)) # 使用每個節點距離的倒數,除以倒數之和,得到權重。 weight = (1 / (dis[index] + 0.001)) / s # 使用鄰居節點的標籤值,乘以對應的權重,然後想加,得到最終的預測結果。 result.append(np.sum(self.y[index] * weight)) return np.array(result)
④構建訓練集與測試集,用於對模型進行訓練與預測。並輸出預測結果。
t = data.sample(len(data), random_state=0) train_X = t.iloc[:120, :-1] train_y = t.iloc[:120, -1] test_X = t.iloc[120:, :-1] test_y = t.iloc[120:, -1] knn = KNN(k=3) knn.fit(train_X, train_y) result = knn.predict(test_X) display(result) display(np.mean((result - test_y) ** 2)) display(test_y.values)
程式執行結果如下:
array([1.33333333, 2. , 1.2 , 1.26666667, 1.93333333,
1.16666667, 2.16666667, 0.36666667, 1.9 , 1.4 ,
1.2 , 0.16666667, 1.93333333, 2.26666667, 1.73333333,
0.13333333, 1.03333333, 1.3 , 1.83333333, 1.23333333,
0.16666667, 0.23333333, 0.16666667, 2.03333333, 1.2 ,
1.8 , 0.2 ])
0.04185185185185184
array([1.5, 1.8, 1. , 1.3, 2.1, 1.2, 2.2, 0.2, 2.3, 1.3, 1. , 0.2, 1.6,
2.1, 2.3, 0.3, 1. , 1.2, 1.5, 1.3, 0.2, 0.4, 0.1, 2.1, 1.1, 1.5,
0.2])
⑤在考慮權重的情況下,進行預測。
result = knn.predict2(test_X)
display(np.mean((result - test_y) ** 2))
⑥匯入視覺化所需的庫,進行視覺化展示。
import matplotlib as mpl
import matplotlib.pyplot as plt
mpl.rcParams["font.family"] = "SimHei"
mpl.rcParams["axes.unicode_minus"] = False
⑦繪製預測值與真實值,並進行對比。
plt.figure(figsize=(10, 10))
# 繪製預測值
plt.plot(result, "ro-", label="預測值")
# 繪製真實值
plt.plot(test_y.values, "go--", label="真實值")
plt.title("KNN連續值預測展示")
plt.xlabel("節點序號")
plt.ylabel("花瓣寬度")
plt.legend()
plt.show()
程式執行結果如下: