文章目录
1. KNN算法简介
K Nearest Neighbor算法又叫KNN算法,这个算法是机器学习里面一个比较经典的算法,总体来说KNN算法是相对比较容易理解的算法。
(1)定义
如果一个样本在特征空间中的k个最相似(即特征空间中最邻近)的样本中的大多数属于某一个类别,则该样本也属于这个类别。
(来源:KNN算法最早是由Cover和Hart提出的一种分类算法)
(2)距离公式
两个样本的距离可以通过如下公式计算,又叫欧式距离,关于距离公式会在后面进行讨论。
二维平面上点 a ( x 1 , y 1 ) a(x_1, y_1) a(x1,y1)与 b ( x 2 , y 2 ) b(x_2, y_2) b(x2,y2)间的欧氏距离: d 12 = ( x 1 − x 2 ) 2 + ( y 1 − y 2 ) 2 d_{12}=\sqrt {(x_1-x_2)^2+(y_1-y_2)^2} d12=(x1−x2)2+(y1−y2)2
三维平面上点 a ( x 1 , y 1 , z 1 ) a(x_1, y_1, z_1) a(x1,y1,z1)与 b ( x 2 , y 2 , z 2 ) b(x_2, y_2, z_2) b(x2,y2,z2)间的欧氏距离: d 12 = ( x 1 − x 2 ) 2 + ( y 1 − y 2 ) 2 + ( z 1 − z 2 ) 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 11 , x 12 , . . . , x 1 n ) a(x_{11}, x_{12}, ...,x_{1n}) a(x11,x12,...,x1n)与 b ( x 21 , x 22 , . . . , x 2 n ) b(x_{21}, x_{22}, ...,x_{2n}) b(x21,x22,...,x2n)间的欧氏距离(两个n维向量): d 12 = ∑ k = 1 n ( x 1 k − x 2 k ) 2 d_{12}=\sqrt {\displaystyle \sum_{k=1}^{n}(x_{1k}-x_{2k})^2} d12=k=1∑n(x1k−x2k)2
(3)电影案例分析
假设我们现在有几部电影
import numpy as np
import pandas as pd
from sklearn.
movies_df = pd.read_excel('data/电影.xlsx')
movies_df.info()
movies_df.head()
# 获取特征向量集合 以及 标签集合
y = movies_df['类别'].copy()
X = movies_df[['动作镜头', '爱情镜头']].copy()
# 手动生成预测的样本(X不论是训练集还是测试集都需要构造成为二维数组)
# A [11, 6]
# B [5, 17]
X_test = np.array([[11, 6], [5, 17]])
X_test
# 注意:结构需要保持一致(二维数组)
X.values
from sklearn.neighbors import KNeighborsClassifier
# 第1步:构造算法对象
# k = n_neighbors
clf = KNeighborsClassifier(n_neighbors=3)
# 第2步:训练算法模型,目的是得到一个有预测能力的模型(本质上就是一个已知参数的函数)
# 注意:X是特征向量矩阵,必须是多维数组(在这个案例中是二维) VSM向量空间模型
# y 标签集合 一般是一位数组 但也可以是多维数组
clf.fit(X, y)
y_predict = clf.predict(X_test)
# 定义一个专门往pyecharts的散点图里加数据的函数
def add_data(pic, X_data, y_data, symbol='circle'):
X_data = pd.DataFrame(X_data).copy()
y_data = pd.Series(y_data).copy()
for i in y_data.drop_duplicates():
pic.add_xaxis(xaxis_data=X_data.loc[y_data == i].iloc[0:, 0].tolist())
pic.add_yaxis(
series_name=i,
y_axis=X_data.loc[y_data == i].iloc[0:, 1].tolist(),
symbol_size=15,
symbol=symbol,
label_opts=opts.LabelOpts(is_show=False),
)
# 绘制样本以观察样本在特征空间中的情况
import pyecharts.options as opts
from pyecharts.charts import Scatter
from pyecharts.globals import ThemeType
m_scatter = Scatter(init_opts=opts.InitOpts(width="700px", height="400px", theme=ThemeType.LIGHT))
# 加入电影数据集
add_data(m_scatter, X, y)
# 加入测试集
add_data(m_scatter, X_test, y_predict, symbol='triangle')
# 设置系列配置
m_scatter.set_series_opts()
# 设置全局配置
m_scatter.set_global_opts(
xaxis_opts=opts.AxisOpts(
type_="value",
name="动作镜头",
splitline_opts=opts.SplitLineOpts(is_show=True)
),
yaxis_opts=opts.AxisOpts(
type_="value",
name="爱情镜头",
axistick_opts=opts.AxisTickOpts(is_show=True),
splitline_opts=opts.SplitLineOpts(is_show=True),
),
tooltip_opts=opts.TooltipOpts(is_show=False),
)
m_scatter.render_notebook()
2. K近邻算法api初步使用
机器学习流程
- 获取数据集
- 数据基本处理
- 特征工程
- 机器学习
- 模型评估
中间略
总结:
-
最近邻 (k-Nearest Neighbors,KNN) 算法是一种分类算法,
-
1968年由 Cover 和 Hart 提出,应用场景有字符识别、文本分类、图像识别等领域。
-
该算法的思想是:一个样本与数据集中的k个样本最相似,如果这k个样本中的大多数属于某一个类别.
-
实现流程
1)计算已知类别数据集中的点与当前点之间的距离
2)按距离递增次序排序
3)选取与当前点距离最小的k个点
4)统计前k个点所在的类别出现的频率
5)返回前k个点出现频率最高的类别作为当前点的预测分类
3. 距离度量
略
4. K值选择
K值过小:容易受到异常点的影响
K值过大:受到样本均衡的问题
K值选择问题,李航博士的一书「统计学习方法」上所说:
(1)选择较小的K值,就相当于用较小的领域中的训练实例进行预测,“学习“近似误差会减小,只有与输入实例较近或相似的训练实例才会对预测结果起作用,与此同时带来的问题是“学习“的估计误差会增大,换句话说,K值的减小就意味着整体模型变得复杂,容易发生过拟合;
(2)选择较大的K值,就相当于用较大领域中的训练实例进行预测,其优点是可以减少学习的估计误差,但缺点是学习的近似误差会增大。这时候,与输入实例较远(不相似的)训练实例也会对预测器作用,使预测发生错误,且K值的增大就意味着整体的模型变得简单。
(3)K=N(N为训练样本个数),则完全不足取,因为此时无论输入实例是什么,都只是简单的预测它属于在训练实例中最多的类,模型过于简单,忽略了训练实例中大量有用信息。
在实际应用中,K值一般取一个比较小的数值,例如采用交叉验证法(简单来说,就是把训练数据在分成两组:训练集和验证集)来选择最优的K值。对这个简单的分类器进行泛化,用核方法把这个线性模型扩展到非线性的情况,具体方法是把低维数据集映射到高维特征空间。
近似误差:对现有训练集的训练误差,关注训练集,如果近似误差过小可能会出现过拟合的现象,对现有的训练集能有很好的预测,但是对未知的测试样本将会出现较大偏差的预测。模型本身不是最接近最佳模型。
估计误差:可以理解为对测试集的测试误差,关注测试集,估计误差小说明对未知数据的预测能力好,模型本身最接近最佳模型。
总结:K值太小造就学习机器,在学校里做熟悉的题全对,区上统考换一批出题老师直接寄。K值太大造就学渣。
5. kd树
问题导入:
实现k近邻法时,主要考虑的问题是如何对训练数据进行快速k近邻搜索。
这在特征空间的维数大及训练数据容量大时尤其必要。
**k近邻法最简单的实现是线性扫描(穷举搜索),即要计算输入实例与每一个训练实例的距离。计算并存储好以后,再查找K近邻。**当训练集很大时,计算非常耗时。
为了提高kNN搜索的效率,可以考虑使用特殊的结构存储训练数据,以减小计算距离的次数。
5.1 kd树简介
5.1.1 什么是kd树
根据KNN每次需要预测一个点时,我们都需要计算训练数据集里每个点到这个点的距离,然后选出距离最近的k个点进行投票。当数据集很大时,这个计算成本非常高,针对N个样本,D个特征的数据集,其算法复杂度为O (DN^2)。
kd树:为了避免每次都重新计算一遍距离,算法会把距离信息保存在一棵树里,这样在计算之前从树里查询距离信息,尽量避免重新计算。其基本原理是,如果A和B距离很远,B和C距离很近,那么A和C的距离也很远。有了这个信息,就可以在合适的时候跳过距离远的点。
这样优化后的算法复杂度可降低到O(DNIlog (N) )。感兴趣的读者可参阅论文: Bentley,J.L.,Communications of the ACM (1975)。
1989年,另外一种称为Ball Tree的算法,在kd Tree的基础上对性能进一步进行了优化。感兴趣的读者可以搜索Five balltree construction algorithms来了解详细的算法信息。
5.1.2 原理
黄色的点作为根节点,上面的点归左子树,下面的点归右子树,接下来再不断地划分,分割的那条线叫做分割超平面(splitting hyperplane),在一维中是一个点,二维中是线,三维的是面。
(1)树的建立;
(2)最近邻域搜索(Nearest-Neighbor Lookup)
kd树(K-dimension tree)是一种对k维空间中的实例点进行存储以便对其进行快速检索的树形数据结构。kd树是一种二叉树,表示对k维空间的一个划分,构造kd树相当于不断地用垂直于坐标轴的超平面将K维空间切分,构成一系列的K维超矩形区域。kd树的每个结点对应于一个k维超矩形区域。利用kd树可以省去对大部分数据点的搜索,从而减少搜索的计算量。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9GfO0uv2-1658125479409)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20220715145609076.png)]
类比“二分查找“:给出一组数据:[9 1 4 7 2 5 0 3 8],要查找8。如果挨个查找(线性扫描),那么将会把数据集都遍历一遍。而如果排一下序那数据集就变成了:[0 1 2 3 4 5 6 7 8 9],按前一种方式我们进行了很多没有必要的查找,现在如果我们以5为分界点,那么数据集就被划分为了左右两个“簇” [0 1 2 3 4]和[6 7 8 9]。
因此,根本就没有必要进入第一个簇,可以直接进入第二个簇进行查找。把二分查找中的数据点换成k维数据点,这样的划分就变成了用超平面对k维空间的划分。空间划分就是对数据点进行分类,“挨得近“的数据点就在一个空间里面。
下略
6. 总结
from sklearn.neighbors import KNeighborsClassifier
from sklearn.neighbors import KNeighborsRegressor
(1)说明:KNN算法总体来说比较简单,建议校招的同学写上去。社招同学在被问到还会什么算法的时候才自爆会这些简单算法。总体来说这个算法基本原理需要人人都熟悉。
(2)原理:KNN是一种既可以用于分类又可用于回归的机器学习算法。对于给定测试样本,基于距离度量找出训练集中与其最靠近的K个训练样本,然后基于这K个邻居的信息来进行预测。
(3)步骤:
当它使用训练数据训练好模型,而用测试数据进行预测的时候:
1.计算测试数据与各个训练数据之间的距离
2.按照距离远近进行排序
3.选取距离最小的K个点
4.确定前K个点所在类别的出现频率,出现频率最高的类别作为测试数据的预测分类/计算前K个点的平均值作为测试数据的预测值 (机制类似bagging)
(4)优点:
-
简单,易于理解,易于实现
-
精度高,对异常值不敏感
-
特别适合于多分类问题
(5)缺点:
-
对测试样本分类时的计算量大,空间开销量大
-
当样本不平衡时,对稀有类别预测准确率低
-
可解释性不强
-
使用消极学习方法,基本上不学习,预测速度较慢
7. 特征工程-特征预处理
7.1 什么是特征预处理
7.1.1 特征预处理定义
(1)通过一些转换函数将特征数据转换成更加适合算法模型的特征数据过程。
(2)为什么我们要进行归一化/标准化?
- 特征的单位或者大小相差较大,或者某特征的方差相比其他的特征要大出几个数量级,容易影响(支配)目标结果,使得一些算法无法学习到其它的特征
(3)举例:约会对象数据
我们需要用到一些方法进行无量纲化,使不同规格的数据转换到同一规格。
7.1.2 包含内容(数值型数据的无量纲化)
-
归一化
-
标准化
7.1.3 特征预处理API
sklearn.preprocessing
7.2 归一化
7.2.1 定义
通过对原始数据进行变换把数据映射到(默认为[0, 1])之间。
7.2.2 公式
X ′ = x − m i n m a x − m i n X ′ ′ = X ′ ∗ ( m x − m i ) + m i \Large X^{'}=\frac {x-min} {max-min} \hspace{1cm} X^{''}=X^{'}*(mx-mi)+mi X′=max−minx−minX′′=X′∗(mx−mi)+mi
作用于每一列,max为一列的最大值,min为一列的最小值,那么X’’为最终结果,mx,mi分别为指定区间值默认mx为1,mi为0。
那么怎么理解这个过程呢?我们通过一个例子
7.2.3 API
- sklearn.preprocessing.MinMaxScaler (feature_range=(0,1)… )
- MinMaxScalar.fit_transform(X)
- X:numpy array格式的数据[n_samples,n_features]
- 返回值:转换后的形状相同的array
- MinMaxScalar.fit_transform(X)
7.2.4 数据计算
我们对以下数据进行运算,在dating.txt中。保存的就是之前的约会对象数据
milage,Liters,Consumtime,target
40920,8.326976,0.953952,3
14488,7.153469,1.673904,2
26052,1.441871,0.805124,1
75136,13.147394,0.428964,1
38344,1.669788,0.134296,1
- 分析
1、实例化MinMaxScalar
2、通过fit_transform转换
import numpy as np
import pandas as pd
from sklearn.preprocessing import MinMaxScaler
def minmax(path):
"""
归一化
"""
data = pd.read_csv(path)
# 1. 实例化一个转换器类
transfer = MinMaxScaler(feature_range=(2, 3))
# 2. 调用fit_transform
data = transfer.fit_transform(data.iloc[0:,:-1])
return data
path = 'data/dating.csv'
minmax_demo(path)
"""
array([[2.43582641, 2.58819286, 2.53237967],
[2. , 2.48794044, 3. ],
[2.19067405, 2. , 2.43571351],
[3. , 3. , 2.19139157],
[2.3933518 , 2.01947089, 2. ]])
"""
问题:如果数据中异常点较多,会有什么影响?
7.2.5 归一化总结
注意最大值最小值是变化的,另外,最大值与最小值非常容易受异常点影响,所以这种方法鲁棒性较差,只适合传统精确小数据场景。
鲁棒性:指系统在不确定性的扰动下,具有保持某种性能不变的能力。
怎么办?
7.3 标准化
7.3.1 定义
通过对原始数据进行变换把数据变换到均值为0,标准差为1范围内。
7.3.2 公式
X ′ = x − m e a n σ \Large X^{'}=\frac {x-mean} {\sigma} X′=σx−mean
作用于每一列,mean为平均值,σ为标准差
所以回到刚才异常点的地方,我们再来看看标准化
- 对于归一化来说:如果出现异常点,影响了最大值和最小值,那么结果显然会发生改变
- 对于标准化来说:如果出现异常点,由于具有一定数据量,少量的异常点对于平均值的影响并不大,从而方差改变较小。
7.3.3 API
- sklearn.preprocessing.StandardScaler( )
- 处理之后每列来说所有数据都聚集在均值0附近标准差差为1
- StandardScaler.fit_transform(X)
- X:numpy array格式的数据[n_samples,n_features]
- 返回值:转换后的形状相同的array
7.3.4 数据计算
同样对上面的数据进行处理
- 分析
1、实例化StandardScaler
2、通过fit_transform转换
from sklearn.preprocessing import StandardScaler
def stand_demo(path):
"""
归一化
"""
data = pd.read_csv(path)
# 1. 实例化一个转换器类
transfer = StandardScaler()
# 2. 调用fit_transform
return transfer.fit_transform(data.iloc[0:,:-1])
stand_demo(path)
7.3.5 标准化总结
在已有样本足够多的情况下比较稳定,适合现代嘈杂大数据场景。
8. 案例:鸢尾花种类预测—流程实现
8.1 再识K-近邻算法API
- sklearn.neighbors.KNeighborsClassifier(n_neighbors=5,algorithm=‘auto’)
- n_neighbors:
- int,可选(默认= 5),k_neighbors查询默认使用的邻居数
- algorithm:{‘auto’,‘ball_tree’,‘kd_tree’,‘brute’}
- 快速k近邻搜索算法,默认参数为auto,可以理解为算法自己决定合适的搜索算法。除此之外,用户也可以自己指定搜索算法ball_tree、kd_tree、brute方法进行搜索,
- brute是蛮力搜索,也就是线性扫描,当训练集很大时,计算非常耗时。
- kd_tree,构造kd树存储数据以便对其进行快速检索的树形数据结构,kd树也就是数据结构中的二叉树。以中值切分构造的树,每个结点是一个超矩形,在维数小于20时效率高。
- ball tree是为了克服kd树高纬失效而发明的,其构造过程是以质心C和半径r分割样本空间,每个节点是一个超球体。
- 快速k近邻搜索算法,默认参数为auto,可以理解为算法自己决定合适的搜索算法。除此之外,用户也可以自己指定搜索算法ball_tree、kd_tree、brute方法进行搜索,
- n_neighbors:
8.2 案例:鸢尾花种类预测
8.2.1 数据集介绍
Iris数据集是常用的分类实验数据集,由Fisher, 1936收集整理。Iris也称鸢尾花卉数据集,是一类多重变量分析的数据集。关于数据集的具体介绍:
8.2.2 步骤分析
- 1.获取数据集
- 2.数据基本处理
- 3.特征工程
- 4.机器学习(模型训练)
- 5.模型评估
8.2.3 代码过程
- 导入模块
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.neighbors import KNeighborsClassifier
- 先从sklearn当中获取数据集,然后进行数据集的分割
# 1.获取数据集
iris = load_iris()
# 2.数据基本处理
# x_train,x_test,y_train,y_test为训练集特征值、测试集特征值、训练集目标值、测试集目标值
x_train, x_test, y_train, y_test = train_test_split(iris.data, iris.target, test_size=0.2, random_state=22)
- 进行数据标准化
- 特征值的标准化
# 3、特征工程:标准化
transfer = StandardScaler()
x_train = transfer.fit_transform(x_train)
x_test = transfer.transform(x_test)
- 模型进行训练预测
# 4、机器学习(模型训练)
estimator = KNeighborsClassifier(n_neighbors=9)
estimator.fit(x_train, y_train)
# 5、模型评估
# 方法1:比对真实值和预测值
y_predict = estimator.predict(x_test)
print("预测结果为:\n", y_predict)
print("比对真实值和预测值:\n", y_predict == y_test)
# 方法2:直接计算准确率
score = estimator.score(x_test, y_test)
print("准确率为:\n", score)
9 总结
-
在本案例中,具体完成内容有:
- 使用可视化加载和探索数据,以确定特征是否能将不同类别分开。
- 通过标准化数字特征并随机抽样到训练集和测试集来准备数据。
- 通过统计学,精确度度量进行构建和评估机器学习模型。
-
k近邻算法总结
-
优点:
- 简单有效
- 重新训练的代价低
- 适合类域交叉样本
- KNN方法主要靠周围有限的邻近的样本,而不是靠判别类域的方法来确定所属类别的,因此对于类域的交叉或重叠较多的待分样本集来说,KNN方法较其他方法更为适合。
- 适合大样本自动分类
- 该算法比较适用于样本容量比较大的类域的自动分类,而那些样本容量较小的类域采用这种算法比较容易产生误分。
-
缺点:
- 惰性学习
- KNN算法是懒散学习方法(lazy learning,基本上不学习),一些积极学习的算法要快很多。
- 类别评分不是规格化
- 不像一些通过概率评分的分类。
- 输出可解释性不强
- 例如决策树的输出可解释性就较强。
- 对不均衡的样本不擅长
- 当样本不平衡时,如一个类的样本容量很大,而其他类样本容量很小时,有可能导致当输入一个新样本时,该样本的K个邻居中大容量类的样本占多数。该算法只计算“最近的”邻居样本,某一类的样本数量很大,那么或者这类样本并不接近目标样本,或者这类样本很靠近目标样本。无论怎样,数量并不能影响运行结果。可以采用权值的方法(和该样本距离小的邻居权值大)来改进。
- 计算量较大
- 目前常用的解决方法是事先对已知样本点进行剪辑,事先去除对分类作用不大的样本。
- 惰性学习
-
10 交叉验证,网格搜索
10.1 什么是交叉验证(cross validation)
交叉验证:将拿到的训练数据,分为训练和验证集。以下图为例:将数据分成4份,其中一份作为验证集。然后经过4次(组)的测试,每次都更换不同的验证集。即得到4组模型的结果,取平均值作为最终结果。又称4折交叉验证。
10.1.1 分析
我们之前知道数据分为训练集和测试集,但是**为了让从训练得到模型结果更加准确。**做以下处理
- 训练集:训练集+验证集
- 测试集:测试集
10.1.2 为什么需要交叉验证
交叉验证目的:为了让被评估的模型更加准确可信
问题:那么这个只是对于参数得出更好的结果,那么怎么选择或者调优参数呢?
10.2 什么是网格搜索(Grid Search)
通常情况下,有很多参数是需要手动指定的(如k-近邻算法中的K值),这种叫超参数。但是手动过程繁杂,所以需要对模型预设几种超参数组合。每组超参数都采用交叉验证来进行评估。最后选出最优参数组合建立模型。
10.3 交叉验证,网格搜索(模型选择与调优)API:
- sklearn.model_selection.GridSearchCV(estimator, param_grid=None,cv=None)
- 对估计器的指定参数值进行详尽搜索
- estimator:估计器对象
- param_grid:估计器参数(dict){“n_neighbors”:[1,3,5]}
- cv:指定几折交叉验证
- fit:输入训练数据
- score:准确率
- 结果分析:
- bestscore__:在交叉验证中验证的最好结果
- bestestimator:最好的参数模型
- cvresults:每次交叉验证后的验证集准确率结果和训练集准确率结果
10.4 鸢尾花案例增加K值调优
- 使用GridSearchCV构建估计器
# 1、获取数据集
iris = load_iris()
# 2、数据基本处理 -- 划分数据集
x_train, x_test, y_train, y_test = train_test_split(iris.data, iris.target, random_state=22)
# 3、特征工程:标准化
# 实例化一个转换器类
transfer = StandardScaler()
# 调用fit_transform
x_train = transfer.fit_transform(x_train)
x_test = transfer.transform(x_test)
# 4、KNN预估器流程
# 4.1 实例化预估器类
estimator = KNeighborsClassifier()
# 4.2 模型选择与调优——网格搜索和交叉验证
# 准备要调的超参数
param_dict = {"n_neighbors": [1, 3, 5]}
estimator = GridSearchCV(estimator, param_grid=param_dict, cv=3)
# 4.3 fit数据进行训练
estimator.fit(x_train, y_train)
# 5、评估模型效果
# 方法a:比对预测结果和真实值
y_predict = estimator.predict(x_test)
print("比对预测结果和真实值:\n", y_predict == y_test)
# 方法b:直接计算准确率
score = estimator.score(x_test, y_test)
print("直接计算准确率:\n", score)
- 然后进行评估查看最终选择的结果和交叉验证的结果
print("在交叉验证中验证的最好结果:\n", estimator.best_score_)
print("最好的参数模型:\n", estimator.best_estimator_)
print("每次交叉验证后的准确率结果:\n", estimator.cv_results_)
- 最终结果
比对预测结果和真实值:
[ True True True True True True True False True True True True
True True True True True True False True True True True True
True True True True True True True True True True True True
True True]
直接计算准确率:
0.947368421053
在交叉验证中验证的最好结果:
0.973214285714
最好的参数模型:
KNeighborsClassifier(algorithm='auto', leaf_size=30, metric='minkowski',
metric_params=None, n_jobs=1, n_neighbors=5, p=2,
weights='uniform')
每次交叉验证后的准确率结果:
{'mean_fit_time': array([ 0.00114751, 0.00027037, 0.00024462]), 'std_fit_time': array([ 1.13901511e-03, 1.25300249e-05, 1.11011951e-05]), 'mean_score_time': array([ 0.00085751, 0.00048693, 0.00045625]), 'std_score_time': array([ 3.52785082e-04, 2.87650037e-05, 5.29673344e-06]), 'param_n_neighbors': masked_array(data = [1 3 5],
mask = [False False False],
fill_value = ?)
, 'params': [{'n_neighbors': 1}, {'n_neighbors': 3}, {'n_neighbors': 5}], 'split0_test_score': array([ 0.97368421, 0.97368421, 0.97368421]), 'split1_test_score': array([ 0.97297297, 0.97297297, 0.97297297]), 'split2_test_score': array([ 0.94594595, 0.89189189, 0.97297297]), 'mean_test_score': array([ 0.96428571, 0.94642857, 0.97321429]), 'std_test_score': array([ 0.01288472, 0.03830641, 0.00033675]), 'rank_test_score': array([2, 3, 1], dtype=int32), 'split0_train_score': array([ 1. , 0.95945946, 0.97297297]), 'split1_train_score': array([ 1. , 0.96 , 0.97333333]), 'split2_train_score': array([ 1. , 0.96, 0.96]), 'mean_train_score': array([ 1. , 0.95981982, 0.96876877]), 'std_train_score': array([ 0. , 0.00025481, 0.0062022 ])}