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()
程序运行结果如下: