机器学习算法原理实现——k近邻算法 KNN
K近邻算法是一种基于距离度量的数据分类模型,其基本做法是首先确定输入实例的[插图]个最近邻实例,然后利用这[插图]个训练实例的多数所属的类别来预测新的输入实例所属类别。
k最近邻(k-nearest neighbors,KNN)算法是一种基本的分类和回归算法。其基本原理如下:
1. 训练阶段:将训练样本集中的数据和对应的标签存储起来,构建一个训练模型。
2. 预测阶段:对于一个新的测试样本,计算它与训练样本集中所有样本的距离(通常使用欧氏距离或其他距离度量方法)。
3. 选择k个最近邻:根据距离计算结果,选择与测试样本距离最近的k个训练样本。
4. 进行投票或计算平均值:对于分类任务,根据k个最近邻的标签进行投票,将得票最多的标签作为测试样本的预测标签。对于回归任务,根据k个最近邻的标签或值进行平均计算,将计算结果作为测试样本的预测值。
KNN算法的关键是选择合适的k值和距离度量方法。k值的选择会影响算法的性能,较小的k值可能会导致过拟合,较大的k值可能会导致欠拟合。距离度量方法的选择应根据具体问题和数据特点进行合理选择。
KNN算法的优点包括简单易懂、易于实现、适用于多分类和回归问题。然而,KNN算法的缺点是计算复杂度高,对于大规模数据集的预测速度较慢。此外,KNN算法对于特征空间的维度敏感,需要进行特征选择或降维等预处理操作。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 | # 导入相关模块 import numpy as np from collections import Counter import matplotlib.pyplot as plt from sklearn import datasets from sklearn.utils import shuffle ### 定义欧氏距离 def compute_distances(X, X_train): ''' 输入: X:测试样本实例矩阵 X_train:训练样本实例矩阵 输出: dists:欧式距离 ''' # 测试实例样本量 num_test = X.shape[ 0 ] # 训练实例样本量 num_train = X_train.shape[ 0 ] # 基于训练和测试维度的欧氏距离初始化 dists = np.zeros((num_test, num_train)) # 测试样本与训练样本的矩阵点乘 M = np.dot(X, X_train.T) # 测试样本矩阵平方 te = np.square(X). sum (axis = 1 ) """ >>> import numpy as np >>> a = np.array([[1,2,3],[4,5,6]]) >>> np.sum(a) 21 >>> np.sum(a, axis=0) array([5, 7, 9]) >>> np.sum(a, axis=1) array([ 6, 15]) X = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) ==>np.square(X).sum(axis=1) 结果为 [14 77 194] """ # 训练样本矩阵平方 tr = np.square(X_train). sum (axis = 1 ) # 计算欧式距离 dists = np.sqrt( - 2 * M + tr + np.matrix(te).T) # 自己可以简单推导下 的确如此 return dists ### 定义预测函数 def predict_labels(y_train, dists, k = 1 ): ''' 输入: y_train:训练集标签 dists:测试集与训练集之间的欧氏距离矩阵 k:k值 输出: y_pred:测试集预测结果 ''' # 测试样本量 num_test = dists.shape[ 0 ] # 初始化测试集预测结果 y_pred = np.zeros(num_test) # 遍历 for i in range (num_test): # 初始化最近邻列表 closest_y = [] # 按欧氏距离矩阵排序后取索引,并用训练集标签按排序后的索引取值 # 最后展平列表 # 注意np.argsort函数的用法 labels = y_train[np.argsort(dists[i, :])].flatten() # 取最近的k个值 closest_y = labels[ 0 :k] # 对最近的k个值进行计数统计 # 这里注意collections模块中的计数器Counter的用法 c = Counter(closest_y) # 取计数最多的那个类别 y_pred[i] = c.most_common( 1 )[ 0 ][ 0 ] return y_pred """ >>> x = np.array([3, 1, 2]) >>> np.argsort(x) array([1, 2, 0]) # 创建计数对象 >>> c = Counter('abcdeabcdabcaba') # 取计数前三的元素 >>> c.most_common(3) [('a', 5), ('b', 4), ('c', 3)] """ # 导入sklearn iris数据集 iris = datasets.load_iris() # 打乱数据后的数据与标签 X, y = shuffle(iris.data, iris.target, random_state = 13 ) # 数据转换为float32格式 X = X.astype(np.float32) # 简单划分训练集与测试集,训练样本-测试样本比例为7:3 offset = int (X.shape[ 0 ] * 0.7 ) X_train, y_train = X[:offset], y[:offset] X_test, y_test = X[offset:], y[offset:] # 将标签转换为竖向量 y_train = y_train.reshape(( - 1 , 1 )) y_test = y_test.reshape(( - 1 , 1 )) # 打印训练集和测试集大小 print ( 'X_train=' , X_train.shape) print ( 'X_test=' , X_test.shape) print ( 'y_train=' , y_train.shape) print ( 'y_test=' , y_test.shape) dists = compute_distances(X_test, X_train) # 测试集预测结果 y_test_pred = predict_labels(y_train, dists, k = 10 ) y_test_pred = y_test_pred.reshape(( - 1 , 1 )) # 找出预测正确的实例 num_correct = np. sum (y_test_pred = = y_test) # 计算分类准确率 accuracy = float (num_correct) / X_test.shape[ 0 ] print ( 'KNN Accuracy based on NumPy: ' , accuracy) # 导入KNeighborsClassifier模块 from sklearn.neighbors import KNeighborsClassifier # 创建k近邻实例 neigh = KNeighborsClassifier(n_neighbors = 10 ) # k近邻模型拟合 neigh.fit(X_train, y_train) # k近邻模型预测 y_pred = neigh.predict(X_test) # 预测结果数组重塑 y_pred = y_pred.reshape(( - 1 , 1 )) # 统计预测正确的个数 num_correct = np. sum (y_pred = = y_test) # 计算分类准确率 accuracy = float (num_correct) / X_test.shape[ 0 ] print ( 'KNN Accuracy based on sklearn: ' , accuracy) |
运行结果:
X_train= (105, 4)
X_test= (45, 4)
y_train= (105, 1)
y_test= (45, 1)
KNN Accuracy based on NumPy: 0.9777777777777777
KNN Accuracy based on sklearn: 0.9777777777777777
其中,计算举例的可以使用下面更加简洁的函数:
1 2 3 4 5 6 7 8 | def compute_distances(X, X_train): num_test = X.shape[ 0 ] num_train = X_train.shape[ 0 ] dists = np.zeros((num_test, num_train)) for i in range (num_test): for j in range (num_train): dists[i, j] = np.sqrt(np. sum (np.square(X[i] - X_train[j]))) return dists |
predict我自己写的话,是下面这样:
1 2 3 4 5 6 7 8 | def predict_labels(y_train, dists, k = 1 ): num_test = dists.shape[ 0 ] y_pred = np.zeros(num_test) for i in range (num_test): sorted_indices = np.argsort(dists[i]) closest_y = y_train[sorted_indices[:k]].flatten() y_pred[i] = Counter(closest_y).most_common()[ 0 ][ 0 ] return y_pred |
标签:
机器学习
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」
2022-09-10 metersploit msf 常用命令
2022-09-10 windows 7 iso下载地址
2020-09-10 小样本学习文献
2019-09-10 联邦学习
2019-09-10 数据库索引数据结构总结——ART树就是前缀树