一、算法思想和原理

基本思想可以参考这篇文章https://blog.csdn.net/hajk2017/article/details/82862788,来自博主hajk2017
https://blog.csdn.net/qq_41709378/article/details/105386111,来自博主三个半_Z,这篇文章能够迅速理解算法的原理和代码实例计算,里面也牵扯到如何采用交叉验证选择k值
有关KD树的构造可以参考知乎专栏https://zhuanlan.zhihu.com/p/23966698,出处为JoinQuant量化课堂。

二、KNN算法的实现

1.简单实例

  1. import matplotlib.pyplot as plt
  2. import numpy as np
  3. import operator #注意这个库
  4. # 已知分类的数据
  5. x1 = np.array([3,2,1])
  6. y1 = np.array([104,100,81])
  7. x2 = np.array([101,99,98])
  8. y2 = np.array([10,5,2])
  9. scatter1 = plt.scatter(x1,y1,c='r') #(x1,y1)是一类
  10. scatter2 = plt.scatter(x2,y2,c='b') #(x2,y2)是一类
  11. # 未知数据
  12. x = np.array([18])
  13. y = np.array([90])
  14. scatter3 = plt.scatter(x,y,c='k')
  15. #画图例
  16. plt.legend(handles=[scatter1,scatter2,scatter3],labels=['labelA','labelB','X'],loc='best')
  17. plt.show()
  18. # 已知分类的数据
  19. x_data = np.array([[3,104],
  20. [2,100],
  21. [1,81],
  22. [101,10],
  23. [99,5],
  24. [81,2]]) #红色和蓝色的点一起归于x_data
  25. y_data = np.array(['A','A','A','B','B','B']) #定义标签
  26. x_test = np.array([18,90]) #测试实例
  27. # 计算样本数量
  28. x_data_size = x_data.shape[0] #计算行数
  29. x_data_size
  30. #复制x_test
  31. np.tile(x_test, (x_data_size,1))#后面的参数是复制行和列的次数,第一个是行的次数,第二个是列的次数,这个相当于在行的方向复制6次,目的是要计算这个点和所有点的距离
  32. # 计算x_test与每一个样本的差值
  33. diffMat = np.tile(x_test, (x_data_size,1)) - x_data
  34. diffMat
  35. # 计算差值的平方
  36. sqDiffMat = diffMat**2
  37. sqDiffMat
  38. # 求和
  39. sqDistances = sqDiffMat.sum(axis=1)
  40. sqDistances
  41. # 开方
  42. distances = sqDistances**0.5
  43. distances #得到欧式距离
  44. # 从小到大排序
  45. sortedDistances = distances.argsort() #对索引进行排序
  46. sortedDistances
  47. classCount = {} #建立一个字典
  48. # 设置k
  49. k = 5
  50. for i in range(k): #这里要统计最近k个点的标签多少,便于依照少数服从多数原则进行分类
  51. # 获取标签
  52. votelabel = y_data[sortedDistances[i]]
  53. # 统计标签数量
  54. classCount[votelabel] = classCount.get(votelabel,0) + 1 #get函数获取键值,如果获取不到键值,就返回0 [key!这里有点难以理解]
  55. classCount
  56. # 根据operator.itemgetter(1)-第1个值对classCount排序,然后再取倒序
  57. sortedClassCount = sorted(classCount.items(),key=operator.itemgetter(1), reverse=True) #数量最多的在最前面
  58. sortedClassCount #得到一个list
  59. # 获取数量最多的标签
  60. knnclass = sortedClassCount[0][0]
  61. knnclass #得到分类类别

2.鸢尾花的应用

  1. # 导入算法包以及数据集
  2. import numpy as np
  3. from sklearn import datasets
  4. from sklearn.model_selection import train_test_split
  5. from sklearn.metrics import classification_report,confusion_matrix
  6. import operator
  7. import random
  8. def knn(x_test, x_data, y_data, k):
  9. # 计算样本数量
  10. x_data_size = x_data.shape[0]
  11. # 复制x_test
  12. np.tile(x_test, (x_data_size,1))
  13. # 计算x_test与每一个样本的差值
  14. diffMat = np.tile(x_test, (x_data_size,1)) - x_data
  15. # 计算差值的平方
  16. sqDiffMat = diffMat**2
  17. # 求和
  18. sqDistances = sqDiffMat.sum(axis=1)
  19. # 开方
  20. distances = sqDistances**0.5 #求解欧氏距离
  21. # 从小到大排序
  22. sortedDistances = distances.argsort()
  23. classCount = {}
  24. for i in range(k):
  25. # 获取标签
  26. votelabel = y_data[sortedDistances[i]]
  27. # 统计标签数量
  28. classCount[votelabel] = classCount.get(votelabel,0) + 1
  29. # 根据operator.itemgetter(1)-第1个值对classCount排序,然后再取倒序
  30. sortedClassCount = sorted(classCount.items(),key=operator.itemgetter(1), reverse=True)
  31. # 获取数量最多的标签
  32. return sortedClassCount[0][0]
  33. data_size = iris.data.shape[0] #计算多少个数据(行数)
  34. index = [i for i in range(data_size)]
  35. random.shuffle(index) #打乱上面的list
  36. # 载入数据
  37. iris = datasets.load_iris() #sklearn库自带的数据集
  38. # x_train,x_test,y_train,y_test = train_test_split(iris.data, iris.target, test_size=0.2) #分割数据0.2为测试数据,0.8为训练数据,系统自带的切分数据集代码形式
  39. #打乱数据
  40. data_size = iris.data.shape[0] #计算多少个数据(行数)
  41. index = [i for i in range(data_size)]
  42. random.shuffle(index) #打乱上面的list
  43. iris.data = iris.data[index]
  44. iris.target = iris.target[index]
  45. #切分数据集(自己实操的方式)
  46. test_size = 40
  47. x_train = iris.data[test_size:] #取剩余部分
  48. x_test = iris.data[:test_size] #取前40个
  49. y_train = iris.target[test_size:]
  50. y_test = iris.target[:test_size]
  51. predictions = []
  52. for i in range(x_test.shape[0]):
  53. predictions.append(knn(x_test[i], x_train, y_train, 5))
  54. print(classification_report(y_test, predictions))
  55. print(confusion_matrix(y_test,predictions))

3.sklearn库的使用

  1. # 导入算法包以及数据集
  2. from sklearn import neighbors
  3. from sklearn import datasets
  4. from sklearn.model_selection import train_test_split
  5. from sklearn.metrics import classification_report
  6. import random
  7. # 载入数据
  8. iris = datasets.load_iris()
  9. print(iris)
  10. # 打乱数据切分数据集
  11. # x_train,x_test,y_train,y_test = train_test_split(iris.data, iris.target, test_size=0.2) #分割数据0.2为测试数据,0.8为训练数据
  12. #打乱数据
  13. data_size = iris.data.shape[0]
  14. index = [i for i in range(data_size)]
  15. random.shuffle(index)
  16. iris.data = iris.data[index]
  17. iris.target = iris.target[index]
  18. #切分数据集
  19. test_size = 40
  20. x_train = iris.data[test_size:]
  21. x_test = iris.data[:test_size]
  22. y_train = iris.target[test_size:]
  23. y_test = iris.target[:test_size]
  24. # 构建模型
  25. model = neighbors.KNeighborsClassifier(n_neighbors=3) #直接利用sklearn库进行分类
  26. model.fit(x_train, y_train)
  27. prediction = model.predict(x_test)
  28. print(classification_report(y_test, prediction))