1. 程式人生 > >AI工程師成長之路-KNN迴歸演算法實現

AI工程師成長之路-KNN迴歸演算法實現

本博文是博主在阿里雲大學學習記錄的筆記,未經博主允許禁止隨意轉載

需要資料集的可以聯絡博主獲取

本實驗將學習如何使用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()

程式執行結果如下:

KNN迴歸執行結果