Lesson 6.3 正则化与 sklearn 逻辑回归参数详解
阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
文章目录
在了解了 sklearn 的一些常用的操作之后接下来我们来详细学习关于正则化的相关内容并对 sklearn 中的逻辑回归的参数进行详细解释。 需要注意的是由于 sklearn 内部参数的一致性有许多参数不仅是逻辑回归的参数更是大多数分类模型的通用参数。
import numpy as np
import pandas as pd
import matplotlib as mpl
import matplotlib. pyplot as plt
from ML_basic_function import *
一、过拟合、正则化、特征衍生与特征重要性评估
在上一篇文章当中我们已经尝试着利用逻辑回归构建了一个多分类模型得益于 sklearn 中良好的默认参数设置我们在对 sklearn 中内部构造基本没有任何了解的情况下就完成了相关模型的建模。 但需要知道的事逻辑回归作为一个诞生时间较早并且拥有深厚统计学背景的模型其实是拥有非常多变种应用方法的虽然我们在 Lesson 4 中就逻辑回归的基本原理、基础公式以及分类性能进行了较长时间的探讨但实际上逻辑回归算法的模型形态和应用方式远不仅于此。 在 sklearn 中则提供了非常丰富的逻辑回归的可选的算法参数相当于是提供了一个集大成者的逻辑回归模型。 当然首先我们需要介绍一个非常重要的机器学习中的概念正则化。 在逻辑回归的说明文档中第一个参数就是关于正则化的一个选项
from sklearn. linear_model import LogisticRegression
LogisticRegression?
也就是 penalty=‘l2’ 一项而正则化也是机器学习中非常通用的一项操作。 接下来我们就正则化的相关内容展开讨论。
1. 正则化Regularization的基本概念
从说明文档中得知就是在 sklearn 中逻辑回归模型是默认进行正则化的即上文所述 “Regularization is applied by default”这是一种在机器学习建模过程中常见的用法但并非统计学常用方法。 据此我们也知道了统计学和机器学习方法之间的又一个区别并且能够清楚的感受到 sklearn 是一个非常“机器学习”的算法库很多时候会从便于机器学习建模的角度出发对算法进行微调。 这也是 sklearn 算法库的一大特性这个特性在导致其非常易用的同时也使得其很多算法和原始提出的算法会存在略微的区别这点也是初学者需要注意的。 什么是正则化/如何进行正则化 其实机器学习中正则化regularization的外在形式非常简单就是在模型的损失函数中加上一个正则化项regularizer有时也被称为惩罚项penalty term如下方程所示其中 L 为损失函数J 为正则化项。 通常来说正则化项往往是关于模型参数的 1- 范数或者 2- 范数当然也有可能是这两者的某种结合例如 sklearn 的逻辑回归中的弹性网正则化项其中加入模型参数的 1- 范数的正则化也被称为
l
1
l1
l 1 正则化加入模型参数的 2- 范数的正则化也被称为
l
2
l2
l 2 正则化。
1
N
∑
i
=
1
N
L
(
y
i
,
f
(
x
i
)
)
+
λ
J
(
f
)
\frac{1}{N}\sum^{N}_{i=1}L(y_i,f(x_i))+\lambda J{(f)}
N 1 i = 1 ∑ N L ( y i , f ( x i )) + λ J ( f ) 为何需要正则化 正则化的过程比不复杂但何时需要进行正则化呢 一般来说正则化核心的作用是缓解模型过拟合倾向 。 此外由于加入正则化项后损失函数的形体发生了变化因此也会影响损失函数的求解过程在某些时候加入了正则化项之后会让损失函数的求解变得更加高效。 如此前介绍的岭回归其实就是在线性回归的损失函数基础上加入了 w 的 1- 范数而 Lasso 则是加入了 w 的 2- 范数。并且对于逻辑回归来说如果加入
l
2
l2
l 2 正则化项损失函数就会变成严格的凸函数。 经验风险与结构风险 要讨论正则化是如何缓解过拟合倾向的问题需要引入两个非常重要的概念经验风险和结构风险。 在我们构建损失函数求最小值的过程其实就是依据以往经验也就是训练数据追求风险最小以往数据误差最小的过程而在给定一组参数后计算得出的损失函数的损失值其实就是经验风险 。 而所谓结构风险 我们可以将其等价为模型复杂程度模型越复杂模型结构风险就越大。而正则化后的损失函数在进行最小值求解的过程中其实是希望损失函数本身和正则化项都取得较小的值即模型的经验风险和结构风险能够同时得到控制。 模型的经验风险需要被控制不难理解因为我们希望模型能够尽可能的捕捉原始数据中的规律但为何模型的结构风险也需要被控制 核心原因在于尽管在一定范围内模型复杂度增加能够有效提升模型性能但模型过于复杂可能会导致另一个非常常见的问题——模型过拟合但总的来说一旦模型过拟合了尽管模型经验风险在降低、但模型的泛化能力会下降。 因此为了控制模型过拟合倾向我们可以把模型结构风险纳入损失函数中一并考虑当模型结构风险的增速高于损失值降低的收益时我们就需要停止参数训练迭代。
同时要求模型性能和模型复杂度都在一个合理的范围内其实等价于希望训练得到一个较小的模型同时具有较好的解释数据的能力规律捕捉能力这也符合奥卡姆剃刀原则。
2. 过拟合概念介绍
此前我们曾深入探讨过关于机器学习建模有效性的问题彼时我们得出的结论是当训练数据和新数据具有规律的一致性时才能够进行建模而只有挖掘出贯穿始终的规律同时影响训练数据和新数据的规律模型才能够进行有效预测。 不过既然有些贯穿始终的全局规律那就肯定存在一些只影响了一部分数据的局部规律。一般来说由于全局规律影响数据较多因此更容易被挖掘。 而局部规律只影响部分数据因此更难被挖掘因此从较为宽泛的角度来看但伴随着模型性能提升也是能够捕获很多局部规律的。 但是需要知道的是局部规律对于新数据的预测并不能起到正面的作用反而会影响预测结果此时就出现模型过拟合现象。我们可以通过如下实例进行说明
np. random. seed( 123 )
n_dots = 20
x = np. linspace( 0 , 1 , n_dots)
y = np. sqrt( x) + 0.2 * np. random. rand( n_dots) - 0.1
x
y
其中x 是一个 0 到 1 之间等距分布 20 个点组成的 ndarray多维数组
y
=
x
+
r
y=\sqrt{x}+r
y = x
+ r 其中 r 是人为制造的随机噪声在 [-0.1,0.1] 之间服从均匀分布。 然后我们借助 numpy 的 polyfit 函数来进行多项式拟合polyfit 函数会根据设置的多项式阶数在给定数据的基础上利用最小二乘法进行拟合并返回拟合后各阶系数。 同时当系数计算完成后我们还常用 ploy1d 函数逆向构造多项式方程进而利用方程求解 y。 例如人为制造一个二阶多项式方程然后进行二阶拟合实验。
y0 = x ** 2
np. polyfit( x, y0, 2 )
能够得出多项式各阶系数而根据该系数可用 ploy1d 逆向构造多项式方程。
p = np. poly1d( np. polyfit( x, y0, 2 ) )
print ( p)
能够看到多项式结构基本和原多项式保持一致此时生成的 p 对象相当于是一个多项式方程可通计算输入参数的多项式输出结果。
p( - 1 )
np. poly1d( np. polyfit( x, y, 3 ) )
接下来进行多项式拟合。分别利用 1 阶 x 多项式、3 阶 x 多项式和 10 阶 x 多项式来拟合 y。并利用图形观察多项式的拟合度首先我们可定义一个辅助画图函数方便后续我们将图形画于一张画布中进而方便观察。
def plot_polynomial_fit ( x, y, deg) :
p = np. poly1d( np. polyfit( x, y, deg) )
t = np. linspace( 0 , 1 , 200 )
plt. plot( x, y, 'ro' , t, p( t) , '-' , t, np. sqrt( t) , 'r--' )
其中t 为 [0,1] 中等距分布的 100 个点而 p 是 deg 参数决定的多项式回归拟合方程p(t) 即为拟合方程 x 输入 t 值时多项式输出结果此处 plot_polynomial_fit 函数用于生成同时包含xy原始值组成的红色点图、tp(t)组成的默认颜色的曲线图、tnp.sqrt(t)构成的红色虚线曲线图。 测试 3 阶多项式拟合结果。
plot_polynomial_fit( x, y, 3 )
这里需要注意 (x,y) 组成的红色点图相当于带有噪声的二维空间数据分布(t, p(t)) 构成的蓝色曲线相当于 3 阶多项式拟合原数据集(x, y)数据集后的结果。 原始数据集包含的客观规律实际上是
y
=
x
y=\sqrt{x}
y = x
因此最后红色的虚线t, np.sqrt(t)实际上是代表红色点集背后的客观规律即我们希望拟合多项式蓝色曲线能够尽可能的拟合代表客观规律的红色虚线而不是被噪声数据所吸引偏离红色虚线位置同时也不希望完全没有捕捉到红色曲线的规律。 接下来我们尝试将 1 阶拟合、3 阶拟合和 10 阶拟合绘制在一张图中。
plt. figure( figsize= ( 18 , 4 ) , dpi= 200 )
titles = [ 'Under Fitting' , 'Fitting' , 'Over Fitting' ]
for index, deg in enumerate ( [ 1 , 3 , 10 ] ) :
plt. subplot( 1 , 3 , index + 1 )
plot_polynomial_fit( x, y, deg)
plt. title( titles[ index] , fontsize= 20 )
根据最终的输出结果我们能够清楚的看到1 阶多项式拟合的时候蓝色拟合曲线即无法捕捉数据集的分布规律离数据集背后客观规律也很远而三阶多项式在这两方面表现良好十阶多项式则在数据集分布规律捕捉上表现良好单同样偏离红色曲线较远。 此时一阶多项式实际上就是欠拟合而十阶多项式则过分捕捉噪声数据的分布规律而噪声之所以被称作噪声是因为其分布本身毫无规律可言或者其分布规律毫无价值如此处噪声分布为均匀分布。 因此就算十阶多项式在当前训练数据集上拟合度很高但其捕捉到的无用规律无法推广到新的数据集上因此该模型在测试数据集上执行过程将会有很大误差。即模型训练误差很小但泛化误差很大。
3. 正则化进行特征筛选与缓解过拟合倾向
接下来我们尝试如何通过在模型中加入正则化项来缓解 10 阶多项式回归的过拟合倾向。 为了更加符合 sklearn 的建模风格、从而能够使用 sklearn 的诸多方法我们将上述 10 阶多项式建模转化为一个等价的形式即在原始数据中衍生出几个特征分别是
x
2
x^2
x 2 、
x
3
x^3
x 3 、…、
x
10
x^{10}
x 10 然后带入线性回归方程进行建模。
x_l = [ ]
for i in range ( 10 ) :
x_temp = np. power( x, i+ 1 ) . reshape( - 1 , 1 )
x_l. append( x_temp)
X = np. concatenate( x_l, 1 )
X[ : 2 ]
y
当然上述过程其实也就是比较简单的一种特征衍生方法该方法也可以通过 sklearn 中的 PolynomialFeatures 类来进行实现。
from sklearn. preprocessing import PolynomialFeatures
PolynomialFeatures?
Name Description degree 最高阶数 interaction_only 是否只包含交叉项交叉项指的是不同特征的乘结果 include_bias 是否只包含0阶计算结果、偏置项 计算模式 默认C模式F模式能提高单独评估器计算效率但会影响机器学习流中其他评估器
x. reshape( - 1 , 1 ) [ : 2 ]
PolynomialFeatures( degree= 2 ) . fit_transform( x. reshape( - 1 , 1 ) ) [ : 2 ]
PolynomialFeatures( degree= 2 , interaction_only= True ) . fit_transform( x. reshape( - 1 , 1 ) ) [ : 2 ]
poly = PolynomialFeatures( degree = 10 , include_bias= False )
poly. fit_transform( x. reshape( - 1 , 1 ) ) [ : 2 ]
from sklearn. linear_model import LinearRegression
lr = LinearRegression( )
lr. fit( X, y)
lr. coef_
from sklearn. metrics import mean_squared_error
mean_squared_error( lr. predict( X) , y)
t = np. linspace( 0 , 1 , 200 )
plt. plot( x, y, 'ro' , x, lr. predict( X) , '-' , t, np. sqrt( t) , 'r--' )
plt. title( '10-degree' )
接下来我们尝试在线性回归的损失函数中引入正则化来缓解 10 阶特征衍生后的过拟合问题。 根据 Lesson 3.3 的讨论我们知道在线性回归中加入
l
2
l2
l 2 正则化实际上就是岭回归Ridge而加入
l
1
l1
l 1 正则化则变成了 Lasso。 因此我们分别考虑围绕上述模型进行岭回归和 Lasso 的建模。
from sklearn. linear_model import Ridge, Lasso
Ridge?
reg_rid = Ridge( alpha= 0.005 )
reg_rid. fit( X, y)
reg_rid. coef_
mean_squared_error( reg_rid. predict( X) , y)
t = np. linspace( 0 , 1 , 200 )
plt. subplot( 121 )
plt. plot( x, y, 'ro' , x, reg_rid. predict( X) , '-' , t, np. sqrt( t) , 'r--' )
plt. title( 'Ridge(alpha=0.005)' )
plt. subplot( 122 )
plt. plot( x, y, 'ro' , x, lr. predict( X) , '-' , t, np. sqrt( t) , 'r--' )
plt. title( 'LinearRegression' )
不难发现
l
2
l2
l 2 正则化对过拟合倾向有较为明显的抑制作用。接下来尝试 Lasso。
Lasso?
reg_las = Lasso( alpha= 0.001 )
reg_las. fit( X, y)
reg_las. coef_
mean_squared_error( reg_las. predict( X) , y)
t = np. linspace( 0 , 1 , 200 )
plt. subplot( 121 )
plt. plot( x, y, 'ro' , x, reg_las. predict( X) , '-' , t, np. sqrt( t) , 'r--' )
plt. title( 'Lasso(alpha=0.001)' )
plt. subplot( 122 )
plt. plot( x, y, 'ro' , x, lr. predict( X) , '-' , t, np. sqrt( t) , 'r--' )
plt. title( 'LinearRegression' )
我们发现Lasso 的惩罚力度更强并且迅速将一些参数清零而这些被清零的参数则代表对应的参数在实际建模过程中并不重要从而达到特种重要性筛选的目的。 而在实际的建模过程中
l
2
l2
l 2 正则化往往应用于缓解过拟合趋势而
l
1
l1
l 1 正则化往往被用于特征筛选的场景中。 其实特征重要性和线性方程中特征对应系数大小并没有太大的关系判断特种是否重要的核心还是在于观察抛弃某些特征后建模结果是否会发生显著影响。 有上述过程我们不难发现
l
2
l2
l 2 缓解过拟合效果更好相比
l
1
l1
l 1 正则化
l
2
l2
l 2 正则化在参数筛选时过程更容易控制而
l
1
l1
l 1 正则化的运算结果说明上述 10 个特征中第一个、第三个和最后一个特征相对重要。 而特征重要的含义其实是代表哪怕带入上述 3 个特征建模依然能够达到带入所有特征建模的效果。我们可以通过下述实验进行验证
X_af = X[ : , [ 0 , 2 , 9 ] ]
lr_af = LinearRegression( )
lr_af. fit( X_af, y)
lr_af. coef_
mean_squared_error( lr_af. predict( X_af) , y)
lr_af. predict( X_af)
t = np. linspace( 0 , 1 , 200 )
plt. subplot( 121 )
plt. plot( x, y, 'ro' , x, lr_af. predict( X_af) , '-' , t, np. sqrt( t) , 'r--' )
plt. subplot( 122 )
plt. plot( x, y, 'ro' , x, lr. predict( X) , '-' , t, np. sqrt( t) , 'r--' )
我们发现哪怕删掉了 70% 的特征最终建模结果仍然还是未收到太大的影响从侧面也说明剩下 70% 的特征确实“不太重要”。 当然在删除这些数据之后模型过拟合的趋势略微有所好转那如果我们继续加上
l
2
l2
l 2 正则化呢会不会有更好防止过拟合的效果
reg_rid_af = Ridge( alpha= 0.05 )
reg_rid_af. fit( X_af, y)
reg_rid_af. coef_
mean_squared_error( reg_rid_af. predict( X_af) , y)
t = np. linspace( 0 , 1 , 200 )
plt. subplot( 121 )
plt. plot( x, y, 'ro' , x, reg_rid_af. predict( X_af) , '-' , t, np. sqrt( t) , 'r--' )
plt. title( 'Ridge_af(alpha=0.05)' )
plt. subplot( 122 )
plt. plot( x, y, 'ro' , x, reg_rid. predict( X) , '-' , t, np. sqrt( t) , 'r--' )
plt. title( 'Ridge(alpha=0.005)' )
不难发现模型整体过拟合倾向被更进一步抑制整体拟合效果较好。 此处虽然重点介绍关于
l
1
l1
l 1 正则化和
l
2
l2
l 2 正则化对模型过拟合效果抑制的效果但实际上从上述过程中我们其实能够总结一套建模策略 1 当模型效果往往是线性模型不佳时可以考虑通过特征衍生的方式来进行数据的“增强” 2 如果出现过拟合趋势则首先可以考虑进行不重要特征的筛选过多的无关特征其实也会影响模型对于全局规律的判断当然此时可以考虑使用
l
1
l1
l 1 正则化配合线性方程进行特征重要性筛选剔除不重要的特征保留重要特征 3 对于过拟合趋势的抑制仅仅踢出不重要特征还是不够的对于线性方程类的模型来说
l
2
l2
l 2 正则化则是缓解过拟合非常好的方法配合特征筛选能够快速的缓解模型过拟合倾向 当然除此以外还有一些注意事项 1 首先哪怕不进行特征筛选
l
2
l2
l 2 正则化也可以帮助线性方程抑制过拟合但特征太多其实会影响
l
2
l2
l 2 正则化的参数取值范围进而影响 alpha 参数惩罚力度的有效性 2 其次上述参数的选取和过拟合倾向的判断其实还是主观判断成分较多一个更加严谨的流程是先进行数据集的划分然后选取更能表示模型泛化能力的评估指标然后将特征提取如果要做的话、
l
2
l2
l 2 正则化后的线性方程组成一个 Pipeline再利用网格搜索确定一组最优的参数组合。 3 最后需要强调的是并非所有模型都需要/可以通过正则化来进行过拟合修正典型的可以通过正则化来进行过拟合倾向修正的模型主要有线性回归、逻辑回归、LDA、SVM 以及一些 PCA 衍生算法如 SparsePCA。而树模型则不用通过正则化来进行过拟合修正。
二、sklearn 中逻辑回归的参数解释
在补充了关于正则化的相关内容之后接下来我们来详细讨论关于逻辑回归的参数解释。
1. 说明文档中的内容解释
首先先对上述逻辑回归的说明文档中的内容进行解释。 sklearn 中逻辑回归损失函数形态 在了解了正则化的相关内容后接下来我们观察 sklearn 官网中给出的逻辑回归加入正则化后的损失函数表达式我们发现该表达式和此前我们推到的交叉熵损失函数的表达式还是略有差异核心原因是 sklearn 在二分类的时候默认两个类别的标签取值为 -1 和 1而不是 0 和 1。 我们曾在 Lesson 4.2 中进行了非常详细的关于逻辑回归损失函数的推导此处的数学推导我们只需将 Lesson 4.2 中公式当中的 y 的取值改为 -1 和 1 即可。 正则化后损失函数表达式 相比原始损失函数正则化后的损失函数有两处发生了变化其一是在原损失函数基础上乘以了系数 C其二则是加入了正则化项。 其中系数 C 也是超参数需要人工输入用于调整经验风险部分和结构风险部分的权重C 越大经验风险部分权重越大反之结构风险部分权重越大。 此外在
l
2
l2
l 2 正则化时采用的
w
T
w
2
\frac{w^Tw}{2}
2 w T w 表达式其实相当于是各参数的平方和除以 2在求最小值时本质上和 w 的 2- 范数起到的作用相同省去开平方是为了简化运算而除以 2 则是为了方便后续求导运算和 2 次方结果相消。 另外sklearn 中还提供了弹性网正则化方法其实是通过
ρ
ρ
ρ 控制
l
1
l1
l 1 正则化和
l
2
l2
l 2 正则化惩罚力度的权重是一个更加综合的解决方案。 不过代价是增加了一个超参数
ρ
ρ
ρ 并且由于损失函数形态发生了变化导致部分优化方法无法使用。
2. sklearn 中逻辑回归评估器的参数解释
在上述的一系列基础内容铺垫之后接下来我们对逻辑回归评估器中的参数进行详细解释
LogisticRegression?
参数 解释 penalty 正则化项 dual 是否求解对偶问题* tol 迭代停止条件两轮迭代损失值差值小于tol时停止迭代 C 经验风险和结构风险在损失函数中的权重 fit_intercept 线性方程中是否包含截距项 intercept_scaling 相当于此前讨论的特征最后一列全为1的列当使用liblinear求解参数时用于捕获截距 class_weight 各类样本权重* random_state 随机数种子 solver 损失函数求解方法* max_iter 求解参数时最大迭代次数迭代过程满足max_iter或tol其一即停止迭代 multi_class 多分类问题时求解方法* verbose 是否输出任务进程 warm_start 是否使用上次训练结果作为本次运行初始参数 l1_ratio 当采用弹性网正则化时
l
1
l1
l 1 正则项权重就是损失函数中的
ρ
\rho
ρ
dual是否求解对偶问题 对偶问题是约束条件相反、求解方向也相反的问题当数据集过小而特征较多时求解对偶问题能一定程度降低运算复杂度其他情况建议保留默认参数取值。 class_weight各类样本权重 class_weight 其实代表各类样本在进行损失函数计算时的数值权重。 例如假设一个二分类问题0、1 两类的样本比例是 2:1此时可以输入一个字典类型对象用于说明两类样本在进行损失值计算时的权重。 例如输入 {0:1, 1:3}则代表 1 类样本的每一条数据在进行损失函数值的计算时都会在原始数值上*3。 而当我们将该参数选为 balanced 时则会自动将这个比例调整为真实样本比例的反比以达到平衡的效果。 solver损失函数求解方法 其实除了最小二乘法和梯度下降以外还有非常多的关于损失函数的求解方法而选择损失函数的参数就是solver参数。 而当前损失函数到底采用何种优化方法进行求解其实最终目的是希望能够更快计算效率更高更好准确性更高的来进行求解而硬性的约束条件是损失函数的形态此外则是用户自行选择的空间。 这里给出何时应该用哪种 solver 的参考列表也就是官网给出的列表
逻辑回归可选的优化方法包括 1 liblinear这是一种坐标轴下降法并且该软件包中大多数算法都有 C++ 编写运行速度很快支持 OVR+L1 或 OVR+L2 2 lbfgs全称是 L-BFGS牛顿法的一种改进算法一种拟牛顿法适用于小型数据集并且支持 MVM+L2、OVR+L2 以及不带惩罚项的情况 3 newton-cg同样也是一种拟牛顿法和 lbfgs 适用情况相同 4 sag随机平均梯度下降随机梯度下降的改进版类似动量法会在下一轮随机梯度下降开始之前保留一些上一轮的梯度从而为整个迭代过程增加惯性除了不支持 L1 正则化的损失函数求解以外包括弹性网正则化其他所有损失函数的求解 5 sagasag 的改进版修改了梯度惯性的计算方法使得其支持所有情况下逻辑回归的损失函数求解 对于逻辑回归来说求解损失函数的硬性约束其实就是多分类问题时采用的策略以及加入的惩罚项所以大多数情况我们会优先根据多分类问题的策略及惩项来选取优化算法其次如果有多个算法可选那么我们可以根据其他情况来进行求解器的选取如 1 Penalize the intercept (bad)如果要对截距项也进行惩罚那只能选取 liblinear 2 Faster for large datasets如果需要对海量数据进行快速处理则可以选取 sag 和 saga 3 Robust to unscaled datasets如果未对数据集进行标准化但希望维持数据集的鲁棒性迭代平稳高效则可以考虑使用 liblinear、lbfgs 和 newton-cg 三种求解方法。 multi_class选用何种方法进行多分类问题求解 可选 OVR 和 MVM当然默认情况是 auto此时模型会优先根据惩罚项和 solver 选择 OVR 还是 MVM但一般来说MVM 效果会好于 OVR。