前言

拟合定义

  • 过拟合:一个假设在训练数据上能够获得比其他假设更好的拟合, 但是在测试数据集上却不能很好地拟合数据,此时认为这个假设出现了过拟合的现象。(模型过于复杂)
  • 欠拟合:一个假设在训练数据上不能获得更好的拟合,并且在测试数据集上也不能很好地拟合数据,此时认为这个假设出现了欠拟合的现象。(模型过于简单)

mark

而模型变复杂的原因,是因为在训练模型的过程中数据中存在很多无用的特征,因为在现实过程中很多东西的特征与目标值的关系并不是线性关系

原因以及解决办法

  • 欠拟合原因以及解决办法
    • 原因:学习到数据的特征过少
    • 解决办法:
      • 1)添加其他特征项,有时候我们模型出现欠拟合的时候是因为特征项不够导致的,可以添加其他特征项来很好地解决。例如,“组合”、“泛化”、“相关性”三类特征是特征添加的重要手段,无论在什么场景,都可以照葫芦画瓢,总会得到意想不到的效果。除上面的特征之外,“上下文特征”、“平台特征”等等,都可以作为特征添加的首选项。
      • 2)添加多项式特征,这个在机器学习算法里面用的很普遍,例如将线性模型通过添加二次项或者三次项使模型泛化能力更强。
  • 过拟合原因以及解决办法
    • 原因:原始特征过多,存在一些嘈杂特征, 模型过于复杂是因为模型尝试去兼顾各个测试数据点
    • 解决办法:
      • 1)重新清洗数据,导致过拟合的一个原因也有可能是数据不纯导致的,如果出现了过拟合就需要我们重新清洗数据。
      • 2)增大数据的训练量,还有一个原因就是我们用于训练的数据量太小导致的,训练数据占总数据的比例过小。
      • 3)正则化
      • 4)减少特征维度,防止维灾难

正则化

什么是正则化

在解决回归过拟合中,我们选择正则化。但是对于其他机器学习算法如分类算法来说也会出现这样的问题,除了一些算法本身作用之外(决策树、神经网络),我们更多的也是去自己做特征选择,包括之前说的删除、合并一些特征

mark

如何解决

mark

在学习的时候,数据提供的特征有些影响模型复杂度或者这个特征的数据点异常较多,所以算法在学习的时候尽量减少这个特征的影响(甚至删除某个特征的影响),这就是正则化

注:调整时候,算法并不知道某个特征影响,而是去调整参数得出优化的结果

正则化类别

  • L2正则化
    • 作用:可以使得其中一些W的都很小,都接近于0,削弱某个特征的影响
    • 优点:越小的参数说明模型越简单,越简单的模型则越不容易产生过拟合现象
    • Ridge回归
  • L1正则化
    • 作用:可以使得其中一些W的值直接为0,删除这个特征的影响
    • LASSO回归

维灾难

维灾难的介绍可以看这篇文章的科普

https://blog.csdn.net/zbc1090549839/article/details/38929215

正则化线性模型

  • Ridge Regression 岭回归
  • Lasso 回归
  • Elastic Net 弹性网络

1 Ridge Regression (岭回归)

岭回归是线性回归的正则化版本,即在原来的线性回归的 cost function 中添加正则项(regularization term):

mark

以达到在拟合数据的同时,使模型权重尽可能小的目的,岭回归代价函数:

mark

  • α=0:岭回归退化为线性回归

2 Lasso Regression(Lasso 回归)

Lasso 回归是线性回归的另一种正则化版本,正则项为权值向量的ℓ1范数。

Lasso回归的代价函数 :

mark

【注意 】

  • Lasso Regression 的代价函数在 θi=0处是不可导的.
  • 解决方法:在θi=0处用一个次梯度向量(subgradient vector)代替梯度,如下式
  • Lasso Regression 的次梯度向量

mark

Lasso Regression 有一个很重要的性质是:倾向于完全消除不重要的权重。

例如:当α 取值相对较大时,高阶多项式退化为二次甚至是线性:高阶多项式特征的权重被置为0。

也就是说,Lasso Regression 能够自动进行特征选择,并输出一个稀疏模型(只有少数特征的权重是非零的)。

3 Elastic Net (弹性网络)

弹性网络在岭回归和Lasso回归中进行了折中,通过 混合比(mix ratio) r 进行控制:

  • r=0:弹性网络变为岭回归
  • r=1:弹性网络便为Lasso回归

弹性网络的代价函数 :

mark

一般来说,我们应避免使用朴素线性回归,而应对模型进行一定的正则化处理,那如何选择正则化方法呢?

小结:

  • 常用:岭回归

  • 假设只有少部分特征是有用的:

    • 弹性网络
    • Lasso
    • 一般来说,弹性网络的使用更为广泛。因为在特征维度高于训练样本数,或者特征是强相关的情况下,Lasso回归的表现不太稳定。
  • api:

    from sklearn.linear_model import Ridge, ElasticNet, Lasso

线性模型改进–(岭回归)

API使用

  • sklearn.linear_model.Ridge(alpha=1.0, fit_intercept=True,solver=“auto”, normalize=False)
    • 具有l2正则化的线性回归
    • alpha:正则化力度,也叫 λ
      • λ取值:0~1 1~10
    • solver:会根据数据自动选择优化方法
      • sag:如果数据集、特征都比较大,选择该随机梯度下降优化
    • normalize:数据是否进行标准化
      • normalize=False:可以在fit之前调用preprocessing.StandardScaler标准化数据
    • Ridge.coef_:回归权重
    • Ridge.intercept_:回归偏置

Ridge方法相当于SGDRegressor(penalty=‘l2’, loss=“squared_loss”),只不过SGDRegressor实现了一个普通的随机梯度下降学习,推荐使用Ridge(实现了SAG)

  • sklearn.linear_model.RidgeCV(_BaseRidgeCV, RegressorMixin)
    • 具有l2正则化的线性回归,可以进行交叉验证
    • coef_:回归系数

正则化程度的变化,对结果的影响

mark

  • 正则化力度越大,权重系数会越小

  • 正则化力度越小,权重系数会越大

波士顿案例

代码示例:

使用Ridge

from sklearn.metrics import mean_squared_error
from sklearn.model_selection import train_test_split
from sklearn.datasets import load_boston
from sklearn.linear_model import Ridge

#加载数据集
data=load_boston()
#数据分割
x_train,x_test,y_train,y_test=train_test_split(data.data,data.target,random_state=22,test_size=0.2)
#模型训练
estimator=Ridge(alpha=0,normalize=True)
estimator.fit(x_train,y_train)
#打印预测值
y_pre=estimator.predict(x_test)
score=estimator.score(x_test,y_test)
#模型评估
print("准确率 \n",score)
print("系数 \n",estimator.coef_)
print("偏置 \n",estimator.intercept_)
error = mean_squared_error(y_test, y_pre)
print("误差为:\n", error)

注:当我们在Ridge(normalize=True)创建实例时,选择normaliz为True时,我们就可以省略标准化数据的代码

运行结果:

准确率 
0.7657465943591123
系数
[-1.01199845e-01 4.67962110e-02 -2.06902678e-02 3.58072311e+00
-1.71288922e+01 3.92207267e+00 -5.67997339e-03 -1.54862273e+00
2.97156958e-01 -1.00709587e-02 -7.78761318e-01 9.87125185e-03
-5.25319199e-01]
偏置
32.42825286699124
误差为:
20.770684784270024

使用RidgeCV:

代码示例:

from sklearn.metrics import mean_squared_error
from sklearn.model_selection import train_test_split
from sklearn.datasets import load_boston
from sklearn.linear_model import RidgeCV

#加载数据集
data=load_boston()
#切分数据集
x_train,x_test,y_train,y_test=train_test_split(data.data,data.target,random_state=22,test_size=0.2)

#模型训练
estimator=RidgeCV(alphas=(1,0.1, 10,0.55,9),normalize=True)
estimator.fit(x_train,y_train)
#打印预测值
y_pre=estimator.predict(x_test)
score=estimator.score(x_test,y_test)
#模型评估
print("准确率 \n",score)
print("系数 \n",estimator.coef_)
print("偏置 \n",estimator.intercept_)
error = mean_squared_error(y_test, y_pre)
print("误差为:\n", error)

使用RidgeCV这个模型,我们在选择alphas时可以输入多个alphas值,进行交叉验证

运行结果为:

准确率 
0.755640759192834
系数
[-7.10636292e-02 2.81853030e-02 -7.07760829e-02 3.72392633e+00
-1.05710401e+01 4.09961387e+00 -9.32546827e-03 -1.06310611e+00
1.37548657e-01 -3.58696599e-03 -6.85595220e-01 9.37914747e-03
-4.66378501e-01]
偏置
23.328276195586888
误差为:
21.666744827223443