AI工程师成长之路-KNN回归算法实现

本博文是博主在阿里云大学学习记录的笔记,未经博主允许禁止随意转载

数据集获取方法:

链接:https://pan.baidu.com/s/1b6Nc3-QmHhQjH_uxZg3WCQ 
提取码:ndv9

本实验将学习如何使用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()

程序运行结果如下:

AI工程师成长之路-KNN回归算法实现