机器学习——02 KNN算法
1 KNN算法
1.1 算法思想
- K-近邻算法是一种基本的分类与回归方法;
- 算法思想:如果一个样本在特征空间中的k个最相似(即特征空间中最邻近)的样本中的大多数属于某一个类别,则该样本也属于这个类别。
1.2 样本相似性&欧式距离
-
样本相似性是指样本都属于一个任务数据集,样本距离越近则越相似。通常使用欧氏距离来衡量样本之间的相似性;
-
欧氏距离的计算
-
二维平面上点
a(x₁,y₁)与b(x₂,y₂)间的欧氏距离:
d12=(x1−x2)2+(y1−y2)2 d_{12} = \sqrt{(x_1 - x_2)^2 + (y_1 - y_2)^2} d12=(x1−x2)2+(y1−y2)2
-
三维空间点
a(x₁,y₁,z₁)与b(x₂,y₂,z₂)间的欧氏距离
d12=(x1−x2)2+(y1−y2)2+(z1−z2)2 d_{12} = \sqrt{(x_1 - x_2)^2 + (y_1 - y_2)^2 + (z_1 - z_2)^2} d12=(x1−x2)2+(y1−y2)2+(z1−z2)2 -
n维空间点
a(x₁₁,x₁₂,…,x₁ₙ)与b(x₂₁,x₂₂,…,x₂ₙ)间的欧氏距离:
d12=∑k=1n(x1k−x2k)2 d_{12} = \sqrt{\sum_{k=1}^{n} (x_{1k} - x_{2k})^2} d12=k=1∑n(x1k−x2k)2
-
-
例:利用K近邻算法预测电影类型
序号 电影名称 搞笑镜头 拥抱镜头 打斗镜头 电影类型 距离 K=5时 1 功夫熊猫 39 0 31 喜剧片 21.47 √ 2 叶问3 3 2 65 动作片 52.01 3 伦敦陷落 2 3 55 动作片 43.42 4 代理情人 9 38 2 爱情片 40.57 5 新步步惊心 8 34 17 爱情片 34.44 √ 6 谍影重重 5 2 57 动作片 43.87 7 功夫熊猫 39 0 31 喜剧片 21.47 √ 8 美人鱼 21 17 5 喜剧片 18.55 √ 9 宝贝当家 45 2 9 喜剧片 23.43 √ 10 唐人街探案 23 3 17 ? —— ? -
“搞笑镜头”、“拥抱镜头”、“打斗镜头”就是三个特征,那么《唐人街探案》与《伦敦陷落》的欧式距离计算如下:
d=(23−2)2+(3−3)2+(17−55)2=43.42 d = \sqrt{(23 - 2)^2 + (3 - 3)^2 + (17 - 55)^2}=43.42 d=(23−2)2+(3−3)2+(17−55)2=43.42 -
依次就可以得出《唐人街探案》与其它影片的欧式距离;
-
将这些欧式距离从小到大排序,K=5,即取出前5个与《唐人街探案》的欧式距离最小的影片(上表中最后打钩的那一列),可以发现这些影片中有4个是喜剧片,所以可以预测《唐人街探案》也是喜剧片(对应算法思想中的“大多数”);
-
1.3 K值选择
- K值过小:用较小邻域中的训练实例进行预测,容易受到异常点的影响。K值的减小就意味着整体模型变得复杂,容易发生过拟合。例如,当K=N(N为训练样本个数)时,无论输入实例是什么,只会按训练集中最多的类别进行预测,受到样本均衡的影响;
- K值过大:用较大邻域中的训练实例进行预测,受到样本均衡的问题。且K值的增大就意味着整体的模型变得简单,欠拟合;
- K值的调优方法:需要一些方法来寻找这个最合适的K值,常用的方法包括交叉验证和网格搜索。
1.4 应用
-
KNN算法可以解决分类问题和回归问题;
-
分类流程:
- 计算未知样本到每一个训练样本的距离
- 将训练样本根据距离大小升序排列
- 取出距离最近的K个训练样本
- 进行多数表决,统计K个样本中哪个类别的样本个数最多
- 将未知的样本归属到出现次数最多的类别
-
回归流程:
- 计算未知样本到每一个训练样本的距离
- 将训练样本根据距离大小升序排列
- 取出距离最近的K个训练样本
- 把这个K个样本的目标值计算其平均值
- 作为将未知的样本预测的值
-
总结来说,KNN算法是一种简单有效的分类和回归方法,但K值的选择对算法的性能有很大影响,需要根据具体情况进行调优。
2 KNN算法API
-
分类代码:
# 导入sklearn库中的KNeighborsClassifier类,用于实现K近邻分类算法 from sklearn.neighbors import KNeighborsClassifier def knnapi_classifier(): # 创建K近邻分类器实例,设置n_neighbors=1表示只考虑最近的1个邻居 estimator = KNeighborsClassifier(n_neighbors=1) # 准备训练数据特征X,这里是一个二维列表,每个子列表代表一个样本的特征 # 这里每个样本只有1个特征,分别是0、1、2、3 X = [[0], [1], [2], [3]] # 准备训练数据的标签y,与X中的样本一一对应 # 前两个样本标签为0,后两个样本标签为1 y = [0, 0, 1, 1] # 使用训练数据拟合模型,即让模型学习特征与标签之间的关系 estimator.fit(X, y) # 使用训练好的模型预测新样本[4]的标签 myret = estimator.predict([[4]]) # 打印预测结果,由于最近邻是3(标签为1),所以预测结果应该是[1] print('myret-->', myret) knnapi_classifier() # myret--> [1] -
回归代码:
# 导入sklearn库中的KNeighborsRegressor类,用于实现K近邻回归算法 from sklearn.neighbors import KNeighborsRegressor def knnapi_regressor(): # 创建K近邻回归器实例,设置n_neighbors=2表示考虑最近的2个邻居 estimator = KNeighborsRegressor(n_neighbors=2) # 准备训练数据特征X,每个样本有3个特征 X = [[0, 0, 1], [1, 1, 0], [3, 10, 10], [4, 11, 12]] # 准备训练数据的目标值y,与X中的样本一一对应(回归问题预测的是连续值) y = [0.1, 0.2, 0.3, 0.4] # 使用训练数据拟合模型,学习特征与目标值之间的关系 estimator.fit(X, y) # 使用训练好的模型预测新样本[3, 11, 10]的目标值 # 这个样本与X中的[3, 10, 10]和[4, 11, 12]最接近 myret = estimator.predict([[3, 11, 10]]) # 打印预测结果,会取两个最近邻目标值的平均值:(0.3+0.4)/2=0.35 print('myret-->', myret) knnapi_regressor() # myret--> [0.35]
3 距离度量
3.1 欧氏距离
-
欧氏距离(Euclidean Distance)是一种非常直观的距离度量方法,在我们日常生活中,通常所说的两个点在空间中的距离一般指的就是欧氏距离;
-
二维平面上点
a(x₁,y₁)与b(x₂,y₂)间的欧氏距离:
d12=(x1−x2)2+(y1−y2)2 d_{12} = \sqrt{(x_1 - x_2)^2 + (y_1 - y_2)^2} d12=(x1−x2)2+(y1−y2)2
-
三维空间点
a(x₁,y₁,z₁)与b(x₂,y₂,z₂)间的欧氏距离
d12=(x1−x2)2+(y1−y2)2+(z1−z2)2 d_{12} = \sqrt{(x_1 - x_2)^2 + (y_1 - y_2)^2 + (z_1 - z_2)^2} d12=(x1−x2)2+(y1−y2)2+(z1−z2)2 -
n维空间点
a(x₁₁,x₁₂,…,x₁ₙ)与b(x₂₁,x₂₂,…,x₂ₙ)间的欧氏距离:
d12=∑k=1n(x1k−x2k)2 d_{12} = \sqrt{\sum_{k=1}^{n} (x_{1k} - x_{2k})^2} d12=k=1∑n(x1k−x2k)2
-
-
例:有ABCD四个点,坐标分别为
X = [[1, 1], [2, 2], [3, 3], [4, 4]],计算AB、AC、AD、BC、BD之间的距离。经过计算,AB的距离为:(2−1)2+(2−1)2=2≈1.414\sqrt{(2 - 1)^2 + (2 - 1)^2} = \sqrt{2} \approx 1.414(2−1)2+(2−1)2=2≈1.414,其他点之间的距离也可以用同样的方法计算得出。
3.2 曼哈顿距离
-
曼哈顿距离(Manhattan Distance)也被称为“城市街区距离”(City Block distance),这个名字的由来是因为曼哈顿城市的街道布局横平竖直,在这样的城市中从一个地点到另一个地点的距离就可以用这种距离来度量;
- 二维平面:二维平面上两点
a(x₁,y₁)与b(x₂,y₂)之间的曼哈顿距离公式为:d12=∣x1−x2∣+∣y1−y2∣d_{12} = |x_1 - x_2| + |y_1 - y_2|d12=∣x1−x2∣+∣y1−y2∣; - n维空间:n维空间中两点 a(x11,x12,…,x1n)a(x_{11}, x_{12}, \dots, x_{1n})a(x11,x12,…,x1n) 和 b(x21,x22,…,x2n)b(x_{21}, x_{22}, \dots, x_{2n})b(x21,x22,…,x2n) 之间的曼哈顿距离公式是d12=∑k=1n∣x1k−x2k∣d_{12} = \sum_{k=1}^{n}|x_{1k} - x_{2k}|d12=∑k=1n∣x1k−x2k∣;
- 二维平面:二维平面上两点
-
同样以ABCD四个点
X = [[1, 1], [2, 2], [3, 3], [4, 4]]为例,计算它们之间的曼哈顿距离。AB的距离为:∣2−1∣+∣2−1∣=2|2 - 1| + |2 - 1| = 2∣2−1∣+∣2−1∣=2,其他点之间的距离也按照此公式计算。
3.3 切比雪夫距离
-
在国际象棋中,国王的移动方式比较特殊,它可以直行、横行、斜行,所以国王走一步可以移动到相邻8个方格中的任意一个。国王从格子
(x₁,y₁)走到格子(x₂,y₂)最少需要的步数就是切比雪夫距离(Chebyshev Distance);- 二维平面:二维平面上两点
a(x₁,y₁)与b(x₂,y₂)之间的切比雪夫距离公式为:d12=max(∣x1−x2∣,∣y1−y2∣)d_{12} = \max(|x_1 - x_2|, |y_1 - y_2|)d12=max(∣x1−x2∣,∣y1−y2∣); - n维空间:n维空间中两点 a(x11,x12,…,x1n)a(x_{11}, x_{12}, \dots, x_{1n})a(x11,x12,…,x1n) 和 b(x21,x22,…,x2n)b(x_{21}, x_{22}, \dots, x_{2n})b(x21,x22,…,x2n) 之间的切比雪夫距离公式是:d12=max(∣x1i−x2i∣)d_{12} = \max(|x_{1i} - x_{2i}|)d12=max(∣x1i−x2i∣);
- 二维平面:二维平面上两点
-
还是以ABCD四个点
X = [[1, 1], [2, 2], [3, 3], [4, 4]]为例,计算它们之间的切比雪夫距离。AB的距离为:max(∣2−1∣,∣2−1∣)=1\max(|2 - 1|, |2 - 1|) = 1max(∣2−1∣,∣2−1∣)=1,其他点之间的距离同理可得。
3.4 闵可夫斯基距离
-
闵可夫斯基距离(Minkowski Distance)是对多个距离度量公式的概括性表述;
-
对于两个n维变量 a(x11,x12,…,x1n)a(x_{11}, x_{12}, \dots, x_{1n})a(x11,x12,…,x1n) 和 b(x21,x22,…,x2n)b(x_{21}, x_{22}, \dots, x_{2n})b(x21,x22,…,x2n),它们之间的闵可夫斯基距离定义为:d12=∑k=1n∣x1k−x2k∣ppd_{12} = \sqrt[p]{\sum_{k=1}^{n}|x_{1k} - x_{2k}|^p}d12=p∑k=1n∣x1k−x2k∣p,其中p是一个变参数:
-
当 p=1p = 1p=1 时,闵可夫斯基距离就是曼哈顿距离;
-
当 p=2p = 2p=2 时,就是欧氏距离;
-
当 p→∞p \to \inftyp→∞ 时,就是切比雪夫距离;
-
-
根据 ppp 的不同,闵氏距离可以表示某一类种的距离。
4 特征预处理
- 特征预处理有两个重要步骤:归一化和标准化。
4.1 为什么要做归一化和标准化?
-
当特征的单位或者大小相差较大,或者某特征的方差相比其他的特征要大出几个数量级时,容易影响(支配)目标结果,使得一些模型(算法)无法学习到其它的特征;
-
例:下表是男子身高体重视力与健康关系表,身高的单位是米,体重是千克,视力范围是0.2 - 2.0,健康状况是1(健康)或2(不健康),这些特征的数值范围差异较大,如果不进行预处理,可能会导致模型的学习效果不佳;
编号 身高m 体重kg 视力0.2-2.0 健康状况 1 1.70 67 1.5 1 2 1.71 80 0.8 2 3 1.75 70 1.5 1 4 1.76 68 1.2 1 5 1.80 80 1.8 1 6 1.81 90 0.6 2
4.2 归一化
-
归一化是通过对原始数据进行变换把数据映射到 [mi,mx][mi, mx][mi,mx](默认为[0,1][0, 1][0,1])之间;
-
公式:首先计算 X′=x−minmax−minX' = \frac{x - min}{max - min}X′=max−minx−min,然后计算 X′′=X′∗(mx−mi)+miX'' = X' * (mx - mi) + miX′′=X′∗(mx−mi)+mi;
-
示例:以特征1、特征2、特征3、特征4的数据为例,通过上述公式进行计算,将数据映射到[0, 1]之间;
- 中间的只是第一步,还需要将第一步计算的结果乘(mx−mi)(mx - mi)(mx−mi),由于默认将数据映射到[0,1][0, 1][0,1],所以是乘(1−0)(1 - 0)(1−0),然后还要再加上mimimi,即加上0;

-
API:
# 归一化 def MinMaxScaler_demo(): # 1. 准备数据。定义一个列表 data,其中包含三个子列表,每个子列表代表一个样本的四个特征值 data = [[90, 2, 10, 40], [60, 4, 15, 45], [75, 3, 13, 46]] # 2. 初始化归一化对象。创建 MinMaxScaler 类的实例 transformer,用于将数据缩放到指定范围(默认是 [0, 1]) transformer = MinMaxScaler() # 可以传入比如feature_range=(0,1)参数来指定范围 # 3. 对原始特征进行变换。使用 transformer 的 fit_transform 方法对 data 进行拟合和变换,实现数据归一化 data = transformer.fit_transform(data) # 4. 打印归一化后的结果 print(data) # 调用 dm01_MinMaxScaler 函数 MinMaxScaler_demo()
4.3 标准化
-
数据标准化是通过对原始数据进行标准化,转换为均值为0标准差为1的标准正态分布的数据;
-
公式:X′=x−meanσX' = \frac{x - mean}{\sigma}X′=σx−mean,其中
mean为特征的平均值,σ为特征的标准差; -
API:
from sklearn.preprocessing import StandardScaler def StandardScaler_demo(): # 1. 准备数据。创建一个列表,其中包含三个子列表,每个子列表代表一个样本的四个特征值 data = [[90, 2, 10, 40], [60, 4, 15, 45], [75, 3, 13, 46]] # 2. 初始化标准化对象。创建一个StandardScaler对象,用于对数据进行标准化处理 transformer = StandardScaler() # 3. 对原始特征进行变换。使用fit_transform方法对数据进行拟合和变换,将数据标准化 data = transformer.fit_transform(data) # 4. 打印标准化后的结果 print(data) # 5. 打印每列数据的均值和方差 # 输出每列数据的均值 print('transformer.mean_-->', transformer.mean_) # 输出每列数据的方差 print('transformer.var_-->', transformer.var_) # 调用dm03_StandardScaler函数 StandardScaler_demo()
4.4 正态分布
-
正态分布是一种概率分布,大自然很多数据符合正态分布,也叫高斯分布、钟形分布;
-
正态分布记作 N(μ,σ)N(\mu, \sigma)N(μ,σ),μ\muμ 决定了其位置,其标准差 σ\sigmaσ 决定了分布的幅度;
- 当 μ=0\mu = 0μ=0,σ=1\sigma = 1σ=1 时的正态分布是标准正态分布;

-
方差 σ2\sigma^2σ2 是在概率论和统计方差衡量一组数据时离散程度的度量,公式为 σ2=(x1−M)2+(x2−M)2+(x3−M)2+⋯+(xn−M)2n\sigma^2 = \frac{(x_1 - M)^2 + (x_2 - M)^2 + (x_3 - M)^2 + \dots + (x_n - M)^2}{n}σ2=n(x1−M)2+(x2−M)2+(x3−M)2+⋯+(xn−M)2,其中M为均值,n为数据总数;
-
标准差 σ\sigmaσ 是方差开根号,公式为 σ=1N∑i=1N(xi−μ)2\sigma = \sqrt{\frac{1}{N}\sum_{i = 1}^{N}(x_i - \mu)^2}σ=N1∑i=1N(xi−μ)2;
-
正态分布的3σ法则(68 - 95 - 99.7法则):约68%的数据落在 μ±σ\mu \pm \sigmaμ±σ 范围内,约95%的数据落在 μ±2σ\mu \pm 2\sigmaμ±2σ 范围内,约99.7%的数据落在 μ±3σ\mu \pm 3\sigmaμ±3σ 范围内;

4.5 数据归一化VS数据标准化
- 数据归一化:
- 如果出现异常点,影响了最大值和最小值,那么结果显然会发生改变;
- 应用场景:最大值与最小值非常容易受异常点影响,鲁棒性较差,只适合传统精确小数据场景;
- 使用的API:
sklearn.preprocessing.MinMaxScaler(feature_range=(0, 1)…);
- 数据标准化:
- 如果出现异常点,由于具有一定数据量,少量的异常点对于平均值的影响并不大;
- 应用场景:适合现代嘈杂大数据场景;
- 使用的API:
sklearn.preprocessing.StandardScaler()。
5 利用KNN算法对鸢尾花分类
5.1 概述
-
鸢尾花的种类:

-
数据样本:
- Sepal length:花萼长度
- Sepal width:花萼宽度
- Petal length:花瓣长度
- Petal width:花瓣宽度
- Class label:类别标签,即鸢尾花的种类(Setosa、Versicolor、Virginica)

-
特征和类别标签
- Features(特征):指的是花萼长度、花萼宽度、花瓣长度和花瓣宽度,这些是用于分类的属性;
- Class labels(类别标签):指的是鸢尾花的种类,是分类的目标变量;
5.2 实操
-
导包:
# 0.导入所需的工具包 from sklearn.datasets import load_iris # 从sklearn数据集模块导入鸢尾花数据集加载函数 import seaborn as sns # 导入seaborn用于数据可视化 import matplotlib.pyplot as plt # 导入matplotlib的pyplot模块用于绘图 import pandas as pd # 导入pandas用于数据处理和分析 from sklearn.model_selection import train_test_split # 从sklearn模型选择模块导入训练集和测试集拆分函数 from sklearn.preprocessing import StandardScaler # 从sklearn预处理模块导入标准化工具 from sklearn.neighbors import KNeighborsClassifier # 从sklearn.neighbors模块导入K近邻分类器 from sklearn.metrics import accuracy_score # 从sklearn metrics模块导入准确率评估函数 -
加载鸢尾花数据集
# 1.加载鸢尾花数据集,返回一个包含数据和元信息的对象 iris_data = load_iris() print("查看数据集信息:\n", iris_data.data[:5]) print("查看目标值:\n", iris_data.target) # 0:山鸢尾(Setosa)、1:变色鸢尾(Versicolor)、2:维吉尼亚鸢尾(Virginica) print("查看目标值名称:\n", iris_data.target_names) print("查看特征名\n", iris_data.feature_names) print("查看数据集描述:\n", iris_data.DESCR) print("查看数据文件路径:\n", iris_data.filename)
-
数据展示与处理
# 2.数据展示与处理 # 将数据集的特征数据转换为DataFrame格式,并指定列名为数据集自带的特征名称 iris_df = pd.DataFrame(iris_data['data'], columns=iris_data.feature_names) # 为DataFrame添加标签列,值为数据集的目标变量(花的类别) iris_df['label'] = iris_data.target # 打印特征值列名 print(iris_data.feature_names) sns.lmplot(x='sepal length (cm)',y='sepal width (cm)',data = iris_df,hue='label',fit_reg=False) plt.show()
-
特征工程:
# 3.特征工程(数据预处理-标准化) # 3.1 划分训练集和测试集 # 将数据集拆分为训练特征(x_train)、测试特征(x_test)、训练标签(y_train)、测试标签(y_test) # test_size=0.3表示测试集占总数据的30%,random_state=22用于固定随机种子,保证结果可复现 x_train, x_test, y_train, y_test = train_test_split(iris_data.data, iris_data.target, test_size=0.3, random_state=22) # 打印原始数据集的样本数量 print(len(iris_data.data)) # 打印训练集的样本数量 print(len(x_train)) # 3.2 对特征进行标准化处理 # 创建标准化处理器实例 process = StandardScaler() # 对训练集特征进行拟合(计算均值和标准差)并转换 x_train = process.fit_transform(x_train) # 使用训练集的标准化参数对测试集特征进行转换(保持数据分布一致) x_test = process.transform(x_test)
-
模型训练:
# 4.模型训练 # 4.1 实例化K近邻分类器,设置近邻数n_neighbors=3 model = KNeighborsClassifier(n_neighbors=3) # 4.2 使用训练集对模型进行训练 model.fit(x_train, y_train)
-
模型预测:
# 5.模型预测 # 定义一个待预测的样本(花萼长度、花萼宽度、花瓣长度、花瓣宽度) x = [[5.1, 3.5, 1.4, 0.2]] # 使用之前的标准化处理器对新样本进行标准化 x = process.transform(x) # 对测试集进行预测,得到预测标签 y_predict = model.predict(x_test) # 输出新样本属于各类别的概率 print(model.predict_proba(x))
-
模型评估:
# 6.模型评估(计算准确率) # 6.1 使用准确率评估函数,比较测试集真实标签和预测标签计算准确率 acc = accuracy_score(y_test, y_predict) print(acc) # 6.2 直接使用模型的score方法计算在测试集上的准确率 acc = model.score(x_test, y_test) print(acc)
6 超参数选择方法
6.1 交叉验证
-
交叉验证是一种在机器学习中用于评估模型性能和泛化能力的技术,是一种数据集的分割方法;
-
核心思想:将原始数据集划分为多个子集,然后用不同的子集组合来训练和验证模型,以获得更可靠的模型性能评估结果。比如将训练集划分为 n 份,拿一份做验证集(测试集)、其他 n-1 份做训练集;
-
以将数据集划分为 cv=4 份为例:
-
多次训练与评估:
- 在第一次时,把第一份数据作为验证集,其余三份作为训练集进行训练和评估;
- 第二次把第二份数据作为验证集,剩下的作为训练集,以此类推,总共进行4次训练和评估;
- 这样做可以让模型在不同的数据子集上都得到训练和检验,减少因数据划分不当导致的偏差;

-
综合评估:使用训练集和验证集多次评估模型后,取这些评估结果的平均值作为交叉验证的模型得分。这能更全面地反映模型的性能;
-
最终模型确定:若某个模型(如第四次得到的模型)得分最好,再使用全部的训练集(包括之前作为验证集的部分)对该模型进行再训练,之后使用独立的测试集对其进行最终评估,以确保模型的泛化能力;
-
-
交叉验证的目的是为了得到更加准确可信的模型评分,避免因单一的训练集和测试集划分导致的评估结果不稳定。
6.2 超参数
- 超参数是在开始机器学习算法的训练过程之前需要手动设置的参数,而不是通过训练数据学习得到的参数 。它们会影响模型的学习过程和最终的性能表现;
- 比如KNN算法中的K的取值(K取值的大小对模型的影响见
1.3 K值选择)。
6.3 网格搜索
- 在机器学习中,模型有很多超参数,不同的超参数组合会使模型的性能产生很大差异。为了找到最优的超参数组合,需要手动尝试很多可能的组合并训练模型。每组超参数都采用交叉验证评估,最后选出最优参数组合建立模型,这既繁琐又耗时;
- 网格搜索是解决这个问题的有力工具。它可以自动地对指定的超参数组合进行搜索,为每组超参数都采用交叉验证评估模型性能,最后选出最优的参数组合来建立模型。
6.4 交叉验证+网格搜索
-
交叉验证和网格搜索的组合是模型选择和调优的强力方案;
- 交叉验证解决了模型的数据输入问题(通过合理划分数据集),得到更可靠的模型;
- 网格搜索解决了超参数的组合问题;
- 两者结合形成了一个完整的模型参数调优解决方案;
-
API:
sklearn.model_selection.GridSearchCV(estimator, param_grid=None, cv=None)- 参数介绍:
estimator:是一个估计器对象,即要进行参数搜索的模型;param_grid:是一个字典,指定了要搜索的估计器参数及其可能的取值。例如{"n_neighbors":[1,3,5]}表示要搜索n_neighbors参数取1、3、5时的模型性能;cv:指定交叉验证的折数;
- 这个API的特点是输入一个估计器,经过处理后返回一个更强大的估计器,这个新的估计器拥有交叉验证网格搜索的功能,能够帮助我们更高效地找到最优的模型参数组合;
fit:用于输入训练数据,开始进行网格搜索和交叉验证过程;score:用于计算模型的准确率;
- 结果分析:
bestscore_:表示在交叉验证中得到的最好结果;bestestimator:表示具有最好参数的模型;cvresults:包含每次交叉验证后的验证集准确率结果和训练集准确率结果;
- 参数介绍:
-
例:利用KNN算法对鸢尾花分类——交叉验证网格搜索
-
导包+预处理:
# 0.导入工具包 from sklearn.datasets import load_iris from sklearn.model_selection import train_test_split,GridSearchCV from sklearn.preprocessing import StandardScaler from sklearn.neighbors import KNeighborsClassifier from sklearn.metrics import accuracy_score # 1.加载数据 data = load_iris() # 2 数据集划分 x_train,x_test,y_train,y_test=train_test_split(data.data,data.target,test_size=0.2,random_state=22) # 3.特征预处理 pre = StandardScaler() x_train=pre.fit_transform(x_train) x_test=pre.transform(x_test) -
模型实例化+交叉验证+网格搜索
# 4.模型实例化+交叉验证+网格搜索 model = KNeighborsClassifier(n_neighbors=1) # 创建一个 KNN 分类器,初始 n_neighbors=1 paras_grid = {'n_neighbors':[4,5,7,9]} # 定义要搜索的超参数 n_neighbors 的可能取值为 [4, 5, 7, 9] estimator =GridSearchCV(estimator=model,param_grid=paras_grid,cv=4) estimator.fit(x_train,y_train) # fit 方法会遍历所有超参数组合,使用交叉验证评估每个组合的性能,并找到最优超参数 print(estimator.best_score_) # 交叉验证中得到的最佳准确率 print(estimator.best_estimator_) # 在交叉验证中表现最佳的模型(包含最优超参数) print(estimator.cv_results_) # 交叉验证的详细结果,包括每个超参数组合的训练时间、验证准确率等 # 使用最优超参数 n_neighbors=7 重新实例化 KNN 分类器 model = KNeighborsClassifier(n_neighbors=7) model.fit(x_train,y_train) #用训练集重新训练模型 x = [[5.1, 3.5, 1.4, 0.2]] x=pre.transform(x) y_prdict=model.predict(x_test) print(accuracy_score(y_test,y_prdict))
-
7 利用KNN算法实现手写数字识别
-
导包:
import matplotlib.pyplot as plt import pandas as pd from collections import Counter from sklearn.model_selection import train_test_split from sklearn.neighbors import KNeighborsClassifier from sklearn.metrics import accuracy_score import joblib -
读取数据:
# 1.读取数据 data = pd.read_csv('data/手写数字识别.csv') x = data.iloc[:,1:] # 提取特征数据,所有行,第 1 列到最后一列 y = data.iloc[:,0] # 提取标签数据,所有行,第 0 列 print(Counter(y)) # 使用 Counter 统计标签中每个数字出现的次数
-
显示:
# 2.显示 digit =x.iloc[1000].values # 提取第 1000 行的特征数据,并转换为 numpy 数组 img =digit.reshape(28,28) # 将一维数组 reshape 为 28x28 的二维数组,以符合图像的尺寸 plt.imshow(img,cmap='gray') # 使用 matplotlib 的 imshow 函数显示图像,cmap='gray' 表示以灰度图形式显示 plt.imsave('data/digit.png',img) # 保存图像到指定路径 plt.show()
-
数据预处理:
# 3.数据预处理 # 3.1 归一化。将特征数据归一化到 0-1 之间,通过除以 255.0(因为图像像素值范围是 0-255) x = x/255. # 3.2 数据集划分 # 使用 train_test_split 划分数据集,test_size=0.2 表示测试集占比 20% # stratify=y 表示分层抽样,保证训练集和测试集的类别分布与原数据一致 # random_state=22 用于设置随机种子,保证结果可复现 x_train,x_test,y_train,y_test=train_test_split(x,y,test_size=0.2,stratify=y,random_state=22) -
模型训练:
# 4.模型训练 # 4.1 实例化。创建 KNeighborsClassifier 模型对象,n_neighbors=11 表示选择最近的 11 个邻居 model =KNeighborsClassifier(n_neighbors=11) # 4.2 训练 model.fit(x_train,y_train)
-
模型预测:
# 5.模型预测 img =plt.imread('data/digit.png') # 提取图像的绿色通道(因为图像是彩色的,这里选择绿色通道),并 reshape 为一维数组,然后归一化 img =img[:,:,1].reshape(1,-1)/255. # 使用训练好的模型对测试集进行预测 y_predict=model.predict(x_test) # 打印预测结果 print(y_predict)
img = plt.imread('data/digit.png'):读取图像文件,将图像数据加载到内存中- 读取后得到的
img是一个三维数组 (假设是彩色图像),形状通常为(高度, 宽度, 通道数) - 通道数取决于图像类型:
- 彩色图像 (RGB) 通常是 3 个通道,形状为
(h, w, 3) - 灰度图像通常是 1 个通道,形状为
(h, w)
- 彩色图像 (RGB) 通常是 3 个通道,形状为
- 像素值范围通常是 0-255 的整数 (取决于图像格式)
- 读取后得到的
img = img[:, :, 1].reshape(1, -1)/255.:对已读取的图像数据进行预处理,使其适合模型输入- 包含三个关键操作:
img[:, :, 1]:取图像的第二个通道 (索引从 0 开始,所以 1 代表绿色通道)reshape(1, -1):将二维图像数据转换为一维数组,并增加一个批次维度 (使形状从(h, w)变为(1, h*w))/255.:将像素值从 0-255 范围归一化到 0-1 范围
- 处理后的数据格式符合机器学习模型的输入要求
- 包含三个关键操作:
-
模型评估:
# 6.模型评估 print(model.score(x_test,y_test)) # 使用模型的 score 方法计算在测试集上的准确率 print(accuracy_score(y_predict,y_test)) # 使用 accuracy_score 函数计算预测结果与真实标签的准确率
-
模型保存:
# 7.模型保存 joblib.dump(model,'data/knn.pth') -
模型加载:
# 8.模型加载 knn =joblib.load('data/knn.pth') print(knn.score(x_test,y_test)) # 计算加载后的模型在测试集上的准确率 img =plt.imread('data/digit.png') # 再次读取图像文件 # 提取绿色通道并 reshape 为一维数组 img = img[:, :, 1].reshape(1, -1) print(knn.predict(img))
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐
所有评论(0)