1. import numpy as np
    2. import pandas as pd
    1. data = pd.read_csv(r"dataset/iris.arff.csv", header=0)
    2. data.drop(["class"], axis=1, inplace=True)
    3. print(data)
    1. sepallength sepalwidth petallength petalwidth
    2. 0 5.1 3.5 1.4 0.2
    3. 1 4.9 3.0 1.4 0.2
    4. 2 4.7 3.2 1.3 0.2
    5. 3 4.6 3.1 1.5 0.2
    6. 4 5.0 3.6 1.4 0.2
    7. .. ... ... ... ...
    8. 145 6.7 3.0 5.2 2.3
    9. 146 6.3 2.5 5.0 1.9
    10. 147 6.5 3.0 5.2 2.0
    11. 148 6.2 3.4 5.4 2.3
    12. 149 5.9 3.0 5.1 1.8

    [150 rows x 4 columns]

    1. class KNN:
    2. def __init__(self, k):
    3. self.k = k
    4. def fit(self, X, y):
    5. '''训练
    6. Parameeters
    7. -----
    8. X: 类数组类型,可以是List也可以是Ndarray,形状为: [样本数量,特征数量]
    9. y: 类数组类型,形状为:[样本数量]
    10. '''
    11. self.X = np.asarray(X)
    12. self.y = np.asarray(y)
    13. def predict(self, X):
    14. '''对样本进行预测
    15. Parameters:
    16. X: 类数组类型,可以是List也可以是Ndarray,形状为: [样本数量,特征数量]
    17. Returns:
    18. 数组类型,预测结果
    19. '''
    20. X = np.asarray(X)
    21. result = []
    22. for x in X:
    23. dis = np.sqrt(np.sum((x - self.X)**2, axis=1))
    24. index = dis.argsort()
    25. index = index[:self.k]
    26. result.append(np.mean(self.y[index])) # 计算均值
    27. return np.asarray(result)
    28. def predict2(self, X):
    29. '''对样本进行预测,考虑权重
    30. 权重计算方式:使用每个节点(邻居)距离的倒数/所有节点距离倒数只和
    31. Parameters:
    32. X: 类数组类型,可以是List也可以是Ndarray,形状为: [样本数量,特征数量]
    33. Returns:
    34. 数组类型,预测结果
    35. '''
    36. X = np.asarray(X)
    37. result = []
    38. for x in X:
    39. # 计算与训练集的距离,取平方后开方
    40. dis = np.sqrt(np.sum((x - self.X)**2, axis=1))
    41. index = dis.argsort()
    42. index = index[:self.k]
    43. s = np.sum(1/(dis[index]+0.001)) # 最后加一个一很小的数就是为了避免距离为0的情况
    44. weight = (1/(dis[index]+0.001))/s # 距离倒数/倒数之和
    45. result.append(np.sum(self.y[index]*weight)) # 邻居节点标签纸*对应权重相加求和
    46. return np.asarray(result)
    1. t = data.sample(len(data), random_state=0)
    2. train_X = t.iloc[:120, :-1]
    3. train_y = t.iloc[:120, -1]
    4. test_X = t.iloc[120:, :-1]
    5. test_y = t.iloc[120:, -1]
    6. knn = KNN(k=3)
    7. knn.fit(train_X, train_y)
    8. result = knn.predict(test_X)
    9. result2 = knn.predict2(test_X)
    10. display(result)
    11. display(test_y.values)
    1. array([0.33333333, 2.06666667, 0.2 , 0.2 , 1.9 ,
    2. 0.23333333, 2.2 , 1.26666667, 1.2 , 1.16666667,
    3. 1.93333333, 2.13333333, 1.83333333, 1.93333333, 0.13333333,
    4. 1.16666667, 2.23333333, 1.96666667, 0.3 , 1.46666667,
    5. 1.26666667, 1.66666667, 1.33333333, 0.26666667, 0.2 ,
    6. 0.13333333, 2.03333333, 1.26666667, 2.2 , 0.23333333])
    7. array([0.2, 2. , 0.3, 0.2, 1.9, 0.2, 2.4, 1.3, 1.2, 1. , 2.3, 2.3, 1.5,
    8. 1.7, 0.2, 1. , 2.4, 1.9, 0.2, 1.3, 1.3, 1.8, 1.3, 0.2, 0.4, 0.1,
    9. 1.8, 1. , 2.2, 0.2])
    1. display(np.mean(np.sum((result - test_y)**2)))
    2. display(np.mean(np.sum((result2 - test_y)**2)))

    0.7244444444444444

    0.7650802020943153

    1. import matplotlib as mpl
    2. import matplotlib.pyplot as plt
    3. mpl.rcParams["font.family"] = "SimHei"
    4. mpl.rcParams["axes.unicode_minus"] = False # 显示负号
    1. plt.figure(figsize=(10,5))
    2. plt.plot(result, 'ro-') # 红色圆圈表示"不带"权重鱼的预测值
    3. plt.plot(result2, 'bo-') # 蓝色圆圈表示"带"权重鱼的预测值
    4. plt.plot(test_y.values, 'go-') # 绿色圆圈表示测试集真实值
    5. plt.title('KNN连续预测展示')
    6. plt.xlabel('节点序号')
    7. plt.ylabel('花瓣长度')
    8. plt.legend()
    9. plt.show()

    image.png