day3-偏差和方差理论(相关案例代码理解分享)

day3-偏差和方差理论(相关案例代码理解分享)


心得体会

开源学习组织datawhale的组队学习第三天,学习了偏差和方差理论,对上次任务的基础模型进行优化,对模型超参数进行调优(调参),所有的代码都加了自己的注释与理解,完成了布置的作业任务,在这里感谢datawhale开源社区的小伙伴们给予的学习帮助,今后的学习也要一样加油呀

提示:以下是本篇文章正文内容,下面案例以及设计到的知识点均为datawhale开源组织提供

前言

我们建立机器学习的目的并不是为了在已有的数据集,也就是训练集上效果表现非常优异,我们希望建立的机器学习模型在未知且情况复杂的测试数据上表现优异,我们称这样的未出现在训练集的未知数据集成为测试数据集,简称测试集。我们希望模型在测试集上表现优异!因为假如我们根据股票市场前六个月的数据拟合一个预测模型,我们的目的不是为了预测以前这六个月越准越好,而是预测明天乃至未来的股价变化。

一、优化基础模型

1、训练均方误差与测试均方误差:

在回归中,我们最常用的评价指标为均方误差,即:
在这里插入图片描述

其中f ^ ( x i ) 是样本x i 应用建立的模型f ^ 预测的结果。如果我们所用的数据是训练集上的数据,那么这个误差为训练均方误差,如果我们使用测试集的数据计算的均方误差,我们称为测试均方误差。一般而言,我们并不关心模型在训练集上的训练均方误差,我们关心的是模型面对未知的样本集,即测试集上的测试误差,我们的目标是使得我们建立的模型在测试集上的测试误差最小。那我们如何选择一个测试误差最小的模型呢?这是个棘手的问题,因为在模型建立阶段,我们是不能得到测试数据的,比如:我们在模型未上线之前是不能拿到未知且真实的测试数据来验证我们的模型的。在这种情况下,为了简便起见,一些观点认为通过训练误差最小化来选择模型也是可行的。这种观点表面看上去是可行的,但是存在一个致命的缺点,那就是:一个模型的训练均方误差最小时,不能保证测试均方误差同时也很小。对于这种想法构造的模型,一般在训练误差达到最小时,测试均方误差一般很大!如图:
在这里插入图片描述
左:由真实函数f模拟产生的数据,用黑色曲线表示。三种f的估计:线性回归(橙色曲线),两条光滑样条拟合(绿色和蓝色曲线)。右:训练均方误差(灰色曲线),测试均方误差(红色曲线),所有方法都已使测试均方误差尽可能最小。方块分别对应左图的三种拟合中的训练均方误差和测试均方误差。

可以看到:当我们的模型的训练均方误差达到很小时,测试均方误差反而很大,但是我们寻找的最优的模型是测试均方误差达到最小时对应的模型,因此基于训练均方误差达到最小选择模型本质上是行不同的。正如上右图所示:模型在训练误差很小,但是测试均方误差很大时,我们称这种情况叫模型的过拟合

2、偏差-方差的权衡:

从上图的测试均方误差曲线可以看到:测试均方误差曲线呈现U型曲线,这表明了在测试误差曲线中有两种力量在互相博弈。可以证明:
在这里插入图片描述
也就是说,我们的测试均方误差的期望值可以分解为f ^ ( x 0 )的方差、f ^ ( x 0 ) 的偏差平方和误差项ϵ \epsilonϵ的方差。为了使得模型的测试均方误差达到最小值,也就是同时最小化偏差的平方和方差。由于我们知道偏差平方和方差本身是非负的,因此测试均方误差的期望不可能会低于误差的方差,因此我们称Var ⁡ ( ε ) 为建模任务的难度,这个量在我们的任务确定后是无法改变的,也叫做不可约误差。那么模型的方差和偏差的平方和究竟是什么呢?所谓模型的方差就是:用不同的数据集去估计f ff时,估计函数的改变量。举个例子:我们想要建立一个线性回归模型,可以通过输入中国人身高去预测我们的体重。但是显然我们没有办法把全中国13亿人做一次人口普查,拿到13亿人的身高体重去建立模型。我们能做的就是从13亿中抽1000个样本进行建模,我们对这个抽样的过程重复100遍,就会得到100个1000人的样本集。我们使用线性回归模型估计参数就能得到100个线性回归模型。由于样本抽取具有随机性,我们得到的100个模型不可能参数完全一样,那么这100个模型之间的差异就叫做方差。显然,我们希望得到一个稳定的模型,也就是在不同的样本集估计的模型都不会相差太大,即要求f的方差越小越好。一般来说,模型的复杂度越高,f的方差就会越大。 如加入二次项的模型的方差比线性回归模型的方差要大。

另一方面,模型的偏差是指:为了选择一个简单的模型去估计真实函数所带入的误差。假如真实的数据X与Y的关系是二次关系,但是我们选择了线性模型进行建模,那由于模型的复杂度引起的这种误差我们称为偏差,它的构成时复杂的。偏差度量了学习算法的期望预测与真实结果的偏离程度,即刻画了学习算法本身的拟合能力。偏差度量的是单个模型的学习能力,而方差度量的是同一个模型在不同数据集上的稳定性。“偏差-方差分解”说明:泛化性能是由学习算法的能力、数据的充分性以及学习任务本身的难度所共同决定的。给定学习任务,为了取得好的泛化性能,则需使偏差较小,即能够充分拟合数据,并且使方差较小,即使得数据扰动产生的影响小。

一般而言,增加模型的复杂度,会增加模型的方差,但是会减少模型的偏差,我们要找到一个方差–偏差的权衡,使得测试均方误差最小。

在这里插入图片描述

3、特征提取:

在前面的讨论中,我们已经明确一个目标,就是:我们要选择一个测试误差达到最小的模型。但是实际上我们很难对实际的测试误差做精确的计算,因此我们要对测试误差进行估计,估计的方式有两种:训练误差修正与交叉验证。
1、训练误差修正:
前面的讨论我们已经知道,模型越复杂,训练误差越小,测试误差先减后增。因此,我们先构造一个特征较多的模型使其过拟合,此时训练误差很小而测试误差很大,那这时我们加入关于特征个数的惩罚。因此,当我们的训练误差随着特征个数的增加而减少时,惩罚项因为特征数量的增加而增大,抑制了训练误差随着特征个数的增加而无休止地减小。具体的数学量如下:
在这里插入图片描述

2、交叉验证:
前面讨论的对训练误差修正得到测试误差的估计是间接方法,这种方法的桥梁是训练误差,而交叉验证则是对测试误差的直接估计。交叉验证比训练误差修正的优势在于:能够给出测试误差的一个直接估计。在这里只介绍K折交叉验证:我们把训练样本分成K等分,然后用K-1个样本集当做训练集,剩下的一份样本集为验证集去估计由K-1个样本集得到的模型的精度,这个过程重复K次取平均值得到测试误差的一个估计
在这里插入图片描述
在测试误差能够被合理的估计出来以后,我们做特征选择的目标就是:从p个特征中选择m个特征,使得对应的模型的测试误差的估计最小。对应的方法有:
最优子集选择:
(1) 记不含任何特征的模型为M 0,计算这个M 0 的测试误差。
(2) 在M 0基础上增加一个变量,计算p个模型的RSS,选择RSS最小的模型记作M1,并计算该模型M1​ 的测试误差。
(3)再增加变量,计算p-1个模型的RSS,并选择RSS最小的模型记作M 2,并计算该模型M 2 的测试误差。
(4) 重复以上过程知道拟合的模型有p个特征为止,并选择p+1个模型{ M 0 , M 1 , . . . , M p }中测试误差最小的模型作为最优模型。

向前逐步选择:
最优子集选择虽然在原理上很直观,但是随着数据特征维度p的增加,子集的数量为2^p,计算效率非常低下且需要的计算内存也很高,在大数据的背景下显然不适用。因此,我们需要把最优子集选择的运算效率提高,因此向前逐步选择算法的过程如下:
(1) 记不含任何特征的模型为M 0,计算这个M 0 的测试误差。
(2) 在M 0 基础上增加一个变量,计算p个模型的RSS,选择RSS最小的模型记作M 1,并计算该模型M1的测试误差。
(3) 在最小的RSS模型下继续增加一个变量,选择RSS最小的模型记作M 2,并计算该模型M 2的测试误差。
(4) 以此类推,重复以上过程知道拟合的模型有p个特征为止,并选择p+1个模型{ M 0 , M 1 , . . . , M p} 中测试误差最小的模型作为最优模型。

4、压缩估计(正则化):

除了刚刚讨论的直接对特征自身进行选择以外,我们还可以对回归的系数进行约束或者加罚的技巧对p个特征的模型进行拟合,显著降低模型方差,这样也会提高模型的拟合效果。具体来说,就是将回归系数往零的方向压缩,这也就是为什么叫压缩估计的原因了。
岭回归(L2正则化的例子):
在线性回归中,我们的损失函数为
在这里插入图片描述
我们在线性回归的损失函数的基础上添加对系数的约束或者惩罚,即:
在这里插入图片描述
调节参数λ的大小是影响压缩估计的关键,λ越大,惩罚的力度越大,系数则越趋近于0,反之,选择合适的λ对模型精度来说十分重要。岭回归通过牺牲线性回归的无偏性降低方差,有可能使得模型整体的测试误差较小,提高模型的泛化能力。

Lasso回归(L1正则化的例子):
岭回归的一个很显著的特点是:将模型的系数往零的方向压缩,但是岭回归的系数只能呢个趋于0但无法等于0,换句话说,就是无法做特征选择。能否使用压缩估计的思想做到像特征最优子集选择那样提取出重要的特征呢?答案是肯定的!我们只需要对岭回归的优化函数做小小的调整就行了,我们使用系数向量的L1范数替换岭回归中的L2范数:
在这里插入图片描述
为什么Losso能做到特征选择而岭回归却不能呢个做到呢?(如图:左边为lasso,右边为岭回归)
在这里插入图片描述
椭圆形曲线为RSS等高线,菱形和圆形区域分别代表了L1和L2约束,Lsaao回归和岭回归都是在约束下的回归,因此最优的参数为椭圆形曲线与菱形和圆形区域相切的点。但是Lasso回归的约束在每个坐标轴上都有拐角,因此当RSS曲线与坐标轴相交时恰好回归系数中的某一个为0,这样就实现了特征提取。反观岭回归的约束是一个圆域,没有尖点,因此与RSS曲线相交的地方一般不会出现在坐标轴上,因此无法让某个特征的系数为0,因此无法做到特征提取。

5、降维:

到目前为止,我们所讨论的方法对方差的控制有两种方式:一种是使用原始变量的子集,另一种是将变量系数压缩至零。但是这些方法都是基于原始特征x 1 , . . . , x p 得到的,现在我们探讨一类新的方法:将原始的特征空间投影到一个低维的空间实现变量的数量变少,如:将二维的平面投影至一维空间。机器学习领域中所谓的降维就是指采用某种映射方法,将原高维空间中的数据点映射到低维度的空间中。降维的本质是学习一个映射函数 f : x->y,其中x是原始数据点的表达,目前最多使用向量表达形式。 y是数据点映射后的低维向量表达,通常y的维度小于x的维度(当然提高维度也是可以的)。f可能是显式的或隐式的、线性的或非线性的。目前大部分降维算法处理向量表达的数据,也有一些降维算法处理高阶张量表达的数据。之所以使用降维后的数据表示是因为在原始的高维空间中,包含有冗余信息以及噪音信息,在实际应用例如图像识别中造成了误差,降低了准确率;而通过降维,我们希望减少 冗余信息 所造成的误差,提高识别(或其他应用)的精度。又或者希望通过降维算法来寻找数据内部的本质结构特征。在很多算法中,降维算法成为了数据预处理的一部分,如PCA。事实上,有一些算法如果没有降维预处理,其实是很难得到很好的效果的。 (摘自:rosenor1博客)

主成分分析(PCA):
主成分分析的思想:通过最大投影方差 将原始空间进行重构,即由特征相关重构为无关,即落在某个方向上的点(投影)的方差最大。在进行下一步推导之前,我们先把样本均值和样本协方差矩阵推广至矩阵形式:
在这里插入图片描述
在这里插入图片描述
可以看到:λ为S ^2 的特征值,u 1为S ^2的特征向量。因此我们只需要对中心化后的协方差矩阵进行特征值分解,得到的特征向量即为投影方向。如果需要进行降维,那么只需要取p的前M个特征向量即可。

6、案例

(1) 特征提取的实例:向前逐步回归
案例来源:https://blog.csdn.net/weixin_44835596/article/details/89763300
根据AIC准则定义向前逐步回归进行变量筛选

from statsmodels.formula.api import ols
#定义向前逐步回归函数
def forward_select(data,target):
    variate=set(data.columns)  #将字段名转换成字典类型
    variate.remove(target)  #去掉因变量的字段名
    selected=[]
    current_score,best_new_score=float('inf'),float('inf')  #目前的分数和最好分数初始值都为无穷大(因为AIC越小越好)
    #循环筛选变量
    while variate:
        aic_with_variate=[]
        for candidate in variate:  #逐个遍历自变量
            formula="{}~{}".format(target,"+".join(selected+[candidate]))  #将自变量名连接起来
            aic=ols(formula=formula,data=data).fit().aic  #利用ols训练模型得出aic值
            aic_with_variate.append((aic,candidate))  #将第每一次的aic值放进空列表
        aic_with_variate.sort(reverse=True)  #降序排序aic值
        best_new_score,best_candidate=aic_with_variate.pop()  #最好的aic值等于删除列表的最后一个值,以及最好的自变量等于列表最后一个自变量
        if current_score>best_new_score:  #如果目前的aic值大于最好的aic值
            variate.remove(best_candidate)  #移除加进来的变量名,即第二次循环时,不考虑此自变量了
            selected.append(best_candidate)  #将此自变量作为加进模型中的自变量
            current_score=best_new_score  #最新的分数等于最好的分数
            print("aic is {},continuing!".format(current_score))  #输出最小的aic值
        else:
            print("for selection over!")
            break
    formula="{}~{}".format(target,"+".join(selected))  #最终的模型式子
    print("final formula is {}".format(formula))
    model=ols(formula=formula,data=data).fit()
    return(model)
'''
import statsmodels.api as sm #最小二乘
from statsmodels.formula.api import ols #加载ols模型
forward_select(data=boston_data,target="Price")

在这里插入图片描述

lm=ols("Price~LSTAT+RM+PTRATIO+DIS+NOX+CHAS+B+ZN+CRIM+RAD+TAX",data=boston_data).fit()
lm.summary()
'''
表格的几个参数
Dep.Variable : 使用的参数值
Model:使用的模型
method:使用的方法
Data:时间
No.Observations:样本数据个数
Df Residuals:残差的自由度
DF Model:模型的自由度
R-squared:R方值
Adj.R-squared:调整后的R方
F-statistic :F统计量
Prob(F-statistic):F统计量的p值
Log-Likelihood:似然度
AIC BIC:衡量模型优良度的指标,越小越好
const:截距项
P>|t| :t检验的p值,如果p值小于0.05 那么我们就认为变量是显著的
'''

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
(2)岭回归实例分享
sklearn.linear_model.ridge_regression(X, y, alpha, *, sample_weight=None, solver=‘auto’, max_iter=None, tol=0.001, verbose=0, random_state=None, return_n_iter=False, return_intercept=False, check_input=True)
https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.ridge_regression.html?highlight=rid#sklearn.linear_model.ridge_regression

'''
alpha:较大的值表示更强的正则化。浮点数
sample_weight:样本权重,默认无。
solver:求解方
'''
from sklearn import linear_model
reg_rid = linear_model.Ridge(alpha=.5)
reg_rid.fit(X,y)
reg_rid.score(X,y)

(3)Lasso实例分享
class sklearn.linear_model.Lasso(alpha=1.0, *, fit_intercept=True, normalize=False, precompute=False, copy_X=True, max_iter=1000, tol=0.0001, warm_start=False, positive=False, random_state=None, selection=‘cyclic’)
https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.Lasso.html?highlight=lasso#sklearn.linear_model.Lasso

'''
alpha:正则化强度,1.0代表标准最小二乘。
fit_intercept:是否计算模型截距。默认true。
normalize:是否标准化,默认false。
positive:是否强制系数为正,默认false。
'''
from sklearn import linear_model
reg_lasso = linear_model.Lasso(alpha = 0.5)
reg_lasso.fit(X,y)
reg_lasso.score(X,y)

二、对模型超参数进行调优(调参)

在刚刚的讨论中,我们似乎对模型的优化都是对模型算法本身的改进,比如:岭回归对线性回归的优化在于在线性回归的损失函数中加入L2正则化项从而牺牲无偏性降低方差。但是,大家是否想过这样的问题:在L2正则化中参数λ \lambdaλ应该选择多少?是0.01、0.1、还是1?到目前为止,我们只能凭经验或者瞎猜,能不能找到一种方法找到最优的参数λ \lambdaλ?事实上,找到最佳参数的问题本质上属于最优化的内容,因为从一个参数集合中找到最佳的值本身就是最优化的任务之一,我们脑海中浮现出来的算法无非就是:梯度下降法、牛顿法等无约束优化算法或者约束优化算法,但是在具体验证这个想法是否可行之前,我们必须先认识两个最本质概念的区别。

(1)参数与超参数
我们很自然的问题就是岭回归中的参数λ 和参数w之间有什么不一样?事实上,参数w是我们通过设定某一个具体的λ后使用类似于最小二乘法、梯度下降法等方式优化出来的,我们总是设定了λ是多少后才优化出来的参数w。因此,类似于参数w一样,使用最小二乘法或者梯度下降法等最优化算法优化出来的数我们称为参数,类似于λ一样,我们无法使用最小二乘法或者梯度下降法等最优化算法优化出来的数我们称为超参数。
模型参数是模型内部的配置变量,其值可以根据数据进行估计。

  • 进行预测时需要参数。
  • 它参数定义了可使用的模型。
  • 参数是从数据估计或获悉的。
  • 参数通常不由编程者手动设置。
  • 参数通常被保存为学习模型的一部分。
  • 参数是机器学习算法的关键,它们通常由过去的训练数据中总结得出 。
  • 模型超参数是模型外部的配置,其值无法从数据中估计。
  • 超参数通常用于帮助估计模型参数。
  • 超参数通常由人工指定。
  • 超参数通常可以使用启发式设置。
  • 超参数经常被调整为给定的预测建模问题。

那本次调整的内容是超参数,也就是取不同的超参数的值对于模型的性能有不同的影响。

(2)网格搜索GridSearchCV()
网格搜索:https://scikitlearn.org/stable/modules/generated/sklearn.model_selection.GridSearchCV.html?highlight=gridsearchcv#sklearn.model_selection.GridSearchCV
网格搜索结合管道:https://scikitlearn.org/stable/auto_examples/compose/plot_compare_reduction.html?highlight=gridsearchcv
网格搜索的思想非常简单,比如你有2个超参数需要去选择,那你就把所有的超参数选择列出来分别做排列组合。举个例子:λ = 0.01 , 0.1 , 1.0 和α=0.01,0.1,1.0,你可以做一个排列组合,即:{[0.01,0.01],[0.01,0.1],[0.01,1],[0.1,0.01],[0.1,0.1],[0.1,1.0],[1,0.01],[1,0.1],[1,1]} ,然后针对每组超参数分别建立一个模型,然后选择测试误差最小的那组超参数。换句话说,我们需要从超参数空间中寻找最优的超参数,很像一个网格中找到一个最优的节点,因此叫网格搜索。
(3)随机搜索 RandomizedSearchCV()
https://scikitlearn.org/stable/modules/generated/sklearn.model_selection.RandomizedSearchCV.html?highlight=randomizedsearchcv#sklearn.model_selection.RandomizedSearchCV
网格搜索相当于暴力地从参数空间中每个都尝试一遍,然后选择最优的那组参数,这样的方法显然是不够高效的,因为随着参数类别个数的增加,需要尝试的次数呈指数级增长。有没有一种更加高效的调优方式呢?那就是使用随机搜索的方式,这种方式不仅仅高校,而且实验证明,随机搜索法结果比稀疏化网格法稍好(有时候也会极差,需要权衡)。参数的随机搜索中的每个参数都是从可能的参数值的分布中采样的。与网格搜索相比,这有两个主要优点:

  • 可以独立于参数数量和可能的值来选择计算成本。
  • 添加不影响性能的参数不会降低效率。

使用SVR的例子,结合管道来进行调优

# 我们先来对未调参的SVR进行评价:
from sklearn.svm import SVR     # 引入SVR类
from sklearn.pipeline import make_pipeline   # 引入管道简化学习流程
from sklearn.preprocessing import StandardScaler # 由于SVR基于距离计算,引入对数据进行标准化的类
from sklearn.model_selection import GridSearchCV  # 引入网格搜索调优
from sklearn.model_selection import cross_val_score # 引入K折交叉验证
from sklearn import datasets


boston = datasets.load_boston()     # 返回一个类似于字典的类
X = boston.data
y = boston.target
features = boston.feature_names
'''
StandardScaler():先通过计算训练集中特征的均值、标准差,对每个特征进行独立居中和缩放。然后,将平均值和标准偏差存储起来,在以后的测试集上有相同比例来缩放。
make_pipeline():创建管道并根据每个步骤所属的类为其自动命名
这里进行缩放操作后,使用SVR,并进行10折交叉验证
'''
pipe_SVR = make_pipeline(StandardScaler(),SVR())
score1 = cross_val_score(estimator=pipe_SVR,
                          X = X,
                          y = y,
                          scoring = 'r2',
                          cv = 10)       # 10折交叉验证
print("CV accuracy: %.3f +/- %.3f" % ((np.mean(score1)),np.std(score1)))

在这里插入图片描述

# 下面我们使用网格搜索来对SVR调参:
from sklearn.pipeline import Pipeline
# 构建管道
pipe_svr = Pipeline([("StandardScaler",StandardScaler()),("svr",SVR())])
param_range = [0.0001,0.001,0.01,0.1,1.0,10.0,100.0,1000.0]
# 设定param_grid参数
param_grid = [{"svr__C":param_range,"svr__kernel":["linear"]},  # 注意__是指两个下划线,一个下划线会报错的
             {"svr__C":param_range,"svr__gamma":param_range,"svr__kernel":["rbf"]}]
'''
其中:
(1)C: 目标函数的惩罚系数C,用来平衡分类间隔margin和错分样本的,default C = 1.0; 
(2)kernel:参数选择有RBF, Linear, Poly, Sigmoid, 默认的是"RBF"; 
(3)degree:if you choose 'Poly' in param 2, this is effective, degree决定了多项式的最高次幂; 
(4)gamma:核函数的系数('Poly', 'RBF' and 'Sigmoid'), 默认是gamma = 1 / n_features; 
'''
# 进行网格搜索
gs = GridSearchCV(estimator=pipe_svr,
                            param_grid = param_grid,
                            scoring = 'r2',
                            cv = 10)       # 10折交叉验证
gs = gs.fit(X,y)
print("网格搜索最优得分:",gs.best_score_)
print("网格搜索最优参数组合:\n",gs.best_params_)

在这里插入图片描述

# 下面我们使用随机搜索来对SVR调参:
from sklearn.model_selection import RandomizedSearchCV
from scipy.stats import uniform  # 引入均匀分布设置参数
# 构建管道
pipe_svr = Pipeline([("StandardScaler",StandardScaler()),("svr",SVR())])
distributions = dict(svr__C=uniform(loc=1.0, scale=4),    # 构建连续参数的分布
                     svr__kernel=["linear","rbf"],                                   # 离散参数的集合
                    svr__gamma=uniform(loc=0, scale=4))

# 进行随机搜索
rs = RandomizedSearchCV(estimator=pipe_svr,
                        param_distributions = distributions,
                        scoring = 'r2',
                        cv = 10)       # 10折交叉验证
rs = rs.fit(X,y)
print("随机搜索最优得分:",rs.best_score_)
print("随机搜索最优参数组合:\n",rs.best_params_)

在这里插入图片描述

三、补充知识

令你事半功倍的pipeline处理机制

pipeline可以将许多算法模型串联起来,形成一个典型的机器学习问题工作流。
在这里插入图片描述

  • Pipeline处理机制就像是把所有模型塞到一个管子里,然后依次对数据进行处理,得到最终的分类结果。例如模型1可以是一个数据标准化处理,模型2可以是特征选择模型或者特征提取模型,模型3可以是一个分类器或者预测模型(模型不一定非要三个,根据自己实际需要)。

  • Pipleline中最后一个之外的所有评估器都必须是变换器,最后一个评估器可以是任意类型(transformer,classifier,regresser),若最后一个评估器是分类器,则整个pipeline就可以作为分类器使用,如果最后一个estimator是个回归器,则整个pipeline就可以作为回归器使用。

  • make_pipeline函数是Pipeline类的简单实现,只需传入每个step的类实例即可,不需自己命名,自动将类的小写设为该step的名。
    make_pipeline(StandardScaler(),GaussianNB())

四、作业

https://blog.csdn.net/Codewith_jing/article/details/118877703?spm=1001.2014.3001.5501
https://blog.csdn.net/weixin_44731995/article/details/115103652
https://zhuanlan.zhihu.com/p/44872686

(1)请用一个具体的案例解释什么是偏差和方差

使用特定模型对一个测试样本进行预测,就像打靶一样。

靶心(红点)是测试样本的真实值,测试样本的y(橙色点)是真实值加上噪音,特定模型重复多次训练会得到多个具体的模型,每一个具体模型对测试样本进行一次预测,就在靶上打出一个预测值(图上蓝色的点)。所有预测值的平均就是预测值的期望(较大的浅蓝色点),浅蓝色的圆圈表示预测值的离散程度,即预测值的方差。预测值与真实值的差值即为偏差

图上的三条橙色线段分别为:预测值的偏差、预测值的方差、样本噪音。
在这里插入图片描述

(2)偏差与方差和误差之间的关系

  • 模型训练不足时,拟合能力不够强,训练数据的扰动(不同训练集之间的差异)不足以使学习器产生显著变化,此时偏差主导泛化误差—欠拟合;
  • 模型训练程度加深,拟合能力增强,训练数据发生的扰动渐渐能被学习器学到,方差逐渐主导泛化误差—过拟合;
  • 随着模型复杂度的提升,偏差逐渐减小,方差逐渐增大

(3)训练误差与测试误差之间的联系和区别,如何估计测试误差

  • 训练误差是指模型在训练集上的错分样本比率,测试误差就是模型在测试集上的错分率
    联系:都是数据集上错分样本的比率
    区别:训练误差在训练集上,测试误差在测试集上

  • 对测试误差进行估计,估计的方式有两种:训练误差修正与交叉验证。
    1、训练误差修正:
    前面的讨论我们已经知道,模型越复杂,训练误差越小,测试误差先减后增。因此,我们先构造一个特征较多的模型使其过拟合,此时训练误差很小而测试误差很大,那这时我们加入关于特征个数的惩罚。因此,当我们的训练误差随着特征个数的增加而减少时,惩罚项因为特征数量的增加而增大,抑制了训练误差随着特征个数的增加而无休止地减小。
    2、交叉验证:
    前面讨论的对训练误差修正得到测试误差的估计是间接方法,这种方法的桥梁是训练误差,而交叉验证则是对测试误差的直接估计。交叉验证比训练误差修正的优势在于:能够给出测试误差的一个直接估计。在这里只介绍K折交叉验证:我们把训练样本分成K等分,然后用K-1个样本集当做训练集,剩下的一份样本集为验证集去估计由K-1个样本集得到的模型的精度,这个过程重复K次取平均值得到测试误差的一个估计

(4)岭回归和LASSO回归的异同点

对OLS进行范数1正则化叫Lasso回归。
对OLS进行范数2正则化叫岭回归。

区别:
Lasso由于使用L1正则项,所以具有一定的特征选择功能,因为L1正则倾向于产生稀疏解,它可以将一些“对标签没有用处”的特征对应的系数压缩为0,进而将对结果有较大影响的特征突显出来,而岭回归中L2正则项不具备这个功能,它只会讲一些无关特征的系数降到一个较小的值,但不会降为0。并且L2正则有解析解,L1没有。
相同:
都可以用来解决标准线性回归的过拟合问题

(5)如果使用pca 降维前是一个三维的椭球,那么把该图形降维成二维是一个什么样的图形

若各投影点方差较大的话为椭圆,方差较小则为圆形

(6)尝试使用对偶理论和核函数对pca进行非线性拓展,使得pca变成非线性降维

(7)本教程讲述的三种模型简化的方法之间有什么异同点

相同点:三种模型简化的方法均是通过减小方差来减小测试误差的

不同点:不同点在于

  • 特征选择中是使用原始变量的子集从而控制方差;
  • 压缩估计(正则化)中通过将变量系数压缩至零从而控制方差
  • 降维中通过将原始的特征空间投影到一个低维的空间实现变量的数量变少从而控制方差。前两种方法都是基于原始特征的方法,而第三种模型则是将原始的特征空间投影到一个低维的空间再进行特征的选择。

(8)尝试使用sklearn,对一组数据先进行特征的简化(使用三种方式),再使用回归模型,最后使用网格搜索调参,观察三种方法的优劣。

我们先来对未调参的SVR进行评价:

# 我们先来对未调参的SVR进行评价: 
from sklearn.svm import SVR     # 引入SVR类
import pandas as pd
from sklearn.pipeline import make_pipeline   # 引入管道简化学习流程
from sklearn.preprocessing import StandardScaler # 由于SVR基于距离计算,引入对数据进行标准化的类
from sklearn.model_selection import GridSearchCV  # 引入网格搜索调优
from sklearn.model_selection import cross_val_score # 引入K折交叉验证
from sklearn import datasets
import statsmodels.api as sm #最小二乘
from statsmodels.formula.api import ols #加载ols模型

# 这里采用熟悉的波士顿房价预测数据集
boston = datasets.load_boston()     # 返回一个类似于字典的类
X = boston.data
y = boston.target
features = boston.feature_names
boston_data = pd.DataFrame(X,columns=features)
boston_data["Price"] = y
pipe_SVR = make_pipeline(StandardScaler(),SVR())
score1 = cross_val_score(estimator=pipe_SVR,
                         X = X,
                         y = y,
                         scoring = 'r2',
                         cv = 10)       # 10折交叉验证
print("CV accuracy: %.3f +/- %.3f" % ((np.mean(score1)),np.std(score1)))

在这里插入图片描述

定义向前逐步回归函数,再使用回归模型,最后使用网格搜索调参

#定义向前逐步回归函数
def forward_select(data,target):
    variate=set(data.columns)  #将字段名转换成字典类型
    variate.remove(target)  #去掉因变量的字段名
    selected=[]
    current_score,best_new_score=float('inf'),float('inf')  #目前的分数和最好分数初始值都为无穷大(因为AIC越小越好)
    #循环筛选变量
    while variate:
        aic_with_variate=[]
        for candidate in variate:  #逐个遍历自变量
            formula="{}~{}".format(target,"+".join(selected+[candidate]))  #将自变量名连接起来
            aic=ols(formula=formula,data=data).fit().aic  #利用ols训练模型得出aic值
            aic_with_variate.append((aic,candidate))  #将第每一次的aic值放进空列表
        aic_with_variate.sort(reverse=True)  #降序排序aic值
        best_new_score,best_candidate=aic_with_variate.pop()  #最好的aic值等于删除列表的最后一个值,以及最好的自变量等于列表最后一个自变量
        if current_score>best_new_score:  #如果目前的aic值大于最好的aic值
            variate.remove(best_candidate)  #移除加进来的变量名,即第二次循环时,不考虑此自变量了
            selected.append(best_candidate)  #将此自变量作为加进模型中的自变量
            current_score=best_new_score  #最新的分数等于最好的分数
            print("aic is {},continuing!".format(current_score))  #输出最小的aic值
        else:
            print("for selection over!")
            break
    formula="{}~{}".format(target,"+".join(selected))  #最终的模型式子
    print("final formula is {}".format(formula))
    model=ols(formula=formula,data=data).fit()
    return(model)

forward_select_model = forward_select(data=boston_data,target="Price")
X_forward = boston_data.loc[:,['LSTAT','RM','PTRATIO','DIS','NOX','CHAS','B','ZN','CRIM','RAD','TAX']]
Y_forward = y

# 下面我们使用网格搜索来对SVR调参:
from sklearn.pipeline import Pipeline
pipe_svr = Pipeline([("StandardScaler",StandardScaler()),
                                                         ("svr",SVR())])
param_range = [0.0001,0.001,0.01,0.1,1.0,10.0,100.0,1000.0]
param_grid = [{"svr__C":param_range,"svr__kernel":["linear"]},  # 注意__是指两个下划线,一个下划线会报错的
                            {"svr__C":param_range,"svr__gamma":param_range,"svr__kernel":["rbf"]}]
gs = GridSearchCV(estimator=pipe_svr,
                  param_grid = param_grid,
                  scoring = 'r2',
                  cv = 10)       # 10折交叉验证
gs = gs.fit(X_forward,Y_forward)
print("网格搜索最优得分:",gs.best_score_)
print("网格搜索最优参数组合:\n",gs.best_params_)

在这里插入图片描述

总结

以上就是今天要讲的内容,本文仅仅简单介绍了偏差和方差理论,对上次任务的基础模型进行优化,对模型超参数进行调优(调参),也实践了相关模型的基础调用代码,复现了一些案例,做了本人的理解与注释,在这里再次感谢datawhale开源社区的小伙伴们的学习帮助,如更多的学习资料请联系datawhale参加组队学习获取。

相关资料:
【1】教学视频:https://www.bilibili.com/video/BV1Mb4y1o7ck?from=search&seid=6085778383215596866
【2】教案:https://github.com/datawhalechina/ensemble-learning
【3】datawhale开源学习社区:http://datawhale.club/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值