1. import numpy as np
    2. import pandas as pd
    1. data = pd.read_csv(r"dataset/iris.arff.csv", header=0)
    2. # data.head(10)
    3. # data.tail(10)
    4. print(data.sample(10))
    5. data["class"] = data["class"].map({"Iris-versicolor":0,"Iris-setosa":1,"Iris-virginica":2}) # 类别名称映射为数字
    6. # data = data.drop("Id",axis=1) # 删除列
    7. print(len(data))
    8. if data.duplicated().any(): # 重复值
    9. data.drop_duplicates(inplace=True) #删除重复值
    10. print(len(data))
    11. data["class"].value_counts() # 查看各个类别的鸢尾花记录
    1. sepallength sepalwidth petallength petalwidth class
    2. 82 5.8 2.7 3.9 1.2 Iris-versicolor
    3. 113 5.7 2.5 5.0 2.0 Iris-virginica
    4. 53 5.5 2.3 4.0 1.3 Iris-versicolor
    5. 62 6.0 2.2 4.0 1.0 Iris-versicolor
    6. 43 5.0 3.5 1.6 0.6 Iris-setosa
    7. 72 6.3 2.5 4.9 1.5 Iris-versicolor
    8. 2 4.7 3.2 1.3 0.2 Iris-setosa
    9. 99 5.7 2.8 4.1 1.3 Iris-versicolor
    10. 148 6.2 3.4 5.4 2.3 Iris-virginica
    11. 20 5.4 3.4 1.7 0.2 Iris-setosa
    12. 150
    13. 147

    0 50
    2 49
    1 48
    Name: class, dtype: int64

    1. class KNN:
    2. '''使用KNN实现K近邻算法实现分类'''
    3. def __init__(self, k):
    4. '''初始化
    5. Parameters
    6. -----
    7. k:int
    8. 邻居个位数
    9. '''
    10. self.k = k
    11. def fit(self, X, y):
    12. '''训练
    13. Parameeters
    14. -----
    15. X: 类数组类型,可以是List也可以是Ndarray,形状为: [样本数量,特征数量]
    16. y: 类数组类型,形状为:[样本数量]
    17. '''
    18. self.X = np.asarray(X) #转换为ndarray类型
    19. self.y = np.asarray(y)
    20. def predict(self, X):
    21. '''对样本进行预测
    22. Parameters:
    23. X: 类数组类型,可以是List也可以是Ndarray,形状为: [样本数量,特征数量]
    24. Returns:
    25. 数组类型,预测结果
    26. '''
    27. X = np.asarray(X)
    28. result = []
    29. for x in X:
    30. dis = np.sqrt(np.sum((x-self.X)**2, axis=1)) # 对于测试机的每隔一个样本,一次与训练集的所有数据求欧氏距离
    31. index = dis.argsort()# 返回排序结果的下标
    32. index = index[:self.k] # 截取前K个
    33. count = np.bincount(self.y[index]) # 返回数组中每个整数元素出现次数,元素必须是非负整数
    34. result.append(count.argmax()) # 返回ndarray中值最大的元素所对应的索引,就是出现次数最多的索引,也就是我们判定的类别
    35. return np.asarray(result)
    36. def predict2(self, X):
    37. '''对样本进行预测,加入权重计算
    38. Parameters:
    39. X: 类数组类型,可以是List也可以是Ndarray,形状为: [样本数量,特征数量]
    40. Returns:
    41. 数组类型,预测结果
    42. '''
    43. X = np.asarray(X)
    44. result = []
    45. for x in X:
    46. dis = np.sqrt(np.sum((x-self.X)**2, axis=1)) # 对于测试机的每隔一个样本,一次与训练集的所有数据求欧氏距离
    47. index = dis.argsort()# 返回排序结果的下标
    48. index = index[:self.k] # 截取前K个
    49. count = np.bincount(self.y[index], weights=1/dis[index]) # 返回数组中每个整数元素出现次数,元素必须是非负整数
    50. result.append(count.argmax()) # 返回ndarray中值最大的元素所对应的索引,就是出现次数最多的索引,也就是我们判定的类别
    1. # 提取每个类中鸢尾花数据
    2. t0 = data[data["class"]==0]
    3. t1 = data[data["class"]==1]
    4. t2 = data[data["class"]==2]
    5. # 打乱# 打乱每个类别数据
    6. t0 = t0.sample(len(t0), random_state=0)
    7. t1 = t1.sample(len(t1), random_state=0)
    8. t2 = t2.sample(len(t2), random_state=0)
    9. # 分配训练集和数据集,axis=0表示按纵向方式拼接
    10. train_X = pd.concat([t0.iloc[:40, :-1], t1.iloc[:40, :-1], t2.iloc[:40, :-1]], axis=0)
    11. train_y = pd.concat([t0.iloc[:40, -1], t1.iloc[:40, -1], t2.iloc[:40, -1]], axis=0)
    12. test_X = pd.concat([t0.iloc[40:, :-1], t1.iloc[40:, :-1], t2.iloc[40:, :-1]], axis=0)
    13. test_y = pd.concat([t0.iloc[40:, -1], t1.iloc[40:, -1], t2.iloc[40:, -1]], axis=0)
    1. knn = KNN(k=3)
    2. knn.fit(X=train_X, y=train_y)
    3. result = knn.predict(test_X)
    4. # display(result)
    5. # display(test_y)
    6. display(np.sum(result==test_y)/len(result))

    0.9629629629629629

    1. # "Iris-versicolor":0,"Iris-setosa":1,"Iris-virginica":2
    2. import matplotlib as mpl
    3. import matplotlib.pyplot as plt
    4. plt.figure(figsize=(20,10))
    5. mpl.rcParams["font.family"] = 'SimHei' # 默认mpl不支持中文,设置一下支持
    6. mpl.rcParams["axes.unicode_minus"] = False # 设置中文字体是可以正常显示负号
    7. plt.scatter(x=t0["sepallength"][:40], y=t0["petallength"][:40], color='r', label="Iris-versicolor")
    8. plt.scatter(x=t1["sepallength"][:40], y=t1["petallength"][:40], color='g', label="Iris-setosa")
    9. plt.scatter(x=t2["sepallength"][:40], y=t2["petallength"][:40], color='b', label="Iris-virginica")
    10. right = test_X[result == test_y]
    11. wrong = test_X[result != test_y]
    12. plt.scatter(x=right["sepallength"], y=right["petallength"], color='c', label="right", marker="x")
    13. plt.scatter(x=wrong["sepallength"], y=wrong["petallength"], color='m', label="wrong", marker=">")
    14. plt.xlabel('花萼长度')
    15. plt.ylabel('花瓣长度')
    16. plt.title('KNN分类结果')
    17. plt.legend(loc='best')
    18. plt.show()

    image.png