有监督学习算法

  • 0. 机器学习理论基础
    • 根据酒精浓度、颜色深度判断红酒类别
    • 常用机器学习算法体系
      • 有监督学习
      • 无监督学习
      • 半监督学习
      • 强化学习
    • 输入/输出空间、特征空间
    • 过拟合与欠拟合
  • 1. KNN/K近邻算法
    • 1.1 算法原理
    • 1.2 算法的优缺点
    • 1.3 算法的变种
    • 1.4 Python代码实现
    • 1.5 SCIKIT-LEARN算法库实现
      • 主要设计原则:
      • 案例
    • 1.6 选择最优K值
      • 绘制学习曲线
    • 1.7 交叉验证
      • 1.7.1 泛化能力
      • 1.7.2 K 折交叉验证
      • 1.7.3 带交叉验证的学习曲线
      • 1.7.4 是否需要验证集
      • 1.7.5 其他交叉验证
      • 1.7.6 避免折数太大
    • 1.8 归一化
      • 1.8.1 距离类模型归一化的要求
      • 1.8.2 先分数据集,再做归一化
      • 1.8.3 通过 python 实现
      • 1.8.4 通过 sklearn 实现
    • 1.9 距离的惩罚
  • 2 决策树
    • 2.1 决策树模型
      • 2.1.1 决策树基本流程
      • 2.1.2 决策与条件概率分布
      • 2.1.3 学习算法
      • 2.1.4 特征选择:香农熵和信息增益
        • 1)香农熵的计算
        • 2)香农熵的代码实现
        • 3)信息增益
      • 2.1.5 划分数据集
        • 1) 数据集最佳切分函数
        • 2) 按照给定列切分数据集
      • 2.1.6 决策树的生成
        • ID3算法
        • C4.5 算法
          • 1) 修改局部最优化条件
          • 2) 连续变量处理手段
      • 2.1.7 决策树的拟合度优化
        • CART 算法
    • 2.2 使用SK-LEARN实现决策树
      • 2.2.1 参数CRITERION
      • 2.2.2 初步建模
      • 2.2.3 探索数据
      • 2.2.4 画出一棵树
      • 2.2.5 探索决策树属性
      • 2.2.6 防止过拟合
        • random_state & splitter
        • 剪枝参数
      • 2.1.7 总结
    • 2.3 分类模型的评估指标
      • 2.3.1 样本不均匀问题
      • 2.3.2 混淆矩阵
    • 2.4 决策树的算法评价
      • 2.4.1 决策树优点
      • 2.4.1 决策树缺点
  • 3 线性回归算法
    • 3.1 概述
    • 3.2 线性回归与机器学习
    • 3.3 线性回归的机器学习表示方法
      • 3.3.1 核心逻辑
      • 3.3.2 优化目标
      • 3.3.3 最小二乘法
    • 3.4 多元线性回归Python实现
      • 1)利用矩阵乘法编写回归算法
      • 2) 回顾算法评估指标
    • 3.5 线性回归的Scikit-learn实现
    • 3.6 多重共线性
    • 3.7 扩展:岭回归和Lasso
      • 3.7.1 岭回归
        • 基本原理
        • Python实践
      • 3.7.2 Lasso
        • 基本原理
        • Python实现
    • 3.8 总结
  • 4. 逻辑回归算法
    • 4.1 概述
    • 4.2 基本原理
    • 4.3 梯度下降(Gradient Descent)
    • 4.3.1 梯度
      • 4.3.2 梯度下降和梯度上升
      • 4.3.3 算法详解
        • 梯度下降的相关观念
      • 4.3.4 梯度下降算法调优:
    • 4.4 逻辑回归的Scikit-Learn实现
      • 4.4.1 参数详解
      • 4.4.1 正则化参数:penalty
      • 4.4.2 算法优化参数:solver
      • 4.4.4 梯度下降:重要参数max_iter
      • 4.4.5 分类方式选参数

0. 机器学习理论基础

根据酒精浓度、颜色深度判断红酒类别

常用机器学习算法体系

机器学习的方法是基于数据产生的"模型"(model)的算法,也称"学习算法"(learning algorithm)。

包括:

  • 有监督学习(supervised learning)
  • 无监督学习(unsupervised learning)
  • 半监督学习(semi-supervised learning)
  • 强化学习(reinforcement learning)

有监督学习

指对数据的若干特征与若干标签(类型)之间的关联性进行建模的过程; 只要模型被确定,就可以应用到新的未知数据上。

这类学习过程可以进一步分为「分类」(classification)任务和「回归」(regression)任务。

在分类任务中,标签都是离散值
而在回归任务中,标签都是连续值

无监督学习

指对不带任何标签的数据特征进行建模,通常被看成是一种“让数据自己介绍自己” 的过程。

这类模型包括「聚类」(clustering)任务和「降维」(dimensionality reduction)任务。

聚类算法可以将数据分成不同的组别,而降维算法追求用更简洁的方式表现数据。

半监督学习

另外,还有一种半监督学习(semi-supervised learning)方法,介于有监督学习和无监督学习之间。通常可以在数据不完整时使用。

强化学习

强化学习不同于监督学习,它将学习看作是试探评价过程,以"试错" 的方式进行学习,并与环境进行交互已获得奖惩指导行为,以其作为评价。

此时系统靠自身的状态和动作进行学习,从而改进行动方案以适应环境。

输入/输出空间、特征空间

在上面的场景中,每一杯酒称作一个「样本」,十杯酒组成一个样本集。

酒精浓度、颜色深度等信息称作「特征」。这十杯酒分布在一个「多维特征空间」中。

进入当前程序的“学习系统”的所有样本称作「输入」,并组成「输入空间」。

在学习过程中,所产生的随机变量的取值,称作「输出」,并组成「输出空间」。

在有监督学习过程中,当输出变量均为连续变量时,预测问题称为回归问题;当输出变量为有限个离散变量时,预测问题称为分类问题。

过拟合与欠拟合

当假设空间中含有不同复杂度的模型时,就要面临模型选择(model selection)的问题。

我们希望获得的是在新样本上能表现得很好的学习器。为了达到这个目的,我们应该从训练样本中尽可能学到适用于所有潜在样本的"普遍规律",我们认为假设空间存在这种"真"模型,那么所选择的模型应该逼近真模型

拟合度可简单理解为模型对于数据集背后客观规律的掌握程度,模型对于给定数据集如果拟合度较差,则对规律的捕捉不完全,用作分类和预测时可能准确率不高。

换句话说,当模型把训练样本学得太好了的时候,很可能已经把训练样本自身的一些特点当作了所有潜在样本的普遍性质,这时候所选的模型的复杂度往往会比真模型更高,这样就会导致泛化性能下降。这种现象称为过拟合(overfitting)。可以说,模型选择旨在避免过拟合并提高模型的预测能力。

与过拟合相对的是欠拟合(underfitting),是指模型学习能力低下,导致对训练样本的一般性质尚未学好。

虚线:针对训练数据集计算出来的分数,即针对训练数据集拟合的准确性。

实线:针对交叉验证数据集计算出来的分数,即针对交叉验证数据集预测的准确性。

  1. 左图:一阶多项式,欠拟合;
    ◼ 训练数据集的准确性(虚线)和交叉验证数据集的准确性(实线)靠得很近,总体水平比较高。
    ◼ 随着训练数据集的增加,交叉验证数据集的准确性(实线)逐渐增大,逐渐和训练数据集的准确性(虚线)靠近,但其总体水平比较低,收敛在 0.88 左右。
    ◼ 训练数据集的准确性也比较低,收敛在 0.90 左右。
    ◼ 当发生高偏差时,增加训练样本数量不会对算法准确性有较大的改善。
  2. 中图:三阶多项式,较好地拟合了数据集;
    ◼ 训练数据集的准确性(虚线)和交叉验证数据集的准确性(实线)靠得很近,总体水平比较
  3. 右图:十阶多项式,过拟合
    ◼ 随着训练数据集的增加,交叉验证数据集的准确性(实线)也在增加,逐渐和训练数据集的准确性(虚线)靠近,但两者之间的间隙比较大。
    ◼ 训练数据集的准确性很高,收敛在 0.95 左右。
    交叉验证数据集的准确性值却较低,最终收敛在 0.91 左右。

从图中我们可以看出,对于复杂数据,低阶多项式往往是欠拟合的状态,而高阶多项式则过分捕捉噪声数据的分布规律,而噪声之所以称为噪声,是因为其分布毫无规律可言,或者其分布毫无价值,因此就算高阶多项式在当前训练集上拟合度很高,但其捕捉到的无用规律无法推广到新的数据集上。因此该模型在测试数据集上执行过程将会有很大误差,即模型训练误差很小,但泛化误差很大。

1. KNN/K近邻算法

1.1 算法原理

它的本质是通过距离判断两个样本是否相似,如果距离够近就认为他们足够相似属于同一类别

当然只对比一个样本是不够的,误差会很大,我们需要找到离其最近的 k 个样本,并将这些样本称之为「近邻」(nearest neighbor)。对这 k 个近邻,查看它们的都属于何种类别(这些类别我们称作「标签」 (labels))。

然后根据“少数服从多数,一点算一票”原则进行判断,数量最多的的标签类别就是新样本的标签类别
其中涉及到的原理是“越相近越相似”,这也是KNN的基本假设。

  1. 实现过程
    假设 X_test 待标记的数据样本,X_train为已标记的数据集。
  • 遍历已标记数据集中所有的样本,计算每个样本与待标记点的距离,并把距离保存在 Distance 数组中。
  • 对 Distance 数组进行排序,取距离最近的 k 个点,记为 X_knn.
  • X_knn 中统计每个类别的个数,即 class0 在 X_knn 中有几个样本,class1 在 X_knn 中有几个样本等。
  • 待标记样本的类别,就是在 X_knn 中样本个数最多的那个类别。
  1. 距离的确定
    该算法的「距离」在二维坐标轴就表示两点之间的距离,计算距离的公式有很多。

我们常用欧拉公式,即“欧氏距离”。回忆一下,一个平面直角坐标系上,如何计算两点之间的距离?一个立体直角坐标系上,又如何计算两点之间的距离?

当特征数量有很多个形成多维空间时,再用上述的写法就不方便了,我们换一个写法,用 X 加下角标的方式表示特征维度。则在 n 维空间中,有两个点 A 和 B,它们的坐标分别为:
A(x1A,x2A,x3A,......xnA);B(x1B,x2B,x3B,......xnB)A(x_{1A},x_{2A},x_{3A},......x_{nA});B(x_{1B},x_{2B},x_{3B},......x_{nB})A(x1A​,x2A​,x3A​,......xnA​);B(x1B​,x2B​,x3B​,......xnB​)
则 A 和 B 两点之间的欧氏距离的基本计算公式如下:

而在我们的机器学习中,坐标轴上的值x1,x2 , x3,…… xn正是我们样本数据上的 n 个特征。

1.2 算法的优缺点

算法参数是 k,k 可以理解为标记数据周围几个数作为参考对象,参数选择需要根据数据来决定。

  • k 值越大,模型的偏差越大,对噪声数据越不敏感。
  • k 值很大时,可能造成模型欠拟合。
  • k 值越小,模型的方差就会越大。
  • 但是 k 值太小,容易过拟合。

1.3 算法的变种

变种一:默认情况下,在计算距离时,权重都是相同的,但实际上我们可以针对不同的邻居指定不同的距离权重,比如距离越近权重越高。

  • 这个可以通过指定算法的 weights 参数来实现。

变种二:使用一定半径内的点取代距离最近的 k 个点

  • 在 scikit-learn 中,RadiusNeighborsClassifier 实现了这种算法的变种。
  • 当数据采样不均匀时,该算法变种可以取得更好的性能。

1.4 Python代码实现

  • 导入相关包
#全部行都能输出
from IPython.core.interactiveshell import InteractiveShell
InteractiveShell.ast_node_interactivity = "all"
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt# 解决坐标轴刻度负号乱码
plt.rcParams['axes.unicode_minus'] = False
# 解决中文乱码问题
plt.rcParams['font.sans-serif'] = ['Simhei']
plt.style.use('ggplot')
# plt.figure(figsize=(2,3),dpi=720)
  • 构建已经分类好的原始数据集
    首先随机设置十个样本点表示十杯酒,这里取了部分样本点。
    为了方便验证,这里使用 Python 的字典 dict 构建数据集,然后再将其转化成 DataFrame 格式。
rowdata = {'颜色深度':[14.13,13.2,13.16,14.27,13.24,12.07,12.43,11.79,12.37,12.04],'酒精浓度': [5.64,4.28,5.68,4.80,4.22,2.76,3.94,3.1,2.12,2.6],'品种': [0,0,0,0,0,1,1,1,1,1]}
# 0 代表 “黑皮诺”,1 代表 “赤霞珠”
wine_data = pd.DataFrame(rowdata)
wine_data

X = np.array(wine_data.iloc[:,0:2]) #我们把特征(酒的属性)放在X
y = np.array(wine_data.iloc[:,-1]) #把标签(酒的类别)放在Y
#探索数据,假如我们给出新数据[12.03,4.1] ,你能猜出这杯红酒是什么类别么?
new_data = np.array([12.03,4.1])plt.scatter(X[y==1,0], X[y==1,1], color='red', label='赤霞珠') #画出标签y为1的、关于“赤霞珠”的散点
plt.scatter(X[y==0,0], X[y==0,1], color='purple', label='黑皮诺') #画出标签y为0的、关于“黑皮诺”的散点
plt.scatter(new_data[0],new_data[1], color='yellow') # 新数据点
new_dataplt.xlabel('酒精浓度')
plt.ylabel('颜色深度')
plt.legend(loc='lower right')
plt.savefig('葡萄酒样本.png')

  • 计算已知类别数据集中的点与当前点之间的距离
    我们使用欧式距离公式,计算新数据点 new_data 与现存的 X 数据集每一个点的距离:
from math import sqrt
distance = [sqrt(np.sum((x-new_data)**2)) for x in X ]
distance

  • 将距离升序排列,然后选取距离最小的k个点
sort = np.argsort(distance)
sort

6、7、4为最近的3个“数据点”的索引值,那么这些索引值对应的原数据的标签是什么?

K3 = sort[:3] #索引值topk = [y[i] for i in K3]
topk

[1, 1, 0]

  • 确定前k个点所在类别的计数,找出最多次计数的类别
pd.Series(topk).value_counts().idxmax()

1

  • 将上述过程封装成一个函数
def KNN(new_data,dataset,k):'''函数功能:KNN分类器参数说明:new_data:需要预测分类的新数据dataset:已有已知分类标签的数据集k:k-紧邻算法参数,选择距离最小的k个点return:分类结果'''from math import sqrtimport numpy as npimport pandas as pd X = np.array(dataset.iloc[:,:2])Y = np.array(dataset.iloc[:,-1])distance = [sqrt(np.sum((x-new_data)**2)) for x in X]K_k = np.argsort(distance)[:k]topk = [Y[i] for i in K_k]catgory = pd.Series(topk).value_counts().idxmax()return catgory
# 测试函数的运行结果
new_data=np.array([12.03,4.1])
k = 3
KNN(new_data,wine_data,k)# 输出1

1.5 SCIKIT-LEARN算法库实现

scikit-learn 自 2007 年发布以来,scikit-learn已经成为 Python 中重要的机器学习库了。

scikit-learn,简称 sklearn, 支持了包括分类、回归、降维和聚类四大机器学习算法,以及特征提取、数据预处理和模型评估三大模块。

在工程应用中,用 Python 手写代码来从头实现一个算法的可能性非常低,这样不仅耗时耗力,还不一 定能够写出构架清晰,稳定性强的模型。更多情况下,是分析采集到的数据,根据数据特征选择适合的算法, 在工具包中调用算法,调整算法的参数,获取需要的信息,从而实现算法效率和效果之间的平衡。而 sklearn, 正是这样一个可以帮助我们高效实现算法应用的工具包。

scikit-learn官网

主要设计原则:

  1. 一致性
    所有对象共享一个简单一致的界面(接口)。

    • 估算器:fit()方法。基于数据估算参数的任意对象,使用的参数是一个数据集(对应 X, 有监督算法还需要一个 y),引导估算过程的任意其他参数称为超参数,必须被设置为实例变量。
    • 转换器:transform()方法。使用估算器转换数据集,转换过程依赖于学习参数。可以使用便捷方式: fit_transform(),相当于先 fit()再 transform()。(fit_transform 有时被优化过,速度更快)
    • 预测器:predict()方法。使用估算器预测新数据,返回包含预测结果的数据,还有score()方法:用于度量给定测试集的预测效果的好坏。(连续 y 使用 R 方,分类 y 使用准确率 accuracy)
  2. 监控
    检查所有参数,所有估算器的超参数可以通过公共实例变量访问,所有估算器的学习参数都可以通过有下划线后缀的公共实例变量访问。

  3. 防止类扩散
    对象类型固定,数据集被表示为 Numpy 数组或 Scipy 稀疏矩阵,超参是普通的 Python 字符或数字。

  4. 合成
    现有的构件尽可能重用,可以轻松创建一个流水线 Pipeline。

  5. 合理默认值
    大多数参数提供合理默认值,可以轻松搭建一个基本的工作系统

案例

  1. 红酒分类
from sklearn.neighbors import KNeighborsClassifier# 0 代表 “黑皮诺”,1 代表 “赤霞珠”
clf = KNeighborsClassifier(n_neighbors = 3)
clf = clf.fit(wine_data.iloc[:,0:2], wine_data.iloc[:,-1])a = np.random.normal(11,2,(10,1))
b = np.random.normal(4,2,(10,1))
new_data = np.concatenate((a,b),axis=1)result = clf.predict(new_data) # 返回预测的标签
result

array([0, 1, 0, 0, 1, 1, 1, 1, 0, 1], dtype=int64)

# 对模型进行一个评估,接口score返回预测的准确率
y_new = np.array([0, 1, 0, 0, 1, 1, 1, 1, 0, 0]) # 实际结果,最后一个1改成0clf.score(new_data,y_new)

返回0.9,代表90%准确率,即10个结果预测对了9个

clf.predict_proba([[12.8,4.1]])
#输出数据[12.8,4.1]为标签0的概率(0.666...),以及标签为1的概率(0.333...)

array([[0.66666667, 0.33333333]])

  1. 乳腺癌
from sklearn.neighbors import KNeighborsClassifier
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_splitimport pandas as pd
import numpy as np
#读取数据集
data = load_breast_cancer()
#DateFrame格式显示
X = data.data
y = data.target
name = data.feature_names
names = np.append(names,'患病否')
data=np.concatenate((X,y.reshape(-1,1)),axis=1)
table=pd.DataFrame(data=data,columns=names)
table.head()

# 划分训练集和测试集 #30%数据作为训练集
Xtrain,Xtest,Ytrain,Ytest = train_test_split(X,y,test_size=0.2,random_state=420)
# 建立模型&评估模型
clf = KNeighborsClassifier(n_neighbors=4)
# 建立分类器
clf = clf.fit(Xtrain,Ytrain)
score = clf.score(Xtest,Ytest)
score

0.9210526315789473

如何用上面分类器拟合结果找出离 Xtest 中第 20 行和第 30 行最近的 4 个“点”?

#查找点的K邻居。返回每个点的邻居的与之的距离和索引值。
clf.kneighbors(Xtest[[20,30],:],return_distance=True)

(array([[35.70015941, 42.02374599, 81.82147557, 83.06271326],
[11.81126721, 14.5871725 , 17.4734004 , 18.94892695]]),
array([[112, 221, 303, 263],[268, 162, 42, 134]], dtype=int64))

1.6 选择最优K值

KNN 中的 k 是一个超参数,所谓“超参数”,就是需要人为输入,算法不能通过直接计算得出的参数

KNN 中的 k 代表的是距离需要分类的测试点 x 最近的 k 个样本点,如果不输入这个值,那么算法中重要部分 “选出 k 个最近邻” 就无法实现。

从 KNN 的原理中可见,是否能够确认合适的 k 值对算法有极大的影响。

如果选择的 k 值较小,就相当于较小的邻域中的训练实例进行预测,这时候只有与输入实例较近的(相似的)训练实例才会对预测结果起作用,但缺点是预测结果会对近邻的实例点非常敏感。如果邻近的实例点恰好是噪声,预测就会出错。

相反地,如果选择的 k 值较大,就相当于较大的邻域中的训练实例进行预测。这时与输入实例较远的 (不相似的)训练实例也会对预测起作用,使预测发生错误。因此,超参数 k 的选定是 KNN 的头号问题。

绘制学习曲线

那我们怎样选择一个最佳的 k 呢?在这里我们要使用机器学习中的神器:参数学习曲线。参数学习曲线是一条以不同的参数取值为横坐标,不同参数取值下的模型结果为纵坐标的曲线,我们往往选择模型表现最佳点的参数取值作为这个参数的取值。

# 更换不同的n_neighbors参数的取值,观察结果的变化
clf = KNeighborsClassifier(n_neighbors=7)
clf = clf.fit(Xtrain,Ytrain)
score = clf.score(Xtest,Ytest)
score

0.9385964912280702

绘制学习曲线:

score = [ ]
krange = range(1,20)
for i in krange:clf = KNeighborsClassifier(n_neighbors=i)clf = clf.fit(Xtrain,Ytrain)score.append(clf.score(Xtest,Ytest))plt.plot(krange,score)
plt.show()

究竟上图中k为多少的时候分数越高?

score.index(max(score))+1

8
但是这个时候会有个问题,如果随机划分的数据集变化的的话,得分最高的k值也会发生变化:

Xtrain,Xtest,Ytrain,Ytest = train_test_split(X,y,test_size=0.2,random_state=421)
score = []
krange = range(1,20)for i in krange:clf = KNeighborsClassifier(n_neighbors=i)clf = clf.fit(Xtrain,Ytrain)score.append(clf.score(Xtest,Ytest))plt.plot(krange,score)
plt.show()
score.index(max(score))+1

3

这样就无法确定最佳的k值了,就无法进行下面的建模工作,怎么办?
这就要用到交叉验证了

1.7 交叉验证

确定了 k 之后,我们还能够发现一件事:每次运行的时候学习曲线都在变化,模型的效果时好时坏, 这是为什么呢?

实际上,这是由于「训练集」和「测试集」的划分不同造成的。模型每次都使用不同的训练集进行训练, 不同的测试集进行测试,自然也就会有不同的模型结果。

在业务当中,我们的训练数据往往是已有的历史数据,但我们的测试数据却是新进入系统的一系列还没有标签的未知数据。我们的确追求模型的效果,但我们追求的是模型在未知数据集上的效果,在陌生数据集上表现优秀的能力被称为泛化能力,即我们追求的是模型的泛化能力。

1.7.1 泛化能力

我们在进行学习算法前, 通常会将一个样本集分成训练集(training set)和测试集(testing set),其中训练集用于模型的学习或训练,而后测试集通常用于评估训练好的模型对于数据的预测性能评估。

训练误差(training error)代表模型在训练集上的错分样本比率。

测试误差(empirical error)是模型在测试集上的错分样本比率。

训练误差的大小,用来判断给定问题是不是一个容易学习的问题。 测试误差则反映了模型对未知数据的预测能力,测试误差小的学习方法具有很好的预测能力,如果得到的训练集和测试集的数据没有交集,通常将此预测能力称为泛化能力(generalization ability)。 我们认为,如果模型在一套训练集和数据集上表现优秀,那说明不了问题,只有在众多不同的训练集和 测试集上都表现优秀,模型才是一个稳定的模型,模型才具有真正意义上的泛化能力。为此,机器学习领域有发挥神作用的技能:「交叉验证」,来帮助我们认识模型。

1.7.2 K 折交叉验证

最常用的交叉验证是 k 折交叉验证。我们知道训练集和测试集的划分会干扰模型的结果,因此用交叉验证 n 次的结果求出的均值,是对模型效果的一个更好的度量。

1.7.3 带交叉验证的学习曲线

对于带交叉验证的学习曲线,我们需要观察的就不仅仅是最高的准确率了,而是准确率高且方差还相对较小的点,这样的点泛化能力才是最强的。在交叉验证+学习曲线的作用下,我们选出的超参数能够保证更好的泛化能力。

from sklearn.model_selection import cross_val_score as CVSXtrain,Xtest,Ytrain,Ytest = train_test_split(X,y,test_size=0.2,random_state=420)
clf = KNeighborsClassifier(n_neighbors=8)
cvresult = CVS(clf,Xtrain,Ytrain,cv=6) #训练集对折6次,一共6个预测率输出
cvresult #每次交叉验证运行时估算器得分的数组

array([0.92207792, 0.90789474, 0.97368421, 0.94736842, 0.93333333, 0.92 ])

# 均值:查看模型的平均效果
cvresult.mean()
# 方差:查看模型是否稳定
cvresult.var()

0.934059770638718
0.0004622658270548926

score = []
var = []
krange=range(1,20) #设置不同的k值,从1到19都看看for i in krange:clf = KNeighborsClassifier(n_neighbors=i)cvresult = CVS(clf,Xtrain,Ytrain,cv=5)score.append(cvresult.mean()) # 每次交叉验证返回的得分数组,再求数组均值var.append(cvresult.var())plt.plot(krange,score,color='k')
plt.plot(krange,np.array(score)+np.array(var)*2,c='red',linestyle='--')
plt.plot(krange,np.array(score)-np.array(var)*2,c='red',linestyle='--')

1.7.4 是否需要验证集

最标准,最严谨的交叉验证应该有三组数据:训练集、验证集和测试集。 当我们获取一组数据后:

  • 先将数据集分成整体的训练集和测试集。
  • 然后我们把训练集放入交叉验证中。
  • 从训练集中分割更小的训练集(k-1 份)和验证集(1 份)。
  • 返回的交叉验证结果其实是验证集上的结果。
  • 使用验证集寻找最佳参数,确认一个我们认为泛化能力最佳的模型。
  • 将这个模型使用在测试集上,观察模型的表现。

通常来说,我们认为经过验证集找出最终参数后的模型的泛化能力是增强了的,因此模型在未知数据(测试集)上的效果会更好,但尴尬的是,模型经过交叉验证在验证集上的调参之后,在测试集上的结果没有变好的情况时有发生。

原因其实是:

  • 我们自己分的训练集和测试集,会影响模型的效果。
  • 交叉验证后的模型的泛化能力增强了,表示它在未知数据集上方差更小,平均水平更高,但却无法保证它在现在分出来的测试集上预测能力最强。
  • 如此说来,是否有测试集的存在,其实意义不大了

如果我们相信交叉验证的调整结果是增强了模型的泛化能力的,那即便测试集上的测试结果并没有变好(甚至变坏了),我们也认为模型是成功的。 如果我们不相信交叉验证的调整结果能够增强模型的泛化能力,而一定要依赖测试集来进行判断,我们完全没有进行交叉验证的必要,直接用测试集上的结果来跑学习曲线就好了。 所以,究竟是否需要验证集,其实是存在争议的,在严谨的情况下,大家还是使用有验证集的方式。

1.7.5 其他交叉验证

交叉验证的方法不止“k 折” 一种,分割训练集和测试集的方法也不止一种,分门别类的交叉验证占据了sklearn 中非常长的一章。

所有的交叉验证都是在分割训练集和测试集,只不过侧重的方向不同。

  • k 折"就是按顺序取训练集和测试集。
  • ShuffleSplit 就侧重于让测试集分布在数据的全方位之内。
  • StratifiedKFold 则是认为训练数据和测试数据必须在每个标签分类中占有相同的比例。

各类交叉验证的原理繁琐,大家在机器学习道路上一定会逐渐遇到更难的交叉验证,但是万变不离其宗:本质上交叉验证是为了解决训练集和测试集的划分对模型带来的影响,同时检测模型的泛化能力的。

交叉验证的折数不可太大,因为折数越大抽出来的数据集越小,训练数据所带的信息量会越小,模型会越来越不稳定。

1.7.6 避免折数太大

如果你发现不使用交叉验证的时候模型表现很好,一使用交叉验证模型的效果就骤降

  • 一定要查看你的标签是否有顺序。
  • 然后就是查看你的数据量是否太小,折数是否太高。

如果将上面例题的代码中将 cv 将 5 改成 100:

折数过大:

  • 运算效率变慢
  • 预测率方差变大,难以保证在新的数据集达到预期预测率。

1.8 归一化

1.8.1 距离类模型归一化的要求

什么是归一化?我们把 X 放到数据框中来看一眼,你是否观察到,每个特征的均值差异很大?有的特征数值很大,有的特征数值很小,这种现象在机器学习中被称为"量纲不统一"。KNN 是距离类模型,欧氏距离的计算公式中存在着特征上的平方和:

如果某个特征的取值非常大,其他特征的取值和它比起来就不算什么,那么距离的大小很大程度都会由这个来决定,其他的特征之间的距离可能就无法对d(A,B)的大小产生什么影响,这种现象会让KNN这样的距离类模型的效果大打折扣。

然而在实际分析情景当中,绝大多数数据集都会存在各特征值量纲不同的情况,此时若要使用 KNN 分类器,则需要先对数据集进行归一化处理,即是将所有的数据压缩都同一个范围内。

当数据(x)按照最小值中心化后,再按极差(最大值-最小值)缩放,数据移动了最小值个单位,并且会被收敛到[0,1]之间,而这个过程,就称作数据归一化(Normalization,又称 Min-Max Scaling)。

1.8.2 先分数据集,再做归一化

直接在全数据集 X 上进行了归一化,然后放入交叉验证绘制学习曲线,这种做法是错误的。

真正正确的方式是,先分训练集和测试集,再归一化!

为什么?想想看归一化的处理手段,我们是使用数据中的最小值和极差在对数据进行压缩处理,如果我们在全数据集上进行归一化,那最小值和极差的选取是会参考测试集中的数据的状况的。因此,当我们归一化后,无论我们如何分割数据,都会由一部分测试集的信息被“泄露”给训练集,这会使得我们的模型效果被高估。

在现实业务中,我们只知道训练集的数据,不了解测试集究竟会长什么样,所以我们要利用训练集上的最小值和极差来归一化测试集。

1.8.3 通过 python 实现

data = [[-1,2],[-0.5,6],[0,10],[1,18]]
data=pd.DataFrame(data)(data-np.min(data,axis=0))/(np.max(data,axis=0)-np.min(data,axis=0))

1.8.4 通过 sklearn 实现

from sklearn.preprocessing import MinMaxScaler as mms
Xtrain,Xtest,Ytrain,Ytest=train_test_split(X,y,test_size=0.2,random_state=420)#归一化
MMS_01=mms().fit(Xtrain) #求训练集最大/小值
MMS_02=mms().fit(Xtest) #求测试集最大/小值#转换
X_train=MMS_01.transform(Xtrain)
X_test =MMS_02.transform(Xtest)score=[]
var=[]for i in range(1,20):clf=KNeighborsClassifier(n_neighbors=i)cvresult=CVS(clf,X_train,Ytrain,cv=5) # 交叉验证的每次得分score.append(cvresult.mean())var.append(cvresult.var())plt.plot(krange,score,color="k")
plt.plot(krange,np.array(score)+np.array(var)*2,c="red",linestyle="--")
plt.plot(krange,np.array(score)-np.array(var)*2,c="red",linestyle="--")
plt.show()

score.index(max(score))+1

8

最终的到 k 最优值为 8,无论 random_state 取什么值,最优 k 值不会相差太多。

把经过交叉验证、归一化处理之后,我们得到最优 k 为 8,放在归一化后的训练集重新建模,然后在归一化后的测试集中查看结果分数:

clf=KNeighborsClassifier(n_neighbors=8,weights='distance').fit(X_train,Ytrain)
score=clf.score(X_test,Ytest)
score

0.956140350877193

1.9 距离的惩罚

最近邻点距离远近修正在对未知分类过程中, “一点一票” 的规则是 KNN 模型优化的一个重要步骤。 也就是说,对于原始分类模型而言,在选取最近的 k 个元素之后,将参考这些点的所属类别,并对其进行简单计数,而在计数的过程中这些点 “一点一票” ,这些点每个点对分类目标点的分类过程中影响效力相同。

但这实际上是不公平的,就算是最近邻的 k 个点,每个点的分类目标点的距离仍然有远近之别,而近的点往往和目标分类点有更大的可能性属于同一类别( 该假设也是 KNN 分类模型的基本假设) 。

关于惩罚因子的选取有很多种方法, 最常用的就是根据每个最近邻

8.1 有监督学习算法相关推荐

  1. 机器学习理论入门:第二章 经典监督学习算法-决策树

    第二章 经典监督学习算法-决策树 一.决策树总体概览 概念:是在已知各种情况发生概率的基础上,通过构成决策树来求取净现值的期望值大于等于零的概率,评价项目风险,判断其可行性的决策分析方法,是直观运用概 ...

  2. 报名 | “阳奉阴违”的半监督学习算法 - Virtual Adversarial Training

    「论文共读」是由 PaperWeekly 发起的协同阅读小组.我们每周精选一篇优质好文,由学术大咖带大家解读论文并展开讨论,在碎片化时代坚持深度阅读. 本期论文共读由 PaperWeekly 社区用户 ...

  3. 论文共读 | “阳奉阴违”的半监督学习算法 - Virtual Adversarial Training

    「论文共读」是由 PaperWeekly 发起的协同阅读小组.我们每周精选一篇优质好文,由学术大咖带大家解读论文并展开讨论,在碎片化时代坚持深度阅读. 本期论文共读由 PaperWeekly 社区用户 ...

  4. ML之监督学习算法之分类算法一 ——— 决策树算法

    一.概述 决策树(decision tree)的一个重要任务是为了数据中所蕴含的知识信息,因此决策树可以使用不熟悉的数据集合,并从中提取出一系列规则,在这些机器根据数据创建规则时,就是机器学习的过程. ...

  5. 小白学数据:教你用Python实现简单监督学习算法

    转载自 小白学数据:教你用Python实现简单监督学习算法 今天,文摘菌想谈谈监督学习. 监督学习作为运用最广泛的机器学习方法,一直以来都是从数据挖掘信息的重要手段.即便是在无监督学习兴起的近日,监督 ...

  6. 更少的标签,更好的学习,谷歌半监督学习算法FixMatch

    点击我爱计算机视觉标星,更快获取CVML新技术 本文向大家推荐谷歌前段时间发布的论文 FixMatch: Simplifying Semi-Supervised Learning with Consi ...

  7. 厉害了!谷歌新发布的半监督学习算法降低4倍错误率

    点击我爱计算机视觉标星,更快获取CVML新技术 昨天跟大家分享了Facebook AI 提出10亿级数据规模的半监督图像分类模型,ImageNet测试精度高达81.2%!,引起了不少朋友的兴趣.虽说做 ...

  8. 机器学习----监督学习算法之决策树(Decision Tree)

    感谢Jack-Cui大佬的知识分享 机器学习专栏点击这里 目录 感谢Jack-Cui大佬的知识分享 0. 概述 1. 使用决策树做预测需要以下过程: 2. 决策树构建步骤 2.1 特征选择 2.1.1 ...

  9. 常见的简单的无监督学习算法总结

    本文仅对常见的无监督学习算法进行了简单讲述,其他的如自动编码器,受限玻尔兹曼机用于无监督学习,神经网络用于无监督学习等未包括.同时虽然整体上分为了聚类和降维两大类,但实际上这两类并非完全正交,很多地方 ...

  10. 卷积神经网络流程图_AAAI 2020 | 北大:图卷积中的多阶段自监督学习算法

    作者 | 孙科 编辑 | 唐里 本文对北京大学林宙辰团队完成,被AAAI-20录用的论文<Multi-Stage Self-Supervised Learning for Graph Convo ...

最新文章

  1. 湖大深大A级学科数超南开,华科文科胜过武大!泰晤士的首份高校评级结果,让人有点方...
  2. HTML5中的websocket实现直播
  3. 【BZOJ3172】单词(AC自动机)
  4. 使用VB.net建立excel文件
  5. 支付宝 PEM routines:PEM_read_bio:no start line
  6. 上海一公司向苹果索赔100亿,要求停售iPhone
  7. E/MediaPlayer: Should have subtitle controller already set
  8. java 日期年度 35变2035_连接IBM MQ原因码报2035的错误解决办法
  9. linux基础命令---bzip2
  10. MVC 如何设定默认默认路由为指定的Area下的某个action(笔记)
  11. macOS linux 并发测试工具 wrk
  12. WEB - 使用CSS 画一个正方体
  13. linux nano vim,修改ubuntu默认Nano编辑器为vim
  14. 今天上班穿了一只拖鞋和一只凉鞋
  15. 大数据平台分布式搭建-Hadoop集群配置
  16. FFmpeg入门详解之124:Qt5 FFmpeg单路网络摄像头采集预览
  17. 化工厂人员定位如何实现,可以解决哪些问题?
  18. Android Studio创建虚拟机选定指定位置
  19. python怎么修改字体_python怎么改字体 | 基础教程
  20. 计算机网络与协议实验VLAN配置,计算机网络实验三虚拟局域网vlan划分与配置

热门文章

  1. java中display中的属性_全面解析display属性
  2. checkSelfPermission总是返回PERMISSION_GRANTED
  3. gerund - 动名词
  4. 调用新浪接口查询IP地址
  5. 屏幕尺寸、分辨率、像素、PPT解释及其关系
  6. java读取加密excel_Java 加密和解密Excel文档
  7. 德州大学奥斯汀分校计算机专业排名,德州大学奥斯汀分校专业排名一览及最强专业推荐(USNEWS美国大学排名)...
  8. 如何用计算机完成一篇文稿制作步骤,第5章 计算机一级演示文稿制作经典教程.ppt...
  9. 大气科学领域必备的模型软件汇总丨WRF、WRF-CMAQ、WRF-Chem、WRF-Hydro、WRF DA、PMF、MCM、CAMx、SMOKE、CMIP6等
  10. H5如何获取内网IP和公网IP