机器学习 02- KNN算法

发布时间:2026/7/9 17:28:05
机器学习 02- KNN算法 算法简介KNN算法思想K-近邻算法K Nearest Neighbor简称KNN。比如根据你的“邻居”来推断出你的类别简单来说预测当前数据时在已知数据中寻找出k个与其最相似的样本这k个样本大多数属于某个类别的话那么该样本也属于某个类别所以k的取值就很有考究这里暂时提及到后面会详细讲解。样本相似性样本都是属于一个任务数据集的。样本距离越近则越相似。利用K近邻算法预测电影类型例如 使用KNN预测电影类别在这里我们可以使用欧氏距离来计算预测数据的“邻居”K值的选择前面我们提到过我们需要找到k个与其最相似的样本那么这个k值的选择就十分重要。k值过小这种情况就是用较小的邻域去进行预测那么该种方法就可能使得预测值易受异常点的影响极端思维理解若k取1的话如果你的参考值是一个异常值那么你预测的值就受到了该异常值的影响。k值的减小也意味着整体模型会变得复杂进而导致过拟合现象的产生k值过大这种情况就是用较大的邻域去进行预测那么该种方法可能会产生样本均衡的问题极端思维理解如果k取n那么无论你输入什么值那么它只会按训练集中最多的类别去进行预测。k值的增大也意味着其整体的模型会变得简单容易发生欠拟合的现象。KNN算法的应用KNN算法解决问题分类问题、回归问题回归问题的处理流程1.计算未知样本到每一个训练样本的距离2.将训练样本根据距离大小升序排列3.取出距离最近的 K 个训练样本4.进行多数表决统计 K 个样本中哪个类别的样本个数最多5.将未知的样本归属到出现次数最多的类别回归问题的处理流程1.计算未知样本到每一个训练样本的距离2.将训练样本根据距离大小升序排列3.取出距离最近的 K 个训练样本4.把这个 K 个样本的目标值计算其平均值5.作为将未知的样本预测的值注不论是分类问题还是回归问题其前期的处理策略都是相同的。KNN算法API介绍分类算法APIKNN分类APIsklearn.neighbors.KNeighborsClassifier(n_neighbors5)n_neighborsint,可选默认 5k_neighbors查询默认使用的邻居数也就是我们所谓的 k的大小。回归算法APIKNN分类APIsklearn.neighbors.KNeighborsRegressor(n_neighbors5)n_neighborsint,可选默认 5k_neighbors查询默认使用的邻居数也就是我们所谓的 k的大小。相关代码#导包importsklearn.neighborsdefdemo01_class():#实例化c_estimatorsklearn.neighbors.KNeighborsClassifier(n_neighbors1)#设置数据x[[0],[1],[2],[3]]y[0,0,1,1]#训练c_estimator.fit(x,y)print(c_estimator.predict([[5]]))defdemo02_regressor():#实例化r_estimatorsklearn.neighbors.KNeighborsRegressor(n_neighbors2)#设置数据x[[0,1,2],[1,2,3],[2,3,4],[3,4,5]]y[0.1,0.2,0.3,0.4]#训练r_estimator.fit(x,y) 计算过程就是找到离预测值最近的两个邻居输出其平均值 print(r_estimator.predict([[5,6,7]]))if__name____main__:demo01_class()demo02_regressor()运行结果距离计算方法在前面我们仅提及了欧式距离的计算方法但计算距离的公式有很多在不同的情况下则使用不同的公式所以我们需要了解下相关的距离计算公式。欧式距离欧氏距离就是我们常说的空间中两点之间的距离。曼哈顿距离曼哈顿距离也可以称之为城市街区距离可以理解为网格中两点之间的距离其结果就是两个点构成的长方形的边长和。切比雪夫距离棋子从a点到b点最少需要多少步旗子可以朝向相邻的八个方向任意移动。闵氏距离闵可夫斯基距离 Minkowski Distance 闵氏距离不是一种新的距离的度量方式。而是距离的组合 是对多个距离度量公式的概括性的表述特征预处理对特征值进行预处理也就是对其进行归一化和标准化原因特征的单位或者大小相差较大或者某特征的方差相比其他的特征要大出几个数量级容易影响支配目标结果使得一些模型算法无法学习到其它的特征。归一化通过对原始数据进行变换把数据映射到【mi,mx】(默认为[0,1])之间注mx-mi是进行值大小的缩放mi是进行值左右的位移数据归一化的API实现sklearn.preprocessing.MinMaxScaler(feature_range(0,1)…)#feature_range 缩放区间注fit()只做一件事 ——计算传入数据的均值、标准差并把这两个统计值保存到标准化器对象里。它不修改数据只 “学习” 数据的分布参数。transform()用对象里已经保存好的均值、标准差按照公式 (x - 均值) / 标准差 对数据做标准化计算。它不重新计算统计量只做变换。fit_transform()等价于先执行 fit() 再执行 transform()是一步到位的简写只应该用在训练集上。归一化受到最大值与最小值的影响这种方法容易受到异常数据的影响,鲁棒性较差适合传统精确小数据场景如果出现异常点 影响了最大值和最小值那么结果会明显的发生改变。标准化通过对原始数据进行标准化转换为均值为0标准差为1的标准正态分布的数据数据标准化的API实现sklearn.preprocessing.StandardScaler()调用 fit_transform(X) 将特征进行归一化缩放适用于现代嘈杂大数据场景。如果出现了异常点 由于数据量较大少量的异常点对于平均值的影响并不大。代码#导包importsklearn.preprocessingdefdemo01_minmax():# 数据x[[90,2,10,40],[60,4,15,45],[75,3,13,46]]#实例化tfsklearn.preprocessing.MinMaxScaler()datatf.fit_transform(x)print(data)defdemo02_ss():# 数据x[[90,2,10,40],[60,4,15,45],[75,3,13,46]]# 实例化tfsklearn.preprocessing.StandardScaler()datatf.fit_transform(x)print(data)if__name____main__:demo01_minmax()demo02_ss()执行结果扩展正态分布案例 - 鸢尾花分类鸢尾花Iris Dataset数据集是机器学习领域经典数据集鸢尾花数据集包含了150条鸢尾花信息每50条取自三个鸢尾花中之一Versicolour、Setosa和Virginica处理流程获取数据集 - 数据基本处理 - 特征值处理 - 模型训练 - 模型评估代码实现## KNN_鸢尾花# 1.导入工具包importnumpyasnpimportpandasaspdimportseabornassnsimportmatplotlib.pyplotaspltimportsklearn.model_selectionimportsklearn.metricsimportsklearn.preprocessingimportsklearn.neighbors# 2.加载数据集# 2.1 加载数据集iris_datasklearn.datasets.load_iris()#这里的数据 是 sklearn 封装的 Bunch 对象# print(iris_data)# print(iris_data.target)# print(iris_data.feature_names) # [sepal length (cm), sepal width (cm), petal length (cm), petal width (cm)]# print(iris_data.target_names) # [setosa versicolor virginica] 三种花的类别# 2.2 展示数据集iris_dfpd.DataFrame(datairis_data.data,columnsiris_data.feature_names)iris_df[label]iris_data.target#花的类别# print(iris_df)# print(iris_data.feature_names)# sns.lmplot(xsepal length (cm),ysepal width (cm),data iris_df,huelabel, fit_regFalse ) #hue 按类别进行分类, fit_reg 关闭回归线拟合# plt.show()# 3.特征工程(预处理-标准化)# 3.1 数据集划分x_train,x_test,y_train,y_testsklearn.model_selection.train_test_split(iris_data.data,iris_data.target,test_size0.3,random_state42)#test_size 0.3 训练集和测试集比为73# print(len(iris_data.data))# print(len(x_train))# 3.2 标准化processsklearn.preprocessing.StandardScaler()x_trainprocess.fit_transform(x_train)#训练集需要计算x_testprocess.transform(x_test)#测试集无需计算# 4.模型训练# 4.1 实例化modelsklearn.neighbors.KNeighborsClassifier()#分类# 4.2 调用fit法model.fit(x_train,y_train)# 5.模型预测x[[5.1,3.5,1.4,0.2]]xprocess.transform(x)print(model.predict_proba(x))# _proba 是每个分类的概率# 6.模型评估(准确率)# 6.1 直接计算准确率accmodel.score(x_test,y_test)#用测试集计算模型的分类准确率print(acc)# 6.2 使用预测结果y_predictmodel.predict(x_test)accsklearn.metrics.accuracy_score(y_test,y_predict)print(acc)运行结果超参数的选择交叉验证交叉验证是一种数据集的分割方法将训练集划分为 n 份其中一份做验证集、其他n-1份做训练集其目的是为了得到更加准确可信的模型评分。交叉验证法原理将数据集划分为 cv10 份1.第一次把第一份数据做验证集其他数据做训练2.第二次把第二份数据做验证集其他数据做训练3… 以此类推总共训练10次评估10次。4.使用训练集验证集多次评估模型取平均值做交叉验证为模型得分5.若k5模型得分最好再使用全部训练集(训练集验证集) 对k5模型再训练一边再使用测试集对k5模型做评估网格搜索模型有很多超参数其能力存在很大的差别所以需要手动产生很多超参数组合来训练模型每组超参数都采用交叉验证评估最后选出最优参数组合建立模型。网格搜做是模型调参的工具我们只需要将若干参数传给网格搜索工具它可以自动帮助我们完成不同超参数的组合、模型训练、模型评估最终返回一组最优参数。注超参数Hyperparameter是模型开始训练之前由人工预先设定、用来控制模型结构 / 训练规则的参数。它最关键的特点不是模型通过 fit() 从数据里自动学习出来的而是你提前定好的 “运行规则”。目前我们正在学的 KNN 算法里KNeighborsClassifier(n_neighbors5) 中的 n_neighbors5就是最典型的超参数。使用网格搜索交叉验证的方法可以形成一个模型参数调优的解决方案。代码 鸢尾花分类包含交叉验证流程## 交叉验证网格搜索# 1.导入工具包importpandasaspdimportnumpyasnpimportmatplotlib.pyplotaspltimportsklearn.metricsimportsklearn.preprocessingimportsklearn.neighborsimportsklearn.model_selectionfromsklearn.metricsimportaccuracy_score# 2.加载数据datasklearn.datasets.load_iris()# 3.数据集划分x_train,x_test,y_train,y_testsklearn.model_selection.train_test_split(data.data,data.target,test_size0.2,random_state1)# 4.特征预处理demosklearn.preprocessing.StandardScaler()#标准化x_traindemo.fit_transform(x_train)x_testdemo.transform(x_test)# 5.模型实例化交叉验证网格搜索modelsklearn.neighbors.KNeighborsClassifier(n_neighbors1)para{n_neighbors:[1,3,5,7,9]}# estimator sklearn.model_selection.GridSearchCV(# estimatormodel, # 要调参的基础模型# param_gridpara, # 超参数候选网格# cv4 # 4折交叉验证 把训练集 x_train 平均分成 4 份每次用 3 份做训练、1 份做验证循环 4 次取 4 次的平均得分作为这组参数的最终成绩。# )# estimator.fit(x_train,y_train)## # 这一行执行后程序会自动完成一整套流程# 遍历每一组超参数共 5 组 K 值# 对每组参数都执行 4 折交叉验证记录每一轮的验证集得分# 计算每组参数的平均验证得分选出平均分最高的那一组作为最优超参数# 用最优超参数在整个训练集上重新训练一个最终模型保存在对象里。# ## print(estimator.best_score_)# print(estimator.best_estimator_)# print(estimator.cv_results_)#结果modelsklearn.neighbors.KNeighborsClassifier(n_neighbors7)# 6.模型训练model.fit(x_train,y_train)# x [[5.1, 3.5, 1.4, 0.2]]# x demo.transform(x)# 7.模型预测y_predictmodel.predict(x_test)# 8.模型评估print(sklearn.metrics.accuracy_score(y_test,y_predict))