当前位置: 首页 > news >正文

网站建设培训赚钱吗新手用jsp做网站

网站建设培训赚钱吗,新手用jsp做网站,做网站上加入模块怎么加入,网站建设课后感视频链接数据集下载地址#xff1a;《3. KNN及练习案例》配套数据集 1. K-近邻算法(KNN)概念 学习目标#xff1a; 掌握K-近邻算法实现过程知道K-近邻算法的距离公式知道K-近邻算法的超参数 K K K值以及取值问题知道kd树实现搜索的过程应用KNeighborsClassifier实现分类知…视频链接数据集下载地址《3. KNN及练习案例》配套数据集 1. K-近邻算法(KNN)概念 学习目标 掌握K-近邻算法实现过程知道K-近邻算法的距离公式知道K-近邻算法的超参数 K K K值以及取值问题知道kd树实现搜索的过程应用KNeighborsClassifier实现分类知道K-近邻算法的优缺点知道交叉验证实现过程知道超参数搜索过程应用GridSearchCv实现算法参数的调优 K Nearest Neighbor算法又叫KNN算法这个算法是机器学习里面一个比较经典的算法总体来说KNN算法是相对比较容易理解的算法。 KNN算法是一种基于实例的机器学习算法用于分类和回归问题。在分类问题中KNN算法使用训练数据集中最接近目标样本的K个最近邻居的标签来预测目标样本的标签。在回归问题中KNN算法使用训练数据集中最接近目标样本的K个最近邻居的数值来预测目标样本的数值。 KNN算法的核心思想是基于距离度量来判断样本之间的相似性。常用的距离度量包括欧几里得距离、曼哈顿距离等。KNN算法的优点是简单易懂、易于实现并且适用于各种类型的数据。但是KNN算法的缺点是需要保存所有的训练数据集计算复杂度高对异常值敏感以及对于高维数据的处理比较困难。 1.1 KNN的定义 如果一个样本在特征空间中的 k k k个最相似(即特征空间中最邻近)的样本中的大多数属于某一个类别则该样本也属于这个类别。 不是说最近的是哪个类别就是哪个类别了而是最近的 k k k个哪个类别多就属于哪个类别。 来源KNN算法最早是由Cover和Hart提出的一种分类算法 距离公式 两个样本的距离可以通过如下公式计算又叫欧式距离关于距离公式会在后面进行讨论 1.2 距离公式 两个样本的距离可以通过如下公式计算又叫欧式距离。欧几里得距离或欧几里得度量是欧几里得空间中两点间“普通”即直线距离。使用这个距离欧氏空间成为度量空间。相关联的范数称为欧几里得范数。较早的文献称之为毕达哥拉斯度量。 对于二维平面上的两个点 ( x 1 , y 1 ) (x_1,y_1) (x1​,y1​) 和 ( x 2 , y 2 ) (x_2,y_2) (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 ​ 对于三维空间中的两个点 ( x 1 , y 1 , z 1 ) (x_1,y_1,z_1) (x1​,y1​,z1​) 和 ( x 2 , y 2 , z 2 ) (x_2,y_2,z_2) (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维空间中的两个点 p ( p 1 , p 2 , . . . , p n ) p(p_1,p_2,...,p_n) p(p1​,p2​,...,pn​) 和 q ( q 1 , q 2 , . . . , q n ) q(q_1,q_2,...,q_n) q(q1​,q2​,...,qn​)它们之间的欧式距离为 d 12 ∑ i 1 n ( p i − q i ) 2 d_{12}\sqrt{\sum_{i1}^n(p_i-q_i)^2} d12​i1∑n​(pi​−qi​)2 ​ 求的是两个点之间的距离不能是多个点之间的距离。 1.3 例子电影类型分析 假设我们现在有几部电影 其中?表示电影不知道类别如何去预测? 我们可以利用K近邻算法的思想。 分别计算每个电影和被预测电影的距离然后求解。 根据上面的定义我们知道《唐人街探案》与《美人鱼》的距离最近。 K 5 K5 K5表明是否为最近的5部电影。最近的5部电影中“喜剧片”有3个“爱情片”有2个因此《唐人街探案》的电影类型应该是“喜剧片”。 1.4 KNN算法流程总结 计算已知类别数据集中的点与当前点之间的距离按距离升序排序选取与当前点距离最小的 k k k个点统计前 k k k个点所在类别出现的频率返回前 k k k个点出现频率最高的类别作为当前点的预测分类 小结 K-近邻算法简介【了解】定义就是通过你的“邻居”来判断你属于哪个类别如何计算你到你的“邻居”的距离一般时候都是使用欧氏距离 2. KNN算法API的初步使用 学习目标 了解sklearn工具的优点和包含内容应用sklearn中的api实现KNN算法的简单使用 机器学习流程 获取数据集数据基本处理特征工程机器学习模型评估 2.1 Scikit-learn工具介绍 sklearn是一个开源的Python机器学习库提供了许多用于建立和分析机器学习模型的工具和算法。主要功能包括 数据预处理提供了数据标准化、特征缩放、特征选择等预处理工具能够帮助用户更好地处理数据。监督学习提供了许多经典的监督学习算法如线性回归、逻辑回归、决策树、支持向量机、随机森林等并且提供了交叉验证、网格搜索等模型调参工具。无监督学习提供了无监督学习算法如聚类、降维、异常检测等其中最常用的算法可能是K-Means聚类和主成分分析PCA等。模型评估提供了常见的模型评估指标如混淆矩阵、精度、召回率、F1值等并且可以使用交叉验证等方法来评估模型的性能。数据可视化提供了一些数据可视化工具如t-SNE、PCA等以帮助用户更好地理解数据。 总之sklearn是一个强大的机器学习库可用于解决各种机器学习问题并且易于使用适合各种程度的用户。 Python语言的机器学习工具Scikit-learn包括许多知名的机器学习算法的实现Scikit-learn文档完善容易上手丰富的API sklearn的全称是scikit-learn。scikit表示SciPy Toolkit因为它依赖于SciPy库。而learn则表示机器学习。 安装 pip install scikit-learn注安装scikit-learn需要Numpy、Scipy等库 2.2 KNN算法API sklearn.neighbors.KNeighborsClassifier(n_neighbors5)其中n_neighbors查询使用的邻居数int默认为5。 2.3 练习案例 2.3.1 步骤分析 获取数据集数据基本处理该案例中省略特征工程该案例中省略机器学习模型评估该案例中省略 2.3.2 代码过程 导入模块 from sklearn.neighbors import KNeighborsClassifier构造数据集 x [[0], [1], [2], [3]] y [0, 0, 1, 1]机器学习训练模型 # 实例化API estimator KNeighborsClassifier(n_neighbors2)# 使用ift方法进行训练 estimator.fit(x, y)# 预测 estimator.predict([[1]]) # array([0])小结 sklearn的优势 文档多且规范包含的算法多实现起来容易 KNN中的API sklearn.neighbors.KNeighborsClassifier(n_neighbors5) 问题 距离公式除了欧式距离还有哪些距离公式可以使用如何选取 K K K值的大小API中其他参数的具体含义 3. 距离度量 学习目标 了解距离公式的基本性质知道机器学习中常见的距离计算公式 3.1 距离公式的基本性质 在机器学习过程中对于函数 d i s t ( ∗ , ∗ ) dist(*, *) dist(∗,∗)若它是“距离度量”(distance measure)则需满足一些基本性质 非负性 d i s t ( x i , x j ) ≥ 0 dist(x_i, x_j) \ge 0 dist(xi​,xj​)≥0 —— 两点之间的距离必须≥0同一性 d i s t ( x i , x j ) 0 dist(x_i, x_j) 0 dist(xi​,xj​)0当且仅当 x i x j x_i x_j xi​xj​ —— 同一个位置距离为0对称性 d i s t ( x i , x j ) d i s t ( x j , x i ) dist(x_i, x_j) dist(x_j, x_i) dist(xi​,xj​)dist(xj​,xi​)直递性 d i s t ( x i , x j ) ≤ d i s t ( x i , x k ) d i s t ( x k , x i ) dist(x_i, x_j) \le dist(x_i, x_k) dist(x_k, x_i) dist(xi​,xj​)≤dist(xi​,xk​)dist(xk​,xi​) —— 三角不等式 直递性常被直接称为“三角不等式” 3.2 常见的距离公式 3.2.1 欧式距离(Euclidean Distance) 欧氏距离是最容易直观理解的距离度量方法我们小学、初中和高中接触到的两个点在空间中的距离一般都是指欧氏距离。 对于二维平面上的两个点 ( x 1 , y 1 ) (x_1,y_1) (x1​,y1​) 和 ( x 2 , y 2 ) (x_2,y_2) (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 ​ 对于三维空间中的两个点 ( x 1 , y 1 , z 1 ) (x_1,y_1,z_1) (x1​,y1​,z1​) 和 ( x 2 , y 2 , z 2 ) (x_2,y_2,z_2) (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维空间中的两个点 p ( p 1 , p 2 , . . . , p n ) p(p_1,p_2,...,p_n) p(p1​,p2​,...,pn​) 和 q ( q 1 , q 2 , . . . , q n ) q(q_1,q_2,...,q_n) q(q1​,q2​,...,qn​)它们之间的欧式距离为 d 12 ∑ i 1 n ( p i − q i ) 2 d_{12}\sqrt{\sum_{i1}^n(p_i-q_i)^2} d12​i1∑n​(pi​−qi​)2 ​ 举例: X [[1, 1], [2, 2], [3, 3], [4, 4]];经计算得: d 1.4142 2.8284 4.2426 1.4142 2.8284 1.41423.2.2 曼哈顿距离(Manhattan Distance) 在曼哈顿街区要从一个十字路口开车到另一个十字路口驾驶距离显然不是两点间的直线距离。这个实际驾驶距离就是“曼哈顿距离”。曼哈顿距离也称为“城市街区距离”(City Block Distance)。 曼哈顿距离是指在一个二维平面上从点 A A A 到点 B B B 沿着网格线走的最短距离。也就是说曼哈顿距离是指两个点横坐标差的绝对值与纵坐标差的绝对值之和。例如如果点 A A A 的坐标为 ( x 1 , y 1 ) (x_1, y_1) (x1​,y1​)点 B B B 的坐标为 ( x 2 , y 2 ) (x_2, y_2) (x2​,y2​)则它们之间的曼哈顿距离为 ∣ x 1 − x 2 ∣ ∣ y 1 − y 2 ∣ | x_1 - x_2 | | y_1 - y_2 | ∣x1​−x2​∣∣y1​−y2​∣。曼哈顿距离得名于美国纽约曼哈顿区的城市规划因为这个地区的街道呈网格状布局人们往往需要沿着网格线行走。曼哈顿距离广泛应用于计算机科学、数据分析以及城市规划等领域。 二维平面两点 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 ∣ ∣ y 1 − y 2 ∣ d_{12} |x_1 - x_2| |y_1 - y_2| d12​∣x1​−x2​∣∣y1​−y2​∣ n n n 维空间点 a ( p 1 , p 2 , p 3 , . . . , p n ) a(p_1, p_2, p_3, ..., p_n ) a(p1​,p2​,p3​,...,pn​) 与 b ( q 1 , q 2 , q 3 , . . . , q n ) b(q_1, q_2, q_3, ..., q_n ) b(q1​,q2​,q3​,...,qn​) 的曼哈顿距离 d 12 ∑ k 1 n ∣ p k − q k ∣ d_{12} \sum^n_{k1}|p_k - q_k| d12​k1∑n​∣pk​−qk​∣ 举例 x [[1, 1], [2, 2], [3, 3], [4, 4]]经计算得d 2 4 6 2 4 23.2.3 切比雪夫距离Chebyshev Distance 切比雪夫距离是指在数学中两个 n n n 维向量之间的度量方式。它定义为两个向量各个维度差值的绝对值的最大值。 具体而言对于两个 n n n 维向量 x ( x 1 , x 2 , . . . , x n ) x (x_1, x_2, ..., x_n) x(x1​,x2​,...,xn​) 和 y ( y 1 , y 2 , . . . , y n ) y (y_1, y_2, ..., y_n) y(y1​,y2​,...,yn​)它们之间的切比雪夫距离 d ( x , y ) d(x,y) d(x,y) 是 d ( x , y ) max ⁡ ( ∣ x 1 − y 1 ∣ , ∣ x 2 − y 2 ∣ , . . . , ∣ x n − y n ∣ ) d(x,y) \max(|x_1-y_1|, |x_2-y_2|, ..., |x_n-y_n|) d(x,y)max(∣x1​−y1​∣,∣x2​−y2​∣,...,∣xn​−yn​∣) 也就是说切比雪夫距离是各个维度差值的绝对值的最大值。例如对于二维平面上的点 x ( x 1 , x 2 ) x(x_1,x_2) x(x1​,x2​) 和 y ( y 1 , y 2 ) y(y_1,y_2) y(y1​,y2​)它们之间的切比雪夫距离是 d ( x , y ) m a x ( ∣ x 1 − y 1 ∣ , ∣ x 2 − y 2 ∣ ) d(x,y) max(|x_1-y_1|, |x_2-y_2|) d(x,y)max(∣x1​−y1​∣,∣x2​−y2​∣) 切比雪夫距离常用于衡量两个向量之间的相似性或差异性特别是在聚类、异常检测和分类等机器学习领域中经常被使用。 国际象棋中国王可以直行、横行、斜行所以国王走一步可以移动到相邻8个方格中的任意一个。国王从格子 ( x 1 , y 1 ) (x_1, y_1) (x1​,y1​)走到格子 ( x 2 , y 2 ) (x_2, y_2) (x2​,y2​)最少需要多少步这个距离就叫切比雪夫距离。 3.2.4 闵可夫斯基距离Minkowski Distance 闵氏距离不是一种距离而是一组距离的定义是对多个距离度量公式的概括性的表述。闵可夫斯基距离是一种用于度量两个 n n n 维向量之间相似性或差异性的距离度量方式它可以看做是将欧几里得距离和切比雪夫距离作为特例的一般化形式。 其定义为对于两个 n n n 维向量 x ( x 1 , x 2 , . . . , x n ) x (x_1, x_2, ..., x_n) x(x1​,x2​,...,xn​) 和 y ( y 1 , y 2 , . . . , y n ) y (y_1, y_2, ..., y_n) y(y1​,y2​,...,yn​)它们之间的闵可夫斯基距离 d ( x , y ) d(x, y) d(x,y)为 d ( x , y ) ∑ i 1 n ∣ x i − y i ∣ p p d(x,y) \sqrt[p]{\sum_{i1}^{n}|x_i-y_i|^p} d(x,y)pi1∑n​∣xi​−yi​∣p ​ 其中 p p p为正实数表示闵可夫斯基距离的阶数。 当 p 1 p1 p1 时就是曼哈顿距离;当 p 2 p2 p2 时就是欧氏距离;当 p → ∞ p \to \infty p→∞ 时就是切比雪夫距离。 根据 p p p 的不同闵氏距离可以表示某一类/种的距离。在机器学习领域闵可夫斯基距离同样被广泛应用于聚类、异常检测和分类等任务中。 小结 闵氏距离包括曼哈顿距离、欧氏距离和切比雪夫距离都存在明显的缺点。 曼哈顿距离的缺点是在处理高维数据时由于数据点之间的距离计算只考虑每个维度上的差异因此随着维度的增加其计算量会快速增加而且容易受到噪声数据的影响使得聚类效果变差。欧氏距离的主要缺点是对异常值敏感即如果某个特征明显偏离其他特征的分布那么该特征对欧氏距离的计算结果会产生较大的影响。此外在高维数据中欧氏距离会出现所谓的“维数灾难”即随着维度的增加样本之间的距离变得越来越相似这会导致聚类效果不佳。切比雪夫距离的主要缺点是它只考虑维度之间的最大差异而忽略了各个维度之间的协同作用。因此当数据点在多个维度上都存在轻微差异时切比雪夫距离可能会产生不合理的结果。此外切比雪夫距离对于对称分布的数据集可能会失效。 因此在实际应用中需要根据具体的问题和数据特征选择适当的距离度量方式或者采用多种距离度量方式综合考虑。 举例二维样本身高[单位cm]体重[单位kg]现有三个样本 a ( 80 , 50 ) a(80, 50) a(80,50) b ( 190 , 50 ) b(190, 50) b(190,50) c ( 180 , 60 ) c(180, 60) c(180,60)。 a a a 与 b b b 的闵氏距离无论是曼哈顿距离、欧氏距离或切比雪夫距离等于 a a a 与 c c c 的闵氏距离。但实际上身高的 10cm 并不能和体重的 10kg 划等号。 闵氏距离的缺点: 将各个分量的量纲(scale)也就是将不同分量的“单位”相同地看待了;未考虑各个分量的分布期望方差等可能是不同的。 3.3 【拓展】其他距离公式 3.3.1 标准化欧氏距离Standardized Euclidean Distance 标准化欧氏距离是一种基于欧氏距离的距离度量方式用于在处理数据时将不同维度上的特征值进行标准化处理。其计算方式是对每个特征值减去该特征值的均值并除以该特征值的标准差从而将特征值转换为标准正态分布然后再计算欧氏距离。 具体而言对于两个 n n n 维向量 x ( x 1 , x 2 , . . . , x n ) x(x_1, x_2, ..., x_n) x(x1​,x2​,...,xn​) 和 y ( y 1 , y 2 , . . . , y n ) y(y_1, y_2, ..., y_n) y(y1​,y2​,...,yn​)它们之间的标准化欧氏距离 d ( x , y ) d(x, y) d(x,y) 可以表示为 d ( x , y ) ∑ i 1 n ( x i − x ˉ i s i − y i − y ˉ i s i ) 2 d(x,y) \sqrt{\sum_{i1}^{n}\left(\frac{x_i-\bar{x}_i}{s_i}-\frac{y_i-\bar{y}_i}{s_i}\right)^2} d(x,y)i1∑n​(si​xi​−xˉi​​−si​yi​−yˉ​i​​)2 ​ 其中 x ˉ i \bar{x}_i xˉi​ 和 y ˉ i \bar{y}_i yˉ​i​ 分别表示向量 x x x 和 y y y 在第 i i i 个维度上的均值 s i s_i si​ 表示向量在第 i i i 个维度上的标准差。 标准化欧氏距离的优点是可以消除由于不同特征量纲和取值范围带来的影响使得各个特征在距离度量中起到相同的作用。此外标准化欧氏距离还可以减小异常值的影响。 在机器学习和数据挖掘领域标准化欧氏距离常常被用于聚类、分类和异常检测等任务中特别是在需要处理多个具有不同量纲和取值范围的特征时标准化欧氏距离能够提高模型的鲁棒性和泛化能力。 举例 X[[1, 1], [2, 2], [3, 3], [4, 4]];假设两个分量的标准差分别为0.5和1经计算得d 2.2361 4.4721 6.7082 2.2361 4.4721 2.23613.3.2 余弦距离Cosine Distance 几何中夹角余弦可用来衡量两个向量方向的差异机器学习中借用这一概念来衡量样本向量之间的差异。余弦距离是一种用于度量两个向量之间相似性的距离度量方式。其定义为两个向量之间的夹角的余弦值即 d ( x , y ) 1 − x ⋅ y ∥ x ∥ ∥ y ∥ d(x,y) 1 - \frac{ x \cdot y }{ \|x\| \|y\| } d(x,y)1−∥x∥∥y∥x⋅y​ 其中 x x x 和 y y y 分别表示两个向量 ⋅ \cdot ⋅ 表示向量的内积运算 ∥ x ∥ \|x\| ∥x∥ 和 ∥ y ∥ \|y\| ∥y∥ 分别表示两个向量的模长。余弦距离的取值范围在0到1之间 当两个向量方向相同时余弦距离等于1当两个向量方向完全相反时余弦距离等于0当两个向量之间不存在线性关系时余弦距离接近于0。 在机器学习领域余弦距离常被用于文本分类、推荐系统和图像处理等任务中特别是在需要考虑向量之间的方向而不仅仅是大小时余弦距离能够提供更好的距离度量方式。 举例 X[[1, 1], [1, 2], [2, 5], [1, -4]]经计算得d 0.9487 8.9191 -0.5145 0.9965 -0.7593 -0.81073.3.3 汉明距离Hamming Distance 汉明距离是衡量两个等长字符串在相同位置上不同字符的个数即通过对比这两个字符串对应位置上的字符是否相同来计算它们之间的“距离”。 设有两个长度为 n n n 的字符串 A A A 和 B B B则它们的汉明距离 H D ( A , B ) HD(A, B) HD(A,B) 定义为将 A A A 转换成 B B B 所需的最小替换次数。也就是说需要将 A A A 中的某些字符替换成另外的字符才能得到 B B B而替换的次数就是它们的汉明距离。 计算公式如下 D H ( A , B ) ∑ i 1 n ( A [ i ] ≠ B [ i ] ) D_H(A, B) \sum_{i1}^n (A[i] \neq B[i]) DH​(A,B)i1∑n​(A[i]B[i]) 其中 A [ i ] A[i] A[i] 表示 A A A 中第 i i i 个字符 B [ i ] B[i] B[i] 表示 B B B 中第 i i i 个字符。符号 ≠ \neq  代表不等于。该公式表示将 A A A 和 B B B 每个位置上的字符逐一比较若不同则累加1。 举个例子假设有两个字符串A101110和B“100101”它们的汉明距离为3因为A[2]、A[4]和A[5]三个字符需要被替换成0才能得到B。 The Hamming distance between 1011101 and 1081881 is 2. The Hamming distance between 2143896 and 2233796is 3. The Hamming distance between toned and roses is 3.“1011101” 和 1081881的汉明距离是2是因为它们在二进制下只有两个位置上的数字不同。 具体来说在这两个字符串中第3个和第7个字符不同。对应到二进制位上1011101中第3个字符是1而1081881中是0“1011101中第7个字符是0而1081881中是8转换成二进制后是1000”。 因此这两个字符串的汉明距离是2即它们只需要进行2次单个字符的修改例如替换、插入、删除等操作就可以互相转换。 汉明距离是用于比较两个等长字符串之间的差异程度的度量方式通常被应用在以下场景中 错误校验与纠错码 汉明距离可以用来检测并纠正传输或存储过程中的数据错误。例如在网络传输中发送方将信息编码成特定的纠错码接收方通过计算汉明距离进行错误检测和自动纠错。 基因组学在基因序列比对中汉明距离被广泛应用于比较不同物种之间的基因组序列。这有助于了解生物进化和变异的原因以及疾病的相关性。 数据库索引在数据库中可以使用汉明距离作为索引键来实现模糊搜索。例如可以使用哈希函数计算所有文本字符串的汉明距离并将其用作索引键从而实现更快的模糊查询。 图像处理在图像处理中汉明距离可以用于比较不同图片之间的相似度。例如可以将图像分割成多个区域并计算每个区域内像素值的汉明距离从而确定两张图片之间的相似度。 机器学习在机器学习中汉明距离可以用于计算特征向量之间的相似性或差异性从而确定不同数据点之间的分类或聚类关系。 3.3.4 杰卡德距离Jaccard Distance 杰卡德距离Jaccard distance是衡量两个集合之间差异性的一种度量方法它定义为两个集合中不同元素的比例。 如果两个集合完全相同则杰卡德距离为0如果两个集合没有共同元素则杰卡德距离为1。 假设有两个集合 A A A 和 B B B它们的交集大小为 ∣ A ∩ B ∣ |A\cap B| ∣A∩B∣并集大小为 ∣ A ∪ B ∣ |A \cup B| ∣A∪B∣则它们的杰卡德距离可以表示为 d J ( A , B ) 1 − ∣ A ∩ B ∣ ∣ A ∪ B ∣ d_{J}(A,B) 1 - \frac{|A\cap B|}{|A\cup B|} dJ​(A,B)1−∣A∪B∣∣A∩B∣​ 其中 ∣ ⋅ ∣ |\cdot| ∣⋅∣表示集合的元素个数。 举例 X[[1, 1, 0], [1, -1, 0], [-1, 1, 0]]经计算得注以下计算中把杰卡德距离定义为不同的维度的个数占“非全零维度”的比例:d 0.5000 0.5000 1.00003.3.5 马氏距离Mahalanobis Distance 马氏距离Mahalanobis distance是一种常用的度量两个样本点之间距离的方法它考虑了不同特征之间的相关性。该距离度量方法通常用于聚类、分类和异常检测等机器学习任务中。 马氏距离可以看作是欧几里得距离的一种推广它在计算时除了考虑各个特征之间的差异还考虑了各个特征之间的相关性。具体来说对于两个样本点 x x x 和 y y y它们之间的 Mahalanobis 距离 D M ( x , y ) D_M(x,y) DM​(x,y) 可以通过以下公式进行计算 D M ( x , y ) ( x − y ) T S − 1 ( x − y ) D_M(x,y) \sqrt{(x-y)^T S^{-1} (x-y)} DM​(x,y)(x−y)TS−1(x−y) ​ 其中 S S S 为协方差矩阵。当样本集合的协方差矩阵 S S S 已知时可以利用上述公式计算任意两个样本点之间的马氏距离。需要注意的是当协方差矩阵是单位矩阵时马氏距离退化为欧几里得距离。 3.4 “连续属性”和“离散属性”的距离计算 我们常将属性划分为“连续属性”(continuous attribute)和“离散属性” (categorical attribute)前者在定义域上有无穷多个可能的取值后者在定义域上是有限个取值。 若属性值之间存在序关系则可以将其转化为连续值。例如身高属性“高”“中等”“矮”可转化为 { 1 , 0.5 , 0 } \{1, 0.5, 0\} {1,0.5,0}。 闵可夫斯基距离可以用于有序属性。 若属性值之间不存在序关系则通常将其转化为向量的形式例如性别属性“男”“女”可转化为 { ( 1 , 0 ) , ( 0 , 1 ) } \{(1, 0), (0, 1)\} {(1,0),(0,1)}。 在距离中序关系通常指的是点之间的大小或者称为“比较”关系。具体来说在欧几里得空间中两个点之间的距离是由它们在空间中的位置所决定的。因此我们可以比较两个点的距离即确定哪一个点更接近另一个点。 在序关系中有三种可能的情况等于、小于和大于。如果两个点之间的距离相同则它们之间的序关系是等于。如果一个点比另一个点距离更近则它们之间的序关系是小于。反之如果一个点比另一个点距离更远则它们之间的序关系是大于。 需要注意的是序关系只能应用于可比较的对象。在距离中任意两个点都是可比较的因为它们之间的距离可以被确定。 小结 距离公式的基本性质 非负性统一性对称性直递性 常见距离公式 欧式距离(Euclidean Distance)通过距离平方值进行计算曼哈顿距离(Manhattan Distance)通过距离的绝对值进行计算切比雪夫距离(Chebyshev Distance)维度的最大值进行计算闵可夫斯基距离(Minkowski Distance) 当 p 1 p1 p1 时就是曼哈顿距离当 p 2 p2 p2 时就是欧氏距离当 p → ∞ p\to \infty p→∞ 时就是切比雪夫距离 属性 连续属性离散属性 存在序关系可以将其转化为连续值不存在序关系通常将其转化为向量的形式 4. K值的选择 学习目标 知道KNN中K值大小选择对模型的影响 4.1 K值选择说明 之前说到过这个表当时选择的K是5。 K 5 K5 K5 意味着我们需要选取距离最近的5部电影作为参考然后选择数量最多的类别。 如果我们将K设置为6此时结果如下表 此时我们发现爱情片和喜剧片的数量都是3数量是相等的那么《唐人街探案》属于爱情片还是喜剧片呢此时模型也不知道了 —— K值选择过大面临的问题 假设我们将K值设置为1那么直接将距离最近的《美人鱼》所属的喜剧片作为《唐人街探案》的电影类型即可。但是这样就太单一了过分地依赖一个数据了结果并不可靠。假如《美人鱼》这部电影的类型在人工统计的时候错了那么此时《唐人街探案》的电影类型也会跟着错抗风险能力太弱了 —— K值选择过小面临的问题 K值过小容易受到异常点的影响K值过大受到样本均衡的问题 关于K值选择问题李航博士的一书《统计学习方法》上所说 选择较小的K值就相当于用较小的领域中的训练实例进行预测“学习”近似误差会减小只有与输入实例较近或相似的训练实例才会对预测结果起作用与此同时带来的问题是“学习”的估计误差会增大。换句话说K值的减小就意味着整体模型变得复杂容易发生过拟合。选择较大的K值就相当于用较大领域中的训练实例进行预测其优点是可以减少学习的估计误差但缺点是学习的近似误差会增大。这时候与输入实例较远不相似的训练实例也会对预测器起作用使预测发生错误且K值的增大就意味着整体的模型变得简单。 K N KN KN ( N N N 为训练样本个数)则完全不可靠。因为此时无论输入实例是什么都只是简单的预测它属于在训练实例中最多的类模型过于简单忽略了训练实例中大量有用信息。 在实际应用中K值一般取一个比较小的数值例如采用交叉验证法简单来说就是把训练数据在分成两组训练集和验证集来选择最优的K值。 4.2 近似误差和估计误差 近似误差 对现有训练集的训练误差主要关注训练集如果近似误差过小可能会出现过拟合的现象。虽然对现有的训练集能有很好的预测效果但是对未知的测试样本将会出现较大偏差的预测。模型本身不是最接近最佳模型。 估计误差 可以理解为对测试集的测试误差主要关注测试集估计误差小说明对未知数据的预测能力好模型本身最接近最佳模型 近似误差训练集Loss估计误差测试集Loss。 测试集Loss低才是好模型说明模型的泛化能力出色训练集Loss低只能说明模型对数据集拟合得较好但不能说明它的泛化能力。 小结 KNN中K值大小选择对模型的影响【知道】 K值过小 容易受到异常点的影响容易过拟合 K值过大 受到样本均衡的问题容易欠拟合 5. kd树kd Tree 学习目标 知道kd树构建和搜索过程 问题导入实现K近邻算法时主要考虑的问题是如何对训练数据进行快速K近邻搜索。这在特征空间的维数大及训练数据容量大时尤其必要。 K近邻法最简单的实现是线性扫描穷举搜索即计算输入实例与每一个训练实例的距离并存储好之后再查找K近邻。当训练集很大时计算非常耗时。 为了提高KNN搜索的效率可以考虑使用特殊的结构存储训练数据以减小计算距离的次数。 5.1 kd树简介 5.1.1 什么是kd树 根据KNN每次需要预测一个点时我们都需要计算训练数据集里每个点到这个点的距离然后选出距离最近的k个点进行投票。当数据集很大时这个计算成本非常高。 kd树为了避免每次都重新计算一遍距离算法会把距离信息保存在一棵树里这样在计算之前从树里查询距离信息尽量避免重新计算。其基本原理是如果A和B距离很远B和C距离很近那么A和C的距离也很远。有了这个信息就可以在合适的时候跳过距离远的点。 这样优化后的算法复杂度可降低到 O ( D × N log ⁡ N ) O(\rm{D\times} N \log^N) O(D×NlogN)。 K近邻搜索如果使用线性扫描穷举搜索时的算法复杂度为 O ( D × N 2 ) O(D\times N^2) O(D×N2) kd树的英文全称是K-dimensional TreeK-dimensional Tree。 5.1.2 kd树的原理 黄色的点作为根节点小于root的在左边大于root的在右边接下来再不断地划分。分割的那条线叫做分割超平面(splitting hyperplane) 在一维中是一个点二维中是线三维的是面。 黄色节点就是Root节点下一层是红色再下一层是绿色再下一层是蓝色。 要想实现划分和搜索分为两个过程 树的建立最近邻域搜索Nearest-Neighbor Lookup kd树(K-dimension tree)是一种对k维空间中的实例点进行存储以便对其进行快速检索的树形数据结构。kd树是一种二叉树表示对k维空间的一个划分构造kd树相当于不断地用垂直于坐标轴的超平面将K维空间切分构成一系列的K维超矩形区域。kd树的每个结点对应于一个k维超矩形区域。利用kd树可以省去对大部分数据点的搜索从而减少搜索的计算量。 类比“二分查找”给出一组数据[9 1 4 7 2 5 0 3 8]要查找8。 如果挨个查找线性扫描那么将会把数据集都遍历一遍而如果排一下序那数据集就变成了︰[0 1 2 3 4 5 6 7 8 9]按前一种方式我们进行了很多没有必要的查找。 现在如果我们以5为分界点那么数据集就被划分为了左右两个“簇(Cluster)”[0 1 2 3 4]和[6 7 8 9]。 因此根本就没有必要进入第一个簇可以直接进入第二个簇进行查找。把二分查找中的数据点换成k维数据点这样的划分就变成了用超平面对k维空间的划分。空间划分就是对数据点进行分类“挨得近”的数据点就在一个空间里面。 二叉树中簇的英文是Cluster它的含义是簇是一种特殊的树形数据结构它由若干个二叉树组成每个二叉树都满足以下条件 它的左子树的所有节点的值都小于它的根节点的值它的右子树的所有节点的值都大于它的根节点的值左右子树也分别是二叉树。 在二叉树中簇的作用是将相似的节点放在同一个簇中以便更高效地查找、插入和删除节点。这样做可以减少树的高度从而提高查找、插入和删除操作的效率。 例如在一个公司的员工档案系统中可以将员工按照他们的工资、工作年限等因素分成不同的簇然后使用搜索引擎等工具来快速查找、浏览和更新这些员工的信息。 二叉树中簇还可以用于构建广度优先搜索BFS算法。在BFS算法中我们从根节点开始遍历整个树每次选择一个起始节点然后遍历它的所有邻居节点并将它们加入到一个队列中。当我们遍历完整个树时我们将队列中的所有节点依次出队即可得到从根节点到达该节点的路径。这个过程可以用图形化的方式表示为一个树形结构其中节点的度数表示其与其父节点的关系节点的高度表示它所在的簇的深度。 5.2 kd树的构造方法 构造根结点使根结点对应于k维空间中包含所有实例点的超矩形区域。通过递归的方法不断地对k维空间进行切分生成子结点。在超矩形区域上选择一个坐标轴和在此坐标轴上的一个切分点确定一个超平面这个超平面通过选定的切分点并垂直于选定的坐标轴将当前超矩形区域切分为左右两个子区域子结点这时实例被分到两个子区域。上述过程直到子区域内没有实例时终止终止时的结点为叶结点。在此过程中将实例保存在相应的结点上。通常循环的选择坐标轴对空间切分选择训练实例点在坐标轴上的中位数为切分点这样得到的kd树是平衡的平衡二叉树它是一棵空树或其左子树和右子树的深度之差的绝对值不超过1且它的左子树和右子树都是平衡二叉树。 kd树中每个节点是一个向量和二叉树按照数的大小划分不同的是kd树每层需要选定向量中的某一维然后根据这一维按左小右大的方式划分数据。在构建kd树时关键需要解决两个问题 选择向量的哪一维进行划分如何划分数据 第一个问题简单的解决方法可以是随机选择某一维或按顺序选择但是更好的方法应该是在数据比较分散的那一维进行划分分散的程度可以根据方差来衡量。 第二个问题中好的划分方法可以使构建的树比较平衡可以每次选择中位数来进行划分。 5.3 kd树的练习案例 5.3.1 树的建立 给定一个二维空间数据集T{(2, 3), (5, 4), (9, 6), (4, 7), (8, 1), (7, 2)构造一个平衡kd树。 第一维度x轴2, 5, 9, 4, 8, 7 排序2, 4, 5, 7, 8, 9 中位数6 【选择根结点】所以选择 x 5 x5 x5 或 x 7 x7 x7 都可以这里选取 x 7 x7 x7 作为root即 ( 7 , 2 ) (7, 2) (7,2) 为root根节点。【通过递归的方法不断地对k维空间进行切分生成子结点】既然root已经指定那么就可以将其他节点放在root的左右即左小右大 —— x 2 , 4 , 5 x2, 4, 5 x2,4,5 在root的左边 x 8 , 9 x8, 9 x8,9 在root的右边。 对 x 2 , 4 , 5 x2, 4, 5 x2,4,5 再进行划分此时不再使用x轴而使用y轴进行划分。 x 2 , 4 , 5 x2, 4, 5 x2,4,5 对应的数据y轴数据是 y 3 , 4 , 7 y 3, 4, 7 y3,4,7。 中位数为4将4作为rootroot确定左小右大所以 ( 2 , 3 ) (2, 3) (2,3) 放在左边 ( 4 , 7 ) (4, 7) (4,7) 放在右边。 对 x 8 , 9 x8, 9 x8,9 再进行划分此时不再使用x轴而使用y轴进行划分。 x 8 , 9 x8, 9 x8,9 对应的数据y轴数据是 y 1 , 6 y 1, 6 y1,6。 因为只有两个数所以中位数选择哪个都可以这里选择 x 6 x6 x6 作为root只剩下一个数据了且y轴数据比root小所以放在左边 因为要垂直划分所以对于二维平面先x轴再y轴再x轴再y轴以此类推。 思路引导 根结点对应包含数据集 T T T的矩形选择 x ( 1 ) x^{(1)} x(1)轴6个数据点的 x ( 1 ) x^{(1)} x(1)坐标中位数是6这里选最接近的 ( 7 , 2 ) (7,2) (7,2)点以平面 x ( 1 ) 7 x^{(1)}7 x(1)7将空间分为左、右两个子矩形子结点接着左矩形以 x ( 2 ) 4 x^{(2)}4 x(2)4分为两个子矩形左矩形中{(2, 3), (5, 4), (4, 7)}点的 x ( 2 ) x^{(2)} x(2)坐标中位数正好为4右矩形以 x ( 2 ) 6 x^{(2)}6 x(2)6分为两个子矩形如此递归最后得到如下图所示的特征空间划分和kd树。 5.3.2 最近邻域的搜索 假设标记为星星的点是test point ⭐️绿色的点是找到的近似点。在回溯过程中需要用到一个队列存储需要回溯的点。在判断其他子节点空间中是否有可能有距离查询点更近的数据点时做法是以查询点为圆心以当前的最近距离为半径画圆这个圆称为候选超球(candidate hypersphere)如果圆与回溯点的轴相交则需要将轴另一边的节点都放到回溯队列里面来。 样本集{(2, 3), (5, 4), (9, 6), (4, 7), (8, 1), (7, 2) 一、查找点为(2.1, 3.1) Step.1 构造队列 从根结点开始划分。在当初构建树的时候root是根据x轴划分出来的即 x ( 1 ) x^{(1)} x(1)为x轴 x ( 2 ) x^{(2)} x(2)为y轴。当初树是怎么建立而来的那么在构造队列的时候也遵循当时的规则。 ( 2.1 , 3.1 ) (2.1, 3.1) (2.1,3.1) 与root在x轴对比在root的左边。 ( 2.1 , 3.1 ) (2.1, 3.1) (2.1,3.1) 与 ( 5 , 4 ) (5, 4) (5,4) 在y轴对比在 ( 5 , 4 ) (5, 4) (5,4) 的左边。此时已经到了最后一层因此停止。此时最近的点是 ( 2 , 3 ) (2, 3) (2,3)。 Step.2 回溯搜索 走完上面的过程就得到一个队列 (7, 2), (5, 4), (2, 3)。找到该队列后我们就需要回溯目的是找最近点。 从队列中取出 ( 2 , 3 ) (2,3) (2,3) 作为当前最佳结点nearest此时 ( 2.1 , 3.1 ) (2.1, 3.1) (2.1,3.1) 与 ( 2 , 3 ) (2,3) (2,3) 的欧式距离为0.141。然后回溯至 ( 5 , 4 ) (5,4) (5,4)。又因为以 ( 2.1 , 3.1 ) (2.1, 3.1) (2.1,3.1) 为圆心dist0.141为半径画一个圆并不和超平面 y 4 y4 y4 相交如上图所以不必跳到结点 ( 5 , 4 ) (5, 4) (5,4) 的右子空间去搜索因为右子空间中不可能有更近样本点了。再回溯至 ( 7 , 2 ) (7,2) (7,2)。同理以 ( 2.1 , 3.1 ) (2.1,3.1) (2.1,3.1) 为圆心dist0.141为半径画一个圆并不和超平面 x 7 x7 x7 相交所以也不用跳到结点 ( 7 , 2 ) (7,2) (7,2) 的右子空间去搜索。至此, search_path队列为空结束整个搜索返回nearest(2,3)作为 ( 2.1 , 3.1 ) (2.1, 3.1) (2.1,3.1) 的最近邻点最近距离为0.141。 二、查找点为(2, 4.5) Step.1 构造队列 在 ( 7 , 2 ) (7, 2) (7,2) 处测试到达 ( 5 , 4 ) (5, 4) (5,4)在 ( 5 , 4 ) (5, 4) (5,4) 处测试到达 ( 4 , 7 ) (4, 7) (4,7)【优先选择在本域搜索】然后search_path中的结点为 (7, 2), (5, 4), (4, 7)从search_path中取出 ( 4 , 7 ) (4,7) (4,7) 作为当前最佳结点nearest, dist为3.202。 Step.2 回溯搜索 回溯至 ( 5 , 4 ) (5, 4) (5,4)。以 ( 2 , 4.5 ) (2, 4.5) (2,4.5) 为圆心dist3.202为半径画一个圆与超平面 y 4 y4 y4 相交所以需要跳到 ( 5 , 4 ) (5, 4) (5,4) 的左子空间去搜索。所以要将 ( 2 , 3 ) (2, 3) (2,3) 加入到search_path中现在search_path中的结点为 (7, 2), (2, 3)另外 ( 5 , 4 ) (5, 4) (5,4) 与 ( 2 , 4.5 ) (2, 4.5) (2,4.5) 的距离为3.04 dist 3.202所以将 ( 5 , 4 ) (5, 4) (5,4) 赋给nearest并且dist3.04。回溯至 ( 2 , 3 ) (2, 3) (2,3)。 ( 2 , 3 ) (2, 3) (2,3) 是叶子节点直接判断 ( 2 , 3 ) (2, 3) (2,3) 是否离 ( 2 , 4.5 ) (2, 4.5) (2,4.5) 更近计算得到距离为1.5所以nearest更新为 ( 2 , 3 ) (2, 3) (2,3)dist更新为1.5。回溯至 ( 7 , 2 ) (7, 2) (7,2)。同理以 ( 2 , 4.5 ) (2, 4.5) (2,4.5) 为圆心dist1.5为半径画一个圆并不和超平面 x 7 x7 x7 相交所以不用跳到结点 ( 7 , 2 ) (7, 2) (7,2) 的右子空间去搜索。至此search_path为空结束整个搜索返回nearest(2, 3)作为 ( 2 , 4.5 ) (2, 4.5) (2,4.5)的最近邻点最近距离为1.5。 总结 kd树的构建过程【知道】 构造根节点通过递归的方法不断地对k维空间进行切分生成子节点重复第二步骤直到子区域中没有示例时终止需要关注细节 选择向量的哪一维进行划分如何划分数据 kd树的搜索过程【知道】 二叉树搜索比较待查询节点和分裂节点的分裂维的值小于等于就进入左子树分支大于就进入右子树分支直到叶子结点顺着“搜索路径”找到最近邻的近似点回溯搜索路径并判断搜索路径上的结点的其他子结点空间中是否可能有距离查询点更近的数据点。如果有可能则需要跳到其他子结点空间中去搜索重复这个过程直到搜索路径为空 6. 练习案例鸢尾花种类预测 学习目标 知道sklearn中获取数据集的方法知道sklearn中对数据集的划分方法 本实验介绍了使用Python进行机器学习的一些基本概念。在本案例中将使用K-NearestNeighbor (KNN)算法对鸢尾花的种类进行分类并测量花的特征。 本案例目的 遵循并理解完整的机器学习过程对机器学习原理和相关术语有基本的了解了解评估机器学习模型的基本过程 6.1 鸢尾花数据集介绍 Iris数据集是常用的分类实验数据集由Fisher于1936收集整理。Iris也称鸢尾花卉数据集是一类多重变量分析的数据集。关于数据集的具体介绍 特征值4个花瓣的长度、花瓣的宽度、花萼的长度、花萼的宽度目标值3个setosa, vericolor, virginica 6.2 scikit-learn中的数据集介绍 一、scikit-learn数据集API介绍 # 获取本地小规模数据集无需下载 sklearn.datasets.load_数据集名称()# 获取大规模数据集需要从网络中下载。参数data_home表示数据集的下载目录默认是~/scikit_learn_data sklearn.datasets.fetch_数据集名称(data_homeNone)二、sklearn小数据集 # 加载并返回鸢尾花数据集 sklearn.datasets.load_iris()名称数量类别3特征4样本总数150每个类别数量50 三、sklearn大数据集 sklearn.datasets.fetch_20newsgroups(data_homeNone, subsettrain)subsettraintestall可选目的是要加载的数据集部分 train加载训练数据test加载测试数据all加载训练测试数据 6.3 sklearn数据集返回值介绍 load和fetch返回的数据类型为datasets.base.Bunch(字典格式)其中包含 data特征数据数组是[n_samples * n_features]的二维numpy.ndarray数组target标签数组是n_samples的一维numpy.ndarray数组DESCR数据描述feature_names特征名。如新闻数据、手写数字。回归数据集则没有该键值对。target_names标签名 from sklearn.datasets import load_iris, fetch_20newsgroups# 获取鸢尾花数据集返回值是一个继承自字典的Bench iris load_iris()# 查看字典的所有键key print(iris.keys())dict_keys([data, target, frame, target_names, DESCR, feature_names, filename, data_module])data这个键值表示鸢尾花数据集中所有样本的特征值(特征矩阵)它是一个二维数组每行代表一个样本每列代表一个特征。target这个键值表示鸢尾花数据集中所有样本的真实标签(目标向量)它是一个一维数组每个元素表示对应样本的类别编号。frame这个键值表示数据集的Pandas DataFrame对象其中包含了data和target以及其他元数据。target_names这个键值表示类别名称它是一个字符串数组每个元素对应一个类别名称。DESCR这个键值表示对数据集的描述包括数据集来源、数据集大小等详细信息。feature_names这个键值表示特征名称它是一个字符串数组每个元素对应一个特征名称。filename这个键值表示数据集文件所在的路径和文件名。data_module这是一个自定义键值表示数据集模块的版本信息。 这个包含多个键值的字典提供了数据集的各种元数据信息使得我们能够更好地理解和使用该数据集。 6.4 查看鸢尾花数据集的数据分布 通过创建一些图以形象地查看不同类别是如何通过特征来区分的。在理想情况下标签类将由一个或多个特征对完美分隔。在现实世界中这种理想情况很少会发生。 sns.lmplot(dataNone, xNone, yNone, hueNone, colNone, rowNone, fit_regTrue)是一个非常有用的方法它会在绘制二维散点图时自动完成回归拟合。其中 data是关联到的数据集xy分别代表横纵坐标的列名hue代表按照target即花的类别分类显示fit_regTrue是否进行线性拟合 import seaborn as sns import matplotlib.pyplot as plt import pandas as pd from sklearn.datasets import load_iris from matplotlib.font_manager import FontProperties import matplotlib myfont FontProperties(fnamerC:\Windows\Fonts\simsun.ttc, size14) matplotlib.rcParams[font.sans-serif] [SimSun] matplotlib.rcParams[font.family] sans-serif matplotlib.rcParams[axes.unicode_minus] False# 画图函数 def plot_iris(iris, col1, col2):sns.lmplot()是Seaborn库中的一个函数用于绘制数据集中两个变量之间关系的回归图。它可以创建一个带有线性回归拟合的散点图并且可以通过hue、col和row参数在多个类别之间进行分面。sns.lmplot(xcol1, ycol2, datairis, huetarget, fit_regFalse)plt.xlabel(col1, fontpropertiesmyfont, size12)plt.ylabel(col2, fontpropertiesmyfont, size12)plt.title(label鸢尾花种类分布图, fontpropertiesmyfont, size18)plt.show()if __name__ __main__:# 直接在加载的时候让其变为DF格式iris load_iris(as_frameTrue)[frame]print(iris)sepal length (cm) sepal width (cm) petal length (cm) petal width (cm) target0 5.1 3.5 1.4 0.2 01 4.9 3.0 1.4 0.2 02 4.7 3.2 1.3 0.2 03 4.6 3.1 1.5 0.2 04 5.0 3.6 1.4 0.2 0.. ... ... ... ... ...145 6.7 3.0 5.2 2.3 2146 6.3 2.5 5.0 1.9 2147 6.5 3.0 5.2 2.0 2148 6.2 3.4 5.4 2.3 2149 5.9 3.0 5.1 1.8 2[150 rows x 5 columns]print(iris.keys()) # Index([sepal length (cm), sepal width (cm), petal length (cm), petal width (cm), target], dtypeobject)# 调用画图函数绘图plot_iris(irisiris, col1petal width (cm), col2sepal length (cm))6.5 数据集的划分 机器学习一般的数据集会划分为两个部分 训练数据用于训练调整模型测试数据在模型检验时使用用于评估模型是否有效 划分比例 训练集 70 % 70\% 70% 80 % 80\% 80% 75 % 75\% 75%测试集 30 % 30\% 30% 20 % 20\% 20% 25 % 25\% 25% 数据集划分api sklearn.model_selection.train_test_split是scikit-learn库中的一个函数用于将数组或矩阵拆分为随机的训练和测试子集。它是一个快速实用的工具可以将输入验证、下一个ShuffleSplit().split(X, y)和应用于输入数据的拆分以及可选的子采样数据封装到一个调用中以便一次性拆分数据。 sklearn.model_selection.train_test_split(*arrays, test_sizeNone, train_sizeNone, random_stateNone, shuffleTrue, stratifyNone)- x_train, x_test, y_train, y_test该函数的主要参数包括 *arrays: 序列允许长度大于等于2的元组。需要拆分的数组。这里的形参应该是X和y即 XNone表示特征数据yNone表示目标数据 test_size: 浮点数、整数或None默认为None。 如果为浮点数则应在0.0和1.0之间并表示要包含在测试拆分中的数据比例。如果为整数则表示测试样本的绝对数量。如果为None则将其设置为0.25。 train_size: 浮点数、整数或None默认为None。 如果为浮点数则应在0.0和1.0之间并表示要包含在训练拆分中的数据比例。如果为整数则表示训练样本的绝对数量。如果为None则将其自动设置为n_samples - test_size。 random_state: int或RandomState实例或None默认为None。即 随机数种子不同的种子会造成不同的随机采样结果。相同的种子采样结果相同。shuffle: 布尔值默认为True。是否在拆分之前打乱数据。stratify: 数组或None默认为None。如果不是None则数据按照指定类别进行分层抽样。 返回值是拆分的训练和测试数据。返回的数据类型与输入数据类型相同。例如如果你传递了两个数组X和y作为输入数据则该函数将返回四个数组X_train、X_test、y_train和y_test。其中 X_train和y_train是拆分后的训练数据X_test和y_test是拆分后的测试数据 from sklearn.datasets import load_iris from sklearn.model_selection import train_test_split import numpy as np# 1. 获取鸢尾花数据集 iris load_iris()# 2. 对鸢尾花数据集进行分割 x_train, x_test, y_train, y_test train_test_split(iris.data, iris.target,test_size0.20, # 写一个就行另一个会自动算出来shuffleTrue) print(fx_train: {x_train.shape}) # (120, 4) print(fx_test: {x_test.shape}) # (30, 4) print(fy_train: {y_train.shape}) # (120,) print(fy_test: {y_test.shape}) # (30,)# 3. 测试一下随机种子对划分的影响 x_train_1, x_test_1, y_train_1, y_test_1 train_test_split(iris.data, iris.target,random_state1) x_train_2, x_test_2, y_train_2, y_test_2 train_test_split(iris.data, iris.target,random_state2) x_train_3, x_test_3, y_train_3, y_test_3 train_test_split(iris.data, iris.target,random_state2) print(如果随机种子不相同, np.all(x_train_1 x_train_2)) # False print(如果随机种子相同, np.all(x_train_2 x_train_3)) # True小结 获取数据集【知道】 小数据sklearn.datasets.load_*大数据集sklearn.datasets.fetch_* 数据集返回值介绍【知道】 返回值类型是bunch —— 是一个字典类型。返回值的属性 data特征数据数组target标签目标数组DESCR数据描述feature_names特征名target_names标签目标值名 数据集的划分【掌握】 sklearn.model_selection.train_test_split(arrays, options)参数 x特征值y目标值test_size测试集大小ramdom_state随机数种子 返回值x_train, x_test, y_train, y_test 7. 特征工程之特征预处理 学习目标 了解什么是特征预处理知道归一化和标准化的原理及区别 7.1 特征预处理的定义 特征预处理就是对数据进行清洗和整理以便更好地进行机器学习。它包括一些常见的操作如缩放数据以使其处于相同的范围内、删除异常值、将分类变量转换为数值变量等。特征预处理的目的是使数据更容易被机器学习算法理解和使用。它可以帮助提高模型的准确性和性能。 Q为什么我们要进行归一化/标准化 A特征的单位或者大小相差较大或者某特征的方差相比其他的特征要大出几个数量级容易影响支配目标结果使得一些算法无法学习到其它的特征 举例约会对象数据 相亲约会对象数据这个样本是男士的数据有三个特征 玩游戏所消耗时间的百分比每年获得的飞行常客里程数每周消费的冰淇淋公升数 然后有一个所属类别被女士评价的三个类别 不喜欢didntLike魅力一般smallDoses极具魅力largeDoses 对于不同的女士可能对“飞行里程数”更加看重这就导致这个特征对所属类别造成不平衡的影响但是统计的人觉得这三个特征同等重要。 因此我们需要用到一些方法进行无量纲化使不同规格的数据转换到同一规格。 7.2 包含内容数值型数据的无量纲化 归一化标准化 7.3 特征预处理API sklearn.preprocessing7.4 归一化 7.4.1 归一化的定义 归一化是一种常用的数据预处理方法它可以将数据缩放到一个特定的范围内。最常用的归一化方法之一是最小-最大缩放Min-Max Scaling它将数据缩放到 [ 0 , 1 ] [0, 1] [0,1] 的范围内。其公式如下 x n o r m x − x min ⁡ x max ⁡ − x min ⁡ x_{\rm{norm}} \frac{x - x_{\min}}{x_{\max} - x_{\min}} xnorm​xmax​−xmin​x−xmin​​ 其中 x x x表示原始数据 x min ⁡ x_{\min} xmin​和 x max ⁡ x_{\max} xmax​分别表示数据中的最小值和最大值 x n o r m x_{\rm{norm}} xnorm​表示归一化后的数据。 如果你想指定归一化的范围可以使用最小-最大缩放Min-Max Scaling方法并对其公式进行修改。假设你想将数据缩放到[a, b]的范围内那么可以使用以下公式 x n o r m x − x m i n x m a x − x m i n × ( b − a ) a x_{\rm{norm}} \frac{x - x_{min}}{x_{max} - x_{min}} \times (b - a) a xnorm​xmax​−xmin​x−xmin​​×(b−a)a 其中 x x x表示原始数据 x min ⁡ x_{\min} xmin​和 x max ⁡ x_{\max} xmax​分别表示数据中的最小值和最大值 x n o r m x_{\rm{norm}} xnorm​表示归一化后的数据 a a a和 b b b表示你想要将数据缩放到的范围。 例如如果你想将数据缩放到[-1, 1]的范围内那么可以使用以下公式 x n o r m x − x min ⁡ x max ⁡ − x min ⁡ × 2 − 1 x_{\rm{norm}} \frac{x - x_{\min}}{x_{\max} - x_{\min}} \times 2 - 1 xnorm​xmax​−xmin​x−xmin​​×2−1 归一化不一定非要将数据缩放到 [ 0 , 1 ] [0, 1] [0,1] 的范围内。虽然最小-最大缩放Min-Max Scaling是一种常用的归一化方法它将数据缩放到 [ 0 , 1 ] [0, 1] [0,1] 的范围内但也有其他归一化方法它们将数据缩放到不同的范围内。 例如Z分数标准化Z-Score Normalization是一种常用的归一化方法它将数据缩放为均值为0 μ 0 \mu0 μ0标准差为1 σ 1 \sigma1 σ1的分布。这种方法并不会将数据缩放到固定的范围内而是根据数据的分布情况进行缩放。 此外你也可以使用其他归一化方法如Robust Scaling、Quantile Transformation等它们都有各自的优缺点和适用场景。 总之归一化并不是固定将数据缩放到 [ 0 , 1 ] [0, 1] [0,1] 的范围内而是根据实际情况选择合适的归一化方法来进行数据预处理。 7.4.2 归一化的API sklearn.preprocessing.MinMaxScaler()MinMaxScaler.fit_transform() 一、sklearn.preprocessing.MinMaxScaler() sklearn.preprocessing.MinMaxScaler是scikit-learn库中的一个类它提供了最小-最大缩放Min-Max Scaling的实现。 sklearn.preprocessing.MinMaxScaler(feature_range(0, 1), *, copyTrue, clipFalse)该类的主要参数包括 feature_range: 元组默认为(0, 1)。期望的缩放范围。所有特征都将被缩放到这个范围内。copy: 布尔值默认为True。如果为True则对数据进行复制否则进行原地缩放。clip: 布尔值默认为False。如果为True则在转换过程中将数据裁剪到指定范围内。 clip参数用于控制是否在转换过程中将数据裁剪到指定范围内。如果将clip设置为True则在使用transform方法转换数据时所有超出指定范围的值都将被裁剪到范围的边界上。 例如如果你将feature_range设置为(0, 1)并且将clip设置为True则所有小于0的值都将被裁剪为0所有大于1的值都将被裁剪为1。 如果将clip设置为False默认值则不会对数据进行裁剪超出指定范围的值将保持不变。 请注意clip参数仅在使用transform方法转换数据时生效在使用fit方法拟合数据时不会对数据进行裁剪。 二、MinMaxScaler.fit_transform() MinMaxScaler.fit_transform方法用于同时拟合和转换数据。 fit_transform(X, yNone, **fit_params)它接受以下参数 X: 数组形状为(n_samples, n_features)。表示要转换的数据。y: 忽略此参数仅用于与Pipeline API兼容。 fit_transform方法返回一个新的数组其中包含缩放后的数据。返回的数组与输入数组具有相同的形状。 例如如果你传入一个形状为(n_samples, n_features)的数组则该方法将返回一个形状为(n_samples, n_features)的数组。 7.4.3 归一化的数据计算 我们对以下数据进行运算在dating.txt中。保存的就是之前的约会对象数据。 milage Liters Consumtime target 14488 7.153469 1.673904 2 26052 1.441871 0.805124 1 75136 13.147394 0.428964 1 38344 1.669788 0.134296 1 72993 10.14174 1.032955 1 35948 6.830792 1.213192 3 42666 13.276369 0.54388 3 67497 8.631577 0.749278 1 35483 12.273169 1.508053 3分析 实例化MinMaxScalar通过fit_transform转换 我们不需要转换目标值target它是Ground Truth我们千万不要转换不然会破坏标准答案。 import pandas as pd from sklearn.preprocessing import MinMaxScalerdata pd.read_csv(../data/dating.txt, delimiter\t) print(data) milage Liters Consumtime target 0 40920 8.326976 0.953952 3 1 14488 7.153469 1.673904 2 2 26052 1.441871 0.805124 1 3 75136 13.147394 0.428964 1 4 38344 1.669788 0.134296 1 .. ... ... ... ... 995 11145 3.410627 0.631838 2 996 68846 9.974715 0.669787 1 997 26575 10.650102 0.866627 3 998 48111 9.134528 0.728045 3 999 43757 7.882601 1.332446 3[1000 rows x 4 columns] # 1. 实例化一个转换器 transformer MinMaxScaler(feature_range(2, 3), copyTrue)# 2. 调用fit_transform方法 data transformer.fit_transform(Xdata.loc[:, [milage, Liters, Consumtime]]) # 或者data transformer.fit_transform(Xdata[[milage, Liters, Consumtime]]) print(最小值-最大值归一化处理的结果为: \r\n, data)最小值-最大值归一化处理的结果为:[[2.44832535 2.39805139 2.56233353][2.15873259 2.34195467 2.98724416][2.28542943 2.06892523 2.47449629]...[2.29115949 2.50910294 2.51079493][2.52711097 2.43665451 2.4290048 ][2.47940793 2.3768091 2.78571804]]print(data.shape) # (1000, 3)所有的数据都被缩放到了 [ 2 , 3 ] [2, 3] [2,3]之间没有动target。 问题如果数据中异常点较多会有什么影响 回答归一化处理可以将数据转换到一个特定的范围内这样可以减少异常点对模型的影响。但是如果数据中存在异常点那么归一化处理可能会受到影响。 例如最大最小归一化Min-Max Normalization会将数据转换到[0, 1]的范围内但是如果数据中存在异常点那么最大值和最小值可能会不稳定导致归一化结果不稳定。 因此在进行归一化处理之前通常需要先对数据进行清洗去除异常点。 注意最大值最小值是变化的另外最大值与最小值非常容易受异常点影响所以这种方法鲁棒性较差只适合传统精确小数据场景。 为了解决这个问题引入“标准化”。 7.5 标准化 7.5.1 标准化的定义 标准化Standardization是一种数据预处理方法它通过将数据转换为均值为0 μ 0 \mu0 μ0标准差为1 σ 1 \sigma1 σ1的正态分布来消除数据的量纲和尺度差异。标准化的公式为 x ′ x − μ σ x \frac{x - \mu}{\sigma} x′σx−μ​ 其中 x x x表示原始数据 μ \mu μ表示数据的均值 σ \sigma σ表示数据的标准差 x ′ x x′表示标准化后的数据。 标准差为1和方差为1是一回事。 【补充】均值、标准差以及方差的计算公式 均值Mean是一组数据的算术平均值它表示数据的中心位置。均值的计算公式为 μ 1 n ∑ i 1 n x i \mu \frac{1}{n}\sum_{i1}^{n}x_i μn1​i1∑n​xi​ 其中 n n n表示数据的个数 x i x_i xi​表示第 i i i个数据。 方差Variance是用来衡量一组数据的离散程度的统计量。它表示数据与均值之间的平均差异。方差的计算公式为 σ 2 1 n ∑ i 1 n ( x i − μ ) 2 \sigma^2 \frac{1}{n}\sum_{i1}^{n}(x_i - \mu)^2 σ2n1​i1∑n​(xi​−μ)2 其中 n n n表示数据的个数 x i x_i xi​表示第 i i i个数据 μ \mu μ表示数据的均值。 标准差Standard Deviation是方差的平方根它也用来衡量一组数据的离散程度。标准差的计算公式为 σ 1 n ∑ i 1 n ( x i − μ ) 2 \sigma \sqrt{\frac{1}{n}\sum_{i1}^{n}(x_i - \mu)^2} σn1​i1∑n​(xi​−μ)2 ​ 回到刚才异常点的地方我们再来看看标准化 对于归一化来说如果出现异常点影响了最大值和最小值那么结果显然会发生改变对于标准化来说如果出现异常点由于样本具有一定数据量样本数量多少量的异常点对于平均值的影响并不大从而方差改变较小方差和标准差是根据均值计算得到的。 7.5.2 标准化的API sklearn.preprocessing.StandardScaler(copyTrue, with_meanTrue, with_stdTrue)sklearn.preprocessing.StandardScaler是一个类它用来对数据进行标准化处理。它的构造函数接受以下参数 copy布尔值表示是否复制数据默认为True。with_mean布尔值表示是否去除均值默认为True。with_std布尔值表示是否除以标准差默认为True。 该类的主要方法有 fit(X[, y])计算数据的均值和标准差。fit_transform(X[, y])计算数据的均值和标准差并对数据进行标准化处理。transform(X)使用之前计算的均值和标准差对数据进行标准化处理。 这些方法都返回一个二维数组表示标准化后的数据。 7.5.3 标准化的数据计算 同样对上面的数据进行处理 实例化StandardScaler通过fit_transform转换 import pandas as pd from sklearn.preprocessing import StandardScalerdata pd.read_csv(filepath_or_buffer../data/dating.txt, delimiter\t) print(data) milage Liters Consumtime target 0 40920 8.326976 0.953952 3 1 14488 7.153469 1.673904 2 2 26052 1.441871 0.805124 1 3 75136 13.147394 0.428964 1 4 38344 1.669788 0.134296 1 .. ... ... ... ... 995 11145 3.410627 0.631838 2 996 68846 9.974715 0.669787 1 997 26575 10.650102 0.866627 3 998 48111 9.134528 0.728045 3 999 43757 7.882601 1.332446 3[1000 rows x 4 columns] # 1. 实例化一个转换器类 transformer StandardScaler()# 2. 调用fit_transform方法 data transformer.fit_transform(Xdata.loc[:, [milage, Liters, Consumtime]]) print(标准化的结果\r\n, data) print(每一列特征的平均值, transformer.mean_) print(每一列特征的方差, transformer.var_) 标准化的结果[[ 0.33193158 0.41660188 0.24523407][-0.87247784 0.13992897 1.69385734][-0.34554872 -1.20667094 -0.05422437]...[-0.32171752 0.96431572 0.06952649][ 0.65959911 0.60699509 -0.20931587][ 0.46120328 0.31183342 1.00680598]] 每一列特征的平均值 [3.36354210e04 6.55996083e00 8.32072997e-01] 每一列特征的方差 [4.81628039e08 1.79902874e01 2.46999554e-01]在已有样本足够多的情况下比较稳定适合现代嘈杂大数据场景。 小结 什么是特征工程【知道】 定义通过一些转化函数将特征数据转换成更加适合算法模型的特征数据过程。包含内容 归一化标准化 归一化【知道】 定义对原始数据进行变换把数据映射到指定区间默认为 [ 0 , 1 ] [0,1] [0,1]。api sklearn.preprocessing.MinMaxScaler(feature_range(0, 1), *, copyTrue, clipFalse)参数 feature_range: 元组默认为(0, 1)。期望的缩放范围。所有特征都将被缩放到这个范围内。copy: 布尔值默认为True。如果为True则对数据进行复制否则进行原地缩放。clip: 布尔值默认为False。如果为True则在转换过程中将数据裁剪到指定范围内。 总结 鲁棒性比较差容易受到异常点的影响只适合传统精确小数据场景以后不会用你了 标准化【掌握】 定义对原始数据进行变换把数据变换到均值为0标准差为1的范围符合正态分布api sklearn.preprocessing.StandardScaler(copyTrue, with_meanTrue, with_stdTrue)参数 copy布尔值表示是否复制数据默认为True。with_mean布尔值表示是否去除均值默认为True。with_std布尔值表示是否除以标准差默认为True。 总结 异常值对其影响小适合现代嘈杂大数据场景以后就是用你了 归一化Normalization和标准化Standardization都是数据预处理方法它们都可以消除数据的量纲和尺度差异。但是它们并没有绝对的优劣之分它们在不同的情况下都有各自的优点。 归一化通过将数据转换到一个特定的范围内来消除数据的量纲和尺度差异。它适用于数据分布比较均匀且没有异常点的情况。标准化通过将数据转换为均值为0标准差为1的正态分布来消除数据的量纲和尺度差异。它适用于数据分布不均匀且存在异常点的情况。 在实际应用中可以根据数据的特点选择合适的方法。 8. 练习案例鸢尾花种类预测 学习目标 知道KNeighborsClassifier的用法 8.1 再识K-近邻算法API sklearn.neighbors.KNeighborsClassifier(n_neighbors5,weightsuniform,algorithmauto, leaf_size30,p2, metricminkowski,metric_paramsNone, n_jobsNone) - Nonesklearn.neighbors.KNeighborsClassifier() 是一个实现了 k-近邻投票的分类器。它有许多参数包括 n_neighbors默认为5用于 k-近邻查询的邻居数量weights默认为’uniform’用于预测的权重函数algorithm默认为’auto’用于计算最近邻居的算法 brute蛮力搜索也就是线性扫描当训练集很大时计算非常耗时。kd_tree构造kd树存储数据以便对其进行快速检索的树形数据结构kd树也就是数据结构中的二叉树。以中值切分构造的树每个结点是一个超矩形在维数小于20时效率高。ball_tree为了克服kd树高维失效而发明的其构造过程是以质心C和半径r分割样本空间每个节点是一个超球体。 leaf_size默认为30传递给 BallTree 或 KDTree 的叶大小p默认为2Minkowski 度量的幂参数metric默认为’minkowski’用于距离计算的度量等等。 它没有返回值但是它有一些属性如 classes_已知分类器的类标签数组和 effective_metric_使用的距离度量。 8.2 鸢尾花种类预测 8.2.1 步骤分析 获取数据集数据基本处理特征工程 训练集transformer.fit_transform(x_train)测试集transformer.transform(x_test) 千万不要fit_transform 机器学习模型训练模型评估 8.2.2 代码实现 from sklearn.datasets import load_iris from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler from sklearn.neighbors import KNeighborsClassifier# 1. 获取数据集 iris load_iris()# 2. 数据基本处理 x_train, x_test, y_train, y_test train_test_split(iris.data, iris.target, test_size0.2,random_state22)# 3. 特征工程标准化 transformer StandardScaler() x_train transformer.fit_transform(x_train) x_test transformer.transform(x_test) # 测试数据处理时应该使用transform而不是fit_transform# 4. 机器学习模型训练 estimator KNeighborsClassifier(n_neighbors5) estimator.fit(Xx_train, yy_train)# 5. 模型评估 # 方法1对比真实值和预测值 y_predict estimator.predict(Xx_test) print(预测结果为\r\n, y_predict) print(对比真实值和预测值\r\n, y_predict y_test)# 方法2直接计算准确率这里是预测计算分数 score estimator.score(Xx_test, yy_test) print(f准确率为{score * 100:.2f}%)结果 预测结果为[0 2 1 2 1 1 1 1 1 0 2 1 2 2 0 2 1 1 1 1 0 2 0 1 2 0 2 2 2 2] 对比真实值和预测值[ True True True True True True True False True True True TrueTrue True True True True True False True True True True TrueTrue True True True True True] 准确率为93.33%小结 KNeighborsClassifier的使用【知道】 sklearn.neighbors.KNeighborsClassifier(n_neighbors5, algorithmauto) autobrutekd_treeball_tree 9. KNN算法总结 9.1 优点 简单有效因为它基于一种直观的思想如果一个样本在特征空间中的K个最近邻居中的大多数属于某一个类别那么该样本也属于这个类别。这种方法简单易懂且在许多实际应用中都取得了很好的效果。此外KNN算法不需要建立模型只需要存储训练数据即可这也使得它更加简单。重新训练的代价低因为它不需要在训练阶段建立模型。它只是在分类时根据测试样本的特征从训练集中找到最近的K个邻居然后根据这些邻居的类别来决定测试样本的类别。因此当训练集发生变化时KNN算法不需要重新训练模型只需要更新训练集即可。这就使得KNN算法重新训练的代价低。适合类域交叉样本KNN方法主要靠周围有限的邻近的样本而不是靠判别类域的方法来确定所属类别的。因此对于类域的交叉或重叠较多的待分样本集来说KNN方法较其他方法更为适合。例如如果一个样本位于两个类域的交叉区域那么它周围的邻居可能属于不同的类别。KNN算法会根据这些邻居的投票结果来确定该样本的类别从而更好地处理类域交叉的情况。适合大样本自动分类KNN算法适合大样本自动分类因为它能够处理大量的训练数据。当样本容量较大时KNN算法能够更好地捕捉数据的分布特征从而更准确地进行分类。但是当样本容量较小时KNN算法可能会产生误分。这是因为当样本容量较小时邻居的数量也会减少这会影响投票结果的准确性。因此KNN算法比较适用于样本容量比较大的类域的自动分类。 9.2 缺点 惰性学习KNN算法是一种惰性学习方法lazy learning基本上不学习相比一些积极学习的算法要慢很多。因为它不需要在训练阶段建立模型。它只是在分类时根据测试样本的特征从训练集中找到最近的K个邻居然后根据这些邻居的类别来决定测试样本的类别。因此KNN算法不需要在训练阶段进行大量的计算而是将计算推迟到分类阶段。这就使得KNN算法成为一种惰性学习算法。类别评分未规格化KNN算法的类别评分未规格化是指它没有像一些通过概率评分的分类器那样给出每个类别的概率估计。KNN算法只是根据测试样本的K个最近邻居的类别来决定测试样本的类别而没有给出每个类别的概率估计。这就使得KNN算法的类别评分未规格化。输出的可解释性不强KNN算法的输出可解释性不强是指它没有像一些其他算法如决策树那样给出清晰的分类规则。KNN算法只是根据测试样本的K个最近邻居的类别来决定测试样本的类别而没有给出清晰的分类规则。这就使得KNN算法的输出可解释性不强而决策树的输出可解释性就较强。不擅长解决不均衡的样本KNN算法在处理不均衡样本时可能会遇到一些问题。当样本不平衡时训练的模型有可能更偏向于其中样本数量较多的类别。为了解决这个问题我们可以剔除一些数样本也可以生成一些样本让各种类别的样本保持平衡而通过KNN剔除冗余样本的方式也可以得到相对平衡的训练样本。计算量较大KNN算法的计算量较大主要是因为它需要计算输入实例与所有训练数据的距离然后再进行判断。当训练集或特征维度很大时这种计算非常耗时。此外KNN的数据存储量也很大因为每次对一个未标记样本进行分类时都需要全部计算一遍距离。 10. 交叉验证、网格搜索 学习目标 知道交叉验证、网格搜索的概念会使用交叉验证、网格搜索优化训练模型 10.1 什么是交叉验证Cross ValidationCV 交叉验证是一种用来观察模型稳定性的方法。它通过将数据划分为 n n n 份依次使用其中一份作为测试集其他 n − 1 n-1 n−1 份作为训练集多次计算模型的精确性来评估模型的平均准确程度。 交叉验证将拿到的训练数据分为训练和验证集。以下图为例将数据分成4份其中一份作为验证集。然后经过4次组的测试每次都更换不同的验证集。即得到4组模型的结果取平均值作为最终结果。又称4折交叉验证。 10.1.1 分析 我们之前知道数据分为训练集和测试集但是为了让从训练得到模型结果更加准确。做以下处理 训练集 训练集 验证集测试集 测试集 组1234准确率第一组验证集训练集训练集训练集80%第二组训练集验证集训练集训练集78%第三组训练集训练集验证集训练集75%第四组训练集训练集训练集验证集82% 那么模型的准确率测试集准确率为 A c c t r a i n 1 k ∑ k 1 4 a c c k 1 4 ( 80 % 78 % 75 % 82 % ) 78.75 % \begin{aligned} \rm{Acc_{train}} \frac{1}{k}\sum^4_{k1} \rm{acc}_k \\ \frac{1}{4}(80\% 78\% 75\% 82\%) \\ 78.75\% \end{aligned} Acctrain​​k1​k1∑4​acck​41​(80%78%75%82%)78.75%​ Q交叉验证是每次换测试集还是每次换验证集 A交叉验证是每次换测试集。 Q那验证集不用换吗 A在交叉验证中通常不使用验证集。交叉验证的目的是通过多次计算模型的精确性来评估模型的平均准确程度而不是使用验证集来评估模型。在交叉验证中数据被划分为 n n n 份每次使用其中一份作为测试集其他 n − 1 n-1 n−1 份作为训练集。 10.1.2 为什么需要交叉验证 交叉验证目的为了让被评估的模型更加准确可信。 Q交叉验证可以提高准确率吗 A交叉验证可以提高模型的准确率。交叉验证是一种评估机器学习模型性能的方法它将数据集划分为训练集和测试集并多次重复这个过程每次使用不同的子集作为测试集和训练集。通过这样做我们可以更好地评估模型在不同数据集上的表现并减少因数据集选择引起的偏差。交叉验证的主要优点是可以提供更准确的模型评估因为它可以对模型进行更全面的测试包括评估模型的泛化能力。泛化能力是指模型在新数据上的性能而不仅仅是适合于用于拟合训练数据的模型。通过使用交叉验证我们可以更好地评估模型对未见过数据的性能从而提高模型的准确率。总之交叉验证是一种有用的技术可以帮助我们在开发机器学习模型时更准确地了解其性能和泛化能力。 Q交叉验证只是让被评估的模型更加准确可信那么怎么选择或者调优参数呢 A利用网络搜索优化模型参数从而提高模型的准确率。 10.2 什么是网格搜索Grid Search 网格搜索Grid Search是一种调参手段它通过穷举搜索在所有候选的参数选择中通过循环遍历尝试每一种可能性表现最好的参数就是最终的结果。它的原理就像是在数组里找最大值。 例如以有两个参数的模型为例参数a有3种可能参数b有4种可能把所有可能性列出来可以表示成一个3*4的表格其中每个cell就是一个网格循环过程就像是在每个网格里遍历、搜索所以叫grid search。 通常情况下有很多参数是需要手动指定的如k-近邻算法中的K值这种叫超参数。但是手动过程繁杂所以需要对模型预设几种超参数组合。每组超参数都采用交叉验证来进行评估。最后选出最优参数组合建立模型。 在机器学习中需要手动指定的参数都是超参数。 网格搜索的目的是选择最优的超参数。 K值K3K5K7模型模型1模型2模型3 10.3 交叉验证网格搜索模型选择与调优的API sklearn.model_selection.GridSearchCV(estimator, param_grid, scoringNone, n_jobsNone, refitTrue, cvNone, verbose0, pre_dispatch2*n_jobs, error_scorenan, return_train_scoreFalse)作用对估计器的指定参数值进行详尽搜索。 参数 estimator估计器对象。param_grid字典或字典列表用于指定要搜索的参数值。例如param_dict {n_neighbors: [1, 3, 5]}scoring用于评估预测的字符串、可调用对象或无。n_jobs并行运行的作业数。cv确定交叉验证拆分策略的整数、可调用对象或无。cv cross validation 方法 fit在指定参数值范围内对估计器进行穷举搜索。score返回给定测试数据和标签的平均精度。score_samples返回给定测试数据和标签的分数。predict预测给定测试数据的类别。predict_proba预测给定测试数据属于每个类别的概率。decision_function计算给定测试数据的决策函数值。transform在拟合数据上应用转换。inverse_transform撤消先前转换的所有转换。 这些方法是否实现取决于所使用的估计器。 属性结果分析 best_score_在交叉验证期间找到的最佳分数最好的结果。best_estimator_在交叉验证期间找到的最佳估计器最好的参数模型。cv_results_一个字典其中包含交叉验证期间所有试验的结果每次交叉验证后的验证集准确率结果和训练集准确率结果。 10.4 鸢尾花案例增加K值调优 第一步使用GridSearchCV构建估计器 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# 1. 获取数据 iris load_iris()# 2. 数据基本处理划分数据集 x_train, x_test, y_train, y_test train_test_split(iris.data, iris.target, test_size0.2, random_state22)# 3. 特征工程标准化 transformer StandardScaler() x_train transformer.fit_transform(Xx_train) x_test transformer.transform(Xx_test)# 4. KNN预估器流程 ## 4.1 实例化预估器 estimator KNeighborsClassifier()## 4.2 模型选择与调优网格搜索和交叉验证 param_dict {n_neighbors: [1, 3, 5]} # 准备调整的超参数 estimator GridSearchCV(estimatorestimator, param_gridparam_dict, cv3)## 4.3 fit数据进行训练 estimator.fit(Xx_train, yy_train)# 5. 评估模型效果 ## 5.1 方法一比对预测值和真实值 y_predict estimator.predict(x_test) print(比对预测值和真实值\r\n, y_predict y_test)## 5.2 方法二直接计算准确率 score estimator.score(Xx_test, yy_test) print(fKNN准确率为: {score*100:.2f}%)第二步进行评估查看最终选择的结果和交叉验证的结果 print(f在交叉验证中最好的结果是{estimator.best_score_*100:.2f}%) print(最好的参数模型是, estimator.best_estimator_.get_params()) print(每次交叉验证后的准确率为\r\n, estimator.cv_results_)结果 比对预测值和真实值[ True True True True True True True False True True True TrueTrue True True True True True False True True True True TrueTrue True True True True True] KNN准确率为: 93.33% 在交叉验证中最好的结果是97.50% 最好的参数模型是 {algorithm: auto, leaf_size: 30, metric: minkowski, metric_params: None, n_jobs: None, n_neighbors: 5, p: 2, weights: uniform} 每次交叉验证后的准确率为{mean_fit_time: array([0.00033243, 0.00066495, 0.00066503]), std_fit_time: array([0.00047013, 0.00047019, 0.00047025]), mean_score_time: array([0.00199477, 0.00132966, 0.00185378]), std_score_time: array([1.12391596e-07, 4.70190252e-04, 1.99158003e-04]), param_n_neighbors: masked_array(data[1, 3, 5],mask[False, False, False],fill_value?,dtypeobject), params: [{n_neighbors: 1}, {n_neighbors: 3}, {n_neighbors: 5}], split0_test_score: array([1. , 0.975, 1. ]), split1_test_score: array([0.925, 0.975, 0.975]), split2_test_score: array([0.95, 0.9 , 0.95]), mean_test_score: array([0.95833333, 0.95 , 0.975 ]), std_test_score: array([0.03118048, 0.03535534, 0.02041241]), rank_test_score: array([2, 3, 1])}“比对预测值和真实值”显示了模型在测试集上的预测结果与真实结果的比较。 True表示预测正确False表示预测错误。 “KNN准确率为: 93.33%”显示了模型在测试集上的准确率。“在交叉验证中最好的结果是97.50%”显示了在交叉验证过程中最佳超参数组合下的平均准确率。“最好的参数模型是…”显示了最佳超参数组合。“每次交叉验证后的准确率为…”显示了交叉验证过程中每次迭代的详细信息包括每个超参数组合下的平均拟合时间、平均评分时间、测试得分等。 小结 交叉验证【知道】 定义 将拿到的训练数据分为训练集和验证集 k k k折交叉验证 分割方式 训练集训练集 验证集测试集测试集 为什么需要交叉验证为了让被评估的模型更加准确可信 网格搜索【知道】 超参数在sklearn中需要手动指定的参数叫做超参数网格搜索就是把这些超参数的值通过字典的形式传递进去然后进行选择最优值 api【知道】 sklearn.model_selection.GridSearchCV(estimator, param_gridNone,cvNone) estimator选择了哪个训练模型param_grid需要传递的超参数cv几折交叉验证 11. 练习案例预测Facebook签到位置 学习目标 通过Facebook位置预测案例熟练掌握KNN的学习内容。 11.1 项目描述 本次比赛的目的是预测一个人将要签到的地方。为了本次比赛Facebook创建了一个虚拟世界其中包括10公里*10公里共100平方公里约10万个地方。对于给定的坐标集您的任务是根据用户的位置准确性和时间戳等预测用户下一次的签到位置。数据被制作成类似于来自移动设备的位置数据。请注意只能使用提供的数据进行预测。 11.2 数据集介绍 数据集下载地址https://www.kaggle.com/competitions/facebook-v-predicting-check-ins/overview 文件说明train.csv, test.csvrow id签入事件的id x y坐标 accuracy准确度定位精度 time时间戳 place_id签到的位置这也是你需要预测的内容11.3 步骤分析 数据基本处理这里所做的一些处理不一定达到很好的效果我们只是简单尝试有些特征我们可以根据一些特征选择的方式去做处理缩小数据集范围目的是让训练速度变快实际中不需要这么做 —— DataFrame.query()选取有用的时间特征将签到位置少于n个用户的删除分割数据集标准化处理k-近邻预测 具体步骤 # 1. 获取数据集# 2. 基本数据处理 ## 2.1 缩小数据范围 ## 2.2 选择时间特征 ## 2.3 去掉签到较少的地方 ## 2.4 确定特征值和目标值 ## 2.5 分割数据集# 3. 特征工程 —— 特征预处理标准化 ## 3.1 实例化一个转换器 ## 3.2 调用fit_transform和transform# 4. 机器学习 —— KNN CV交叉验证Cross Validation ## 4.1 实例化一个估计器 ## 4.2 调用GridSearchCV ## 4.3 训练模型# 5. 模型评估11.4 代码实现 import pandas as pd from sklearn.model_selection import train_test_split, GridSearchCV from sklearn.preprocessing import StandardScaler from sklearn.neighbors import KNeighborsClassifier# 1. 获取数据集 facebook pd.read_csv(filepath_or_buffer../data/FacebookLocation/train.csv) print(facebook.head()) row_id x y accuracy time place_id 0 0 0.7941 9.0809 54 470702 8523065625 1 1 5.9567 4.7968 13 186555 1757726713 2 2 8.3078 7.0407 74 322648 1137537235 3 3 7.3665 2.5165 65 704587 6567393236 4 4 4.0961 1.1307 31 472130 7440663949 # 2. 基本数据处理## 2.1 缩小数据范围 partial_data facebook.query(x 2.0 x 2.5 y 2.0 y 2.5).copy()## 2.2 选择时间特征 # 使用to_datetime函数将DF中的time列转换为日期时间格式。其中units表示时间单位为秒 time pd.to_datetime(partial_data[time], units) print(time.head())163 1970-01-08 18:02:17 310 1970-01-03 17:11:59 658 1970-01-06 19:32:23 1368 1970-01-04 16:50:22 1627 1970-01-07 21:18:04 Name: time, dtype: datetime64[ns] # 将转换后的日期时间数据存储在一个新的数据框time中 time pd.DataFrame(time)# 从time数据框中提取出日期、小时和星期几的信息并分别存储在facebook_data数据框的新列day、hour和weekday中 # .dt是一个访问器它用于访问时间日期序列的属性和方法。它类似于.str访问器 partial_data.loc[:, day] time[time].dt.day partial_data.loc[:, hour] time[time].dt.hour partial_data.loc[:, weekday] time[time].dt.weekdayprint(partial_data.head()) row_id x y accuracy time place_id day hour weekday 163 163 2.1663 2.3755 84 669737 3869813743 8 18 3 310 310 2.3695 2.2034 3 234719 2636621520 3 17 5 658 658 2.3236 2.1768 66 502343 7877745055 6 19 1 1368 1368 2.2613 2.3392 73 319822 9775192577 4 16 6 1627 1627 2.3331 2.0011 66 595084 6731326909 7 21 2 ## 2.3 去掉签到较少的地方 # 使用groupby和count函数统计facebook_data数据框中每个地点的出现次数并将结果存储在place_count数据框中 place_count partial_data.groupby(byplace_id).count() print(place_count.head()) row_id x y accuracy time day hour weekday place_id 1006234733 1 1 1 1 1 1 1 1 1008823061 4 4 4 4 4 4 4 4 1012580558 3 3 3 3 3 3 3 3 1025585791 21 21 21 21 21 21 21 21 1026507711 220 220 220 220 220 220 220 220 # 筛选出place_count数据框中出现次数大于3的地点 place_count place_count[place_count[row_id] 3] print(place_count[row_id] 3)place_id 1006234733 False 1008823061 True 1012580558 False 1025585791 True 1026507711 TrueName: row_id, Length: 2524, dtype: bool print(place_count.head()) row_id x y accuracy time day hour weekday place_id 1008823061 4 4 4 4 4 4 4 4 1025585791 21 21 21 21 21 21 21 21 1026507711 220 220 220 220 220 220 220 220 1032417180 10 10 10 10 10 10 10 10 1040557418 123 123 123 123 123 123 123 123 # 使用isin函数只保留facebook_data数据框中属于筛选后的地点的数据 partial_data partial_data[partial_data[place_id].isin(place_count.index)] print(place_count.index)Int64Index([1008823061, 1025585791, 1026507711, 1032417180, 1040557418,1067960232, 1068428112, 1068896566, 1104074781, 1113141722,...9929803766, 9934025626, 9944591314, 9951996370, 9953487159,9966115681, 9970566102, 9983648790, 9995108787, 9998968845],dtypeint64, nameplace_id, length929) print(partial_data[place_id].isin(place_count.index))163 True 310 True 658 True 1368 True 1627 TrueName: place_id, Length: 71664, dtype: bool print(partial_data.head()) row_id x y accuracy time place_id day hour weekday 163 163 2.1663 2.3755 84 669737 3869813743 8 18 3 310 310 2.3695 2.2034 3 234719 2636621520 3 17 5 658 658 2.3236 2.1768 66 502343 7877745055 6 19 1 1368 1368 2.2613 2.3392 73 319822 9775192577 4 16 6 1627 1627 2.3331 2.0011 66 595084 6731326909 7 21 2 ## 2.4 确定特征值和目标值 x partial_data[[x, y, accuracy, day, hour, weekday]] # 两个中括号或者使用.loc y partial_data[place_id]## 2.5 分割数据集 x_train, x_test, y_train, y_test train_test_split(x, y, random_state2, test_size0.25)print(x_train.shape) # (51948, 6) print(x_test.shape) # (17316, 6) print(y_train.shape) # (51948,) print(y_test.shape) # (17316,)# 3. 特征工程 —— 特征预处理标准化## 3.1 实例化一个转换器 transformer StandardScaler()## 3.2 调用fit_transform和transform x_train transformer.fit_transform(x_train) x_test transformer.transform(x_test)# 4. 机器学习 —— KNN CV交叉验证Cross Validation## 4.1 实例化一个估计器 estimator KNeighborsClassifier()## 4.2 调用GridSearchCV param_grid {n_neighbors: [3, 5, 7, 9]} estimator GridSearchCV(estimatorestimator, param_gridparam_grid, cv3, n_jobs-1) # 因为cv3即3折交叉验证而超参数n_neighbors有4种所以需要跑12次 # n_jobs是需要调用几个CPU来运行-1表示全部的CPU## 4.3 训练模型 estimator.fit(Xx_train, yy_train)# 5. 模型评估## 5.1 基本评估方式### 5.1.1 方法1 score estimator.score(Xx_test, yy_test) print(f最后预测的准确率为{score*100:.2f}%)### 5.1.2 方法2 y_predict estimator.predict(Xx_test) print(最后的预测值为, y_predict) print(预测值和真实值的对比情况\r\n, y_predict y_test)## 5.2 使用CV交叉验证后的评估方式 print(f在交叉验证中最好的准确率为{estimator.best_score_*100:.2f}%) print(f在交叉验证中最好的模型参数为{estimator.best_estimator_.get_params()}) print(在交叉验证中记录/所有的结果为\r\n, estimator.cv_results_)结果 最后预测的准确率为37.08% 最后的预测值为 [8283681418 8980163153 1247398579 ... 1891783132 8169595806 3661555534] 预测值和真实值的对比情况21112721 False 15305275 False 2286447 False 2683519 False 276963 True... 5377682 False 5778143 True 10652670 True 5835344 True 12327543 False Name: place_id, Length: 17316, dtype: bool 在交叉验证中最好的准确率为33.69% 在交叉验证中最好的模型参数为{algorithm: auto, leaf_size: 30, metric: minkowski, metric_params: None, n_jobs: None, n_neighbors: 7, p: 2, weights: uniform} 在交叉验证中记录/所有的结果为{mean_fit_time: array([0.07546322, 0.06881396, 0.07014338, 0.07014489]), std_fit_time: array([0.00517131, 0.00141153, 0.00169545, 0.00046935]), mean_score_time: array([1.49170359, 1.58113194, 1.68219447, 1.71676771]), std_score_time: array([0.04526898, 0.01525681, 0.01882355, 0.02216745]), param_n_neighbors: masked_array(data[3, 5, 7, 9],mask[False, False, False, False],fill_value?,dtypeobject), params: [{n_neighbors: 3}, {n_neighbors: 5}, {n_neighbors: 7}, {n_neighbors: 9}], split0_test_score: array([0.32802033, 0.33743359, 0.33679834, 0.33136983]), split1_test_score: array([0.33085008, 0.34193809, 0.34228459, 0.33633634]), split2_test_score: array([0.32212982, 0.33073458, 0.33165858, 0.32796258]), mean_test_score: array([0.32700008, 0.33670209, 0.33691384, 0.33188958]), std_test_score: array([0.00363239, 0.00460297, 0.00433882, 0.00343827]), rank_test_score: array([4, 2, 1, 3])}这里的效果不好是因为我们截取了很多数据所以数据量不够多模型欠拟合 12. 【知识补充】数据分割 前面已经讲过我们可通过实验测试来对学习器的泛化误差进行评估并进而做出选择。为此需使用一个“测试集”testing set来测试学习器对新样本的判别能力然后以测试集上的“测试误差”testing error作为泛化误差的近似。 通常我们假设测试样本也是从样本真实分布中独立同分布采样而得。但需注意的是测试集应该尽可能与训练集互斥。 互斥即测试样本尽量不在训练集中出现、未在训练过程中使用过。 测试样本为什么要尽可能不出现在训练集中呢为理解这一点不妨考虑这样一个场景 老师出了10道习题供同学们练习考试时老师又用同样的这10道题作为试题这个考试成绩能否有效反映出同学们学得好不好呢 答案是否定的可能有的同学只会做这10道题却能得高分。 回到我们的问题上来我们希望得到泛化性能强的模型好比是希望同学们对课程学得很好、获得了对所学知识“举一反三”的能力训练样本相当于给同学们练习的习题测试过程则相当于考试。显然若测试样本被用作训练了则得到的将是过于“乐观”的估计结果。 可是如果我们只有一个包含 m m m 个样例的数据集 D { ( x 1 , y 1 ) , ( x 2 , y 2 ) , . . . , ( x m , y m ) } D\{(x_1, y_1), (x_2, y_2), ..., (x_m, y_m) \} D{(x1​,y1​),(x2​,y2​),...,(xm​,ym​)}。这个数据集既要训练又要测试怎样才能做到呢 答案是通过对 D D D 进行适当的处理从中产生出训练集 S S S 和测试集 T T T这个也是我们前面一直在做的事情。 下面我们一起总结一下几种常见的做法 留出法交叉验证法自助法 12.1 留出法Hold-out Method 12.1.1 留出法的原理 “留出法”Hold-out直接将数据集 D D D 划分为两个互斥的集合其中一个集合作为训练集 S S S另一个作为测试集 T T T即 D S ∪ T DS \cup T DS∪T S ∩ T Φ S \cap T \Phi S∩TΦ。在 S S S 上训练出模型后用 T T T 来评估其测试误差作为对泛化误差的估计。 之前我们使用的划分方法就是留出法 大家在使用的过程中需注意的是训练/测试集的划分要尽可能保持数据分布的一致性避免因数据划分过程引入额外的偏差而对最终结果产生影响例如在分类任务中至少要保持样本的类别比例相似。 如果从采样Sampling的角度来看待数据集的划分过程则保留类别比例的采样方式通常称为“分层采样”Stratified Sampling。 例如通过对 D D D 进行分层样而获得含 70 % 70\% 70% 样本的训练集 S S S 和含 30 % 30\% 30% 样本的测试集 T T T。 若 D D D 包含 500 500 500 个正例、 500 500 500 个反例则分层采样得到的 S S S 应包含 350 350 350 个正例、 350 350 350 个反例而 T T T 则包含 150 150 150 个正例和 150 150 150 个反例。 —— 训练集和测试集的正例:反例得到的比例应该相同 正 例 训练集 反 例 训练集 正 例 测试集 反 例 测试集 \frac{正例_{训练集}}{反例_{训练集}} \frac{正例_{测试集}}{反例_{测试集}} 反例训练集​正例训练集​​反例测试集​正例测试集​​ 若 S S S、 T T T 中样本类别比例差别很大则误差估计将由于训练/测试数据分布的差异而产生偏差。 另一个需注意的问题是即便在给定训练测试集的样本比例后仍存在多种划分方式对初始数据集 D D D 进行分割。 例如在上面的例子中可以把 D D D 中的样本排序然后把前350个正例放到训练集中也可以把最后350个正例放到训练集中这些不同的划分将导致不同的训练/测试集。相应的模型评估的结果也会有差别。 因此单次使用留出法得到的估计结果往往不够稳定可靠。在使用留出法时一般要采用若干次随机划分、重复进行实验评估后取平均值作为留出法的评估结果。 例如进行100次随机划分每次产生一个训练/测试集用于实验评估。100次后就得到100个结果而留出法返回的则是这100个结果的平均。 a c c t e s t 1 n ∑ i 1 n a c c i \rm{acc_{test}} \frac{1}{n}\sum_{i1}^n \rm{acc}_i acctest​n1​i1∑n​acci​ 其中 i i i 是每次实验的ID。 12.1.2 留出法的问题 此外我们希望评估的是用 D D D 训练出的模型的性能但留出法需划分训练/测试集这就会导致一个窘境 若令训练集 S S S 包含绝大多数样本则训练出的模型可能更接近于用 D D D 训练出的模型由于 T T T 比较小评估结果可能不够稳定准确若令测试集 T T T 多包含一些样本则训练集 S S S 与 D D D 差别大了被评估的模型与用 D D D 训练出的模型相比可能有较大差别从而降低了评估结果的保真性fidelity。 fidelity英[fɪˈdeləti] 美[fɪˈdeləti] n. 忠诚; 忠实; (对丈夫、妻子或性伴侣的)忠贞; 准确性; 精确性; 这个问题没有完美的解决方案常见做法是将大约 2 3 \frac{2}{3} 32​ ~ 4 5 \frac{4}{5} 54​ 的样本用于训练剩余样本用于测试。 12.1.3 留出法的实现 使用Python实现留出法 from sklearn.model_selection import train_test_splitdata [数据1, 数据2, 数据3, 数据4, 数据5, 数据6, 数据7, 数据8, 数据9, 数据10] target [标签1, 标签2, 标签3, 标签4, 标签5, 标签6, 标签7, 标签8, 标签9, 标签10]# 使用train_test_split划分训练集和测试集 x_train, x_test, y_train, y_test train_test_split(data, target, test_size0.3, random_state0)print(训练集, x_train, y_train) print(测试集, x_test, y_test) 训练集 [数据10, 数据2, 数据7, 数据8, 数据4, 数据1, 数据6] [标签10, 标签2, 标签7, 标签8, 标签4, 标签1, 标签6] 测试集 [数据3, 数据9, 数据5] [标签3, 标签9, 标签5]12.1.4 留出法的特例留一法Leave-One-OutLOO 在留出法中有一个特例叫做留一法Leave-One-Out简称LOO。即每次抽取一个样本作为测试集。显然留一法不受随机样本划分方式的影响因为 m m m 个样本只有唯一的方式划分为 m m m 个子集——每个子集包含一个样本。 简而言之留一法就是每次训练时都只留下一个样本作为测试集其余的样本都用来训练模型。 使用Python实现留一法 LeaveOneOut() 是 sklearn.model_selection 模块中的一个函数它提供了训练/测试索引来将数据分成训练集和测试集。 注意LeaveOneOut 必须实例化对象后才能使用 .split() 方法。 LeaveOneOut.split() 方法用于将数据分成训练集和测试集。它接受一个参数 X表示要分割的数据。它返回一个生成器可以用来迭代训练集和测试集的索引。 from sklearn.model_selection import LeaveOneOutdata [数据1, 数据2, 数据3, 数据4, 数据5, 数据6, 数据7, 数据8, 数据9, 数据10] target [标签1, 标签2, 标签3, 标签4, 标签5, 标签6, 标签7, 标签8, 标签9, 标签10]# 使用LeaveOneOut划分训练集必须实例化LeaveOneOut对象 loo LeaveOneOut() res loo.split(Xdata, ytarget) # ytarget可写可不写for train_idx, test_idx in res:print(训练集, train_idx)print(测试集, test_idx)结果 训练集 [1 2 3 4 5 6 7 8 9] 测试集 [0] 训练集 [0 2 3 4 5 6 7 8 9] 测试集 [1] 训练集 [0 1 3 4 5 6 7 8 9] 测试集 [2] 训练集 [0 1 2 4 5 6 7 8 9] 测试集 [3] 训练集 [0 1 2 3 5 6 7 8 9] 测试集 [4] 训练集 [0 1 2 3 4 6 7 8 9] 测试集 [5] 训练集 [0 1 2 3 4 5 7 8 9] 测试集 [6] 训练集 [0 1 2 3 4 5 6 8 9] 测试集 [7] 训练集 [0 1 2 3 4 5 6 7 9] 测试集 [8] 训练集 [0 1 2 3 4 5 6 7 8] 测试集 [9]Q为什么 LeaveOneOut.split() 方法会返回好几组数据 ALeaveOneOut.split() 方法返回一个生成器它会生成多组数据每组数据都包含一组训练集索引和一组测试集索引。这是因为 LeaveOneOut 是一种特殊的交叉验证方法它会将数据集分成多个子集每次留下一个子集作为测试集其余的子集作为训练集。因此它会返回多组数据每组数据都对应一种不同的训练集和测试集的划分方式。 留一法的优缺点 优点 留一法使用的训练集与初始数据集相比只少了一个样本这就使得在绝大多数情况下被实际评估的模型与期望评估的用 D D D 训练出的模型很相似数据尽可能用来训练而不是保留一部分用来测试。因此留一法的评估结果往往被认为比较准确。 缺点 在数据集比较大时训练 m m m 个模型的计算开销可能是难以忍受的例如数据集包含1百万个样本则需训练1百万个模型而这还是在未考虑算法调参的情况下。 留一法适合小数据集的场景。 12.2 交叉验证法Cross ValidationCV “交叉验证法”Cross ValidationCV先将数据集 D D D 划分为 k k k 个大小相似的互斥的子集即 D D 1 ∪ D 2 ∪ . . . ∪ D k 其中 D i ∩ D j Φ ( i ≠ j ) D D_1 \cup D_2 \cup ... \cup D_k \\ 其中D_i \cap D_j \Phi (i \neq j) DD1​∪D2​∪...∪Dk​其中Di​∩Dj​Φ(ij) 每个子集 D i D_i Di​ 都尽可能保持数据分布的一致性即从 D D D 中通过分层抽样得到。 然后每次用 k − 1 k-1 k−1 个子集的并集 ∪ \cup ∪作为训练集余下的那个子集作为测试集这样就可获得 k k k 组训练集/测试集从而可进行 k k k 次训练和测试最终返回的是这 k k k 个测试结果的均值。 显然交叉验证法评估结果的稳定性和保真性在很大程度上取决于 k k k 的取值为强调这一点通常把交叉验证法称为“k折交叉验证”k-fold cross validationk-CV。 k k k 最常用的取值是10此时称为10折交叉验证其他常用的 k k k 值有5、20等。下图给出了10折交叉验证的示意图。 与留出法相似将数据集 D D D 划分为 k k k 个子集同样存在多种划分方式。为减小因样本划分不同而引入的差别k-CV通常要随机使用不同的划分重复 p p p 次最终的评估结果是这 p p p 次K-CV结果的均值例如常见的有“10次10折交叉验证” —— K-CV(p10)。 与留出法相似并不是一次得出结果而是多次得出结果。 交叉验证实现方法除了咱们前面讲的GridSearchCV之外还有KFold、StratifiedKFold。 KFold和StratifiedKFold的代码实现 from sklearn.model_selection import KFold, StratifiedKFold用法 将训练/测试数据集划分n_splits个互斥的子集每次用其中一个子集当作测试集剩下的n_splits-1个作为训练集。进行n_splits次训练和测试得到n_splits个结果。StratifiedKFold的用法和KFold的区别是StratifiedKFold是分层采样确保训练集/测试集中各类别样本的比例是和原始数据集中的一致。 Q什么是分层采样 A分层抽样stratified sampling是一种概率抽样方法它将总体按照某些特征分成若干个互不相交的层然后从每一层中按照一定的比例随机抽取样本。这样可以保证每一层中的样本数量与总体中该层所占比例相同从而提高抽样的代表性。 Q举个例子来解释分层抽样。 A假设你想调查一个城市中人们对某个问题的看法你可以将这个城市的人口按照年龄分成若干个层比如18-30岁、31-40岁、41-50岁、51-60岁和60岁以上。然后你可以根据每个层在总人口中所占的比例来确定每个层中应该抽取多少样本。例如如果18-30岁这个层占总人口的20%那么在抽取1000个样本时就应该从这个层中抽取200个样本。这样你就能获得一个更具代表性的样本。 注意点 对于不能均等分数据集其前n_samples % n_splits子集拥有n_samples // n_splits 1个样本其余子集都只有n_samples // n_splits个样本。前面几个多1个样本后面的少一个样本 参数说明 n_splits表示划分几等份shuffle在每次划分时是否进行洗牌 若为False时其效果等同于random_state等于整数每次划分的结果相同若为True时每次划分的结果都不一样表示经过洗牌随机取样的操作 属性 split(XNone, yNone, groupsNone)将数据集划分成训练集和测试集返回索引生成器。注意KFold和StratifiedKFold都必须实例化才能使用.split()方法 之前我们使用的留出法train_test_split()返回的不是索引生成器。它返回的是划分后的训练集和测试集数据。 举例 import numpy as np from sklearn.model_selection import KFold, StratifiedKFoldx np.array([[1, 2, 3, 4], [11, 12, 13, 14], [21, 22, 23, 24], [31, 32, 33, 34], [41, 42, 43, 44], [51, 52, 53, 54], [61, 62, 63, 64], [71, 72, 73, 74]])y np.array([1, 1, 0, 0, 1, 1, 0, 0])# 实例化 kf KFold(n_splits4, random_stateNone, shuffleFalse) skf StratifiedKFold(n_splits4, random_stateNone, shuffleFalse)count 1 for train_idx, test_idx in kf.split(Xx, yy):print(第%d组 % count, end)print(训练集索引%s\t测试集索引%s % (train_idx, test_idx))count 1print(- * 50) count 1 for train_idx, test_idx in skf.split(Xx, yy):print(第%d组 % count, end)print(训练集索引%s\t测试集索引%s % (train_idx, test_idx))count 1结果 第1组训练集索引[2 3 4 5 6 7] 测试集索引[0 1] 第2组训练集索引[0 1 4 5 6 7] 测试集索引[2 3] 第3组训练集索引[0 1 2 3 6 7] 测试集索引[4 5] 第4组训练集索引[0 1 2 3 4 5] 测试集索引[6 7] -------------------------------------------------- 第1组训练集索引[1 3 4 5 6 7] 测试集索引[0 2] 第2组训练集索引[0 2 4 5 6 7] 测试集索引[1 3] 第3组训练集索引[0 1 2 3 5 7] 测试集索引[4 6] 第4组训练集索引[0 1 2 3 4 6] 测试集索引[5 7]可以看出SKFold进行4折计算时候是平衡了测试集中样本正负的分布的﹔但是KFold却没有。 12.3 自助法Bootstrap Method 我们希望评估的是用 D D D 训练出的模型。但在留出法和交叉验证法中由于保留了一部分样本用于测试因此实际评估的模型所使用的训练集比 D D D 小这必然会引入一些因训练样本规模不同而导致的估计偏差。留一法受训练样本规模变化的影响较小但计算复杂度又太高了。 有没有什么办法可以减少训练样本规模不同造成的影响同时还能比较高效地进行实验估计呢 “自助法”(bootstrap)是一个比较好的解决方案它直接以自助采样法(bootstrap samplingBS)为基础。给定包含 m m m 个样本的数据集 D D D我们对它进行采样产生数据集 D ′ D D′ 每次随机从 D D D 中挑选一个样本将其拷贝放入 D ′ D D′然后再将该样本放回初始数据集 D D D 中使得该样本在下次采样时仍有可能被到这个过程重复执行 m m m 次后我们就得到了包含 m m m 个样本的数据集 D ′ D D′这就是自助采样的结果。 显然 D D D 中有一部分样本会在 D ′ D D′ 中多次出现而另一部分样本不出现。可以做一个简单的估计样本在 m m m 次采样中始终不被采到的概率是 ( 1 − 1 m ) m (1 - \frac{1}{m})^m (1−m1​)m取极限得到 lim ⁡ m → ∞ ( 1 − 1 m ) m → 1 e ≈ 36.8 % \lim_{m\to \infty}(1 - \frac{1}{m})^m \to \frac{1}{e} \approx 36.8\% m→∞lim​(1−m1​)m→e1​≈36.8% 即通过自助采样初始数据集 D D D 中约有 36.8 % 36.8\% 36.8% 的样本未出现在采样数据集 D ′ D D′ 中。 于是我们可将 D ′ D D′ 用作训练集 D / D ′ D / D D/D′ 用作测试集。这样实际评估的模型与期望评估的模型都使用 m m m 个训练样本而我们仍有数据总量约1/3的、没在训练集中出现的样本用于测试。 这样的测试结果亦称“包外估计”out-of-bag estimateOOB。 Qbootstrap这个单词应该怎么理解 Abootstrap 这个单词原意指靴子上的拉环用来帮助人们穿上靴子。后来这个词被引申为“自助”的意思表示通过自己的力量解决问题。在计算机科学中bootstrap 指的是计算机启动时加载操作系统的过程在统计学中bootstrap 指的是一种通过对原始数据集进行重采样来生成新数据集的方法用于估计总体参数或构建置信区间。 自助法优缺点: 优点 自助法在数据集较小、难以有效划分训练集/测试集时很有用自助法能从初始数据集中产生多个不同的训练集这对集成学习等方法有很大的好处。 缺点 自助法产生的数据集改变了初始数据集的分布这会引入估计偏差。因此在初始数据量足够时留出法和交叉验证法更常用一些。 小结 当我们数据量足够时选择留出法简单省时在牺牲很小的准确度的情况下换取计算的简便当我们的数据量较小时我们应该选择交叉验证法因为此时划分样本集将会使训练数据过少当我们的数据量特别少的时候我们可以考虑留一法。
http://www.dnsts.com.cn/news/103720.html

相关文章:

  • 千万别去电商公司上班百度排名优化咨询电话
  • 江阳建设集团网站旅游网站建设方案简介
  • 阿里巴巴上做网站达内学网站开发培训课程
  • 网站建设首选九零后网络快速建站视频
  • 中国电商网站排行榜郑州购物网站建设
  • 北京网站建设还公司做网站和APP需要多少钱
  • 织梦网站后台登陆河南企业建站系统信息
  • 网站开发最流行的语言建网站有哪些文件夹
  • 做网站的外包能学到什么python云服务器网站开发实例
  • 网站seo收录工具网站设置默认首页
  • 湖南专业建站按效果付贿小众电商平台有哪些
  • 门窗厂家东莞网站建设wordpress网站如何提速
  • 怎样看一个网站的信息吗快手app下载安装免费下载
  • 网站建设丷金手指专业十五wordpress文章随机缩略图
  • 做网站需要买ip地址吗互联网公司薪资待遇
  • wordpress站群主题网络实施方案
  • 江西省建设厅教育网站上查询电商网站 服务器
  • 专业制作门户型网站公司网页设计作品
  • 如何给一个网站做定时的更新dedecms 做网站
  • 深圳网站建设软件开发公司排名wordpress插件装多了卡
  • 做高仿网站开发网站公司名称
  • 网站模板 源码之家优化关键词排名工具
  • 南京专业做网站的公司有哪些京东pc网站用什么做的
  • 网站seo推广计划怎样将网站开发说清楚
  • 工作站学校网站建设工作会议
  • 网站重新设计韩雪个人网站
  • 成都网站建设小公司宜昌做网站优化
  • 网站的设计方法有哪些内容安徽网站建设推荐-晨飞网络
  • 网站后台备份丢失晋城网站建设
  • 做美图 网站有哪些东西广告营销推广