开始我是很难弄懂什么是过拟合,什么是欠拟合以及造成两者的各自原因以及相应的解决办法,学习了一段时间机器学习和深度学习后,分享下自己的观点,方便初学者能很好很形象地理解上面的问题。
无论在机器学习还是深度学习建模当中都可能会遇到两种最常见结果,一种叫过拟合(over-fitting )另外一种叫欠拟合(under-fitting)。
首先谈谈什么是过拟合呢?什么又是欠拟合呢?网上很直接的图片理解如下:
所谓过拟合(over-fitting)其实就是所建的机器学习模型或者是深度学习模型在训练样本中表现得过于优越,导致在验证数据集以及测试数据集中表现不佳。过拟合就是学到了很多没必要的特征,比如你说的长得像猫的狗,和长得像狗的猫,其实这只是特例,但神经网络为了更好的降低Loss,就只能被迫学习这些特征用来区分猫和狗。但是学习的太过了,(举个例子:一个男人穿着蓝色的衣服,神经网络可能把是否穿蓝色衣服作为区分男人女人的特征,这就是过拟合)遇到了新样本这些错误的特征就没有什么用了。所以过拟合就是表现为训练的时候效果很好(因为神经网络已经学到了很多有用没用的特征),但是在测试样本上的效果就很差(有的特征完全没用啊,完全就是为了降低loss而得出来的特征)。至于为什么会产生过拟合,一般是因为参数过多,为了降低loss(神经网络的任务就是为了最小化loss),后者样本过少。总之就是参数/样本的比太大。
所谓欠拟合呢(under-fitting)?相对过拟合欠拟合还是比较容易理解。还是拿刚才的模型来说,可能训练样本被提取的特征比较少,导致训练出来的模型不能很好地匹配,表现得很差,甚至样本本身都无法高效的识别。
那么问题来了,我们需要怎么去解决过拟合和欠拟合的问题呢??
现在常用的判断方法是从训练集中随机选一部分作为一个验证集,采用K折交叉验证的方式,用训练集训练的同时在验证集上测试算法效果。在缺少有效预防欠拟合和过拟合措施的情况下,随着模型拟合能力的增强,错误率在训练集上逐渐减小,而在验证集上先减小后增大;当两者的误差率都较大时,处于欠拟合状态(high bias, low variance);当验证集误差率达到最低点时,说明拟合效果最好,由最低点增大时,处与过拟合状态(high variance, low bias)。下图的横坐标用拟合函数多项式的阶数笼统地表征模型拟合能力:
过拟合:
首先我们从上面我们可以知道,造成过拟合的原因有可以归结为:参数过多。那么我们需要做的事情就是减少参数,这里有两种办法:
1、回想下我们的模型,假如我们采用梯度下降算法将模型中的损失函数不断减少,那么最终我们会在一定范围内求出最优解,最后损失函数不断趋近0。那么我们可以在所定义的损失函数后面加入一项永不为0的部分,那么最后经过不断优化损失函数还是会存在。其实这就是所谓的“正则化”。
下面这张图片就是加入了正则化(regulation)之后的损失函数。这里m是样本数目,λ表示的是正则化系数。
注意:当 λ 过大时,则会导致后面部分权重比加大,那么最终损失函数过大,从而导致欠拟合
当 λ 过小时,甚至为0,导致过拟合。
2、对于神经网络,参数膨胀原因可能是因为随着网路深度的增加,同时参数也不断增加,并且增加速度、规模都很大。那么可以采取减少神经网络规模(深度)的方法。也可以用一种叫dropout的方法。dropout的思想是当一组参数经过某一层神经元的时候,去掉这一层上的一部分神经元,让参数只经过一部分神经元进行计算。注意这里的去掉并不是真正意义上的去除,只是让参数不经过一部分神经元计算而已。
3.提前停止训练:
也就是减少训练的迭代次数。从上面的误差率曲线图可以看出,理论上能够找到一个训练程度,此时验证集误差率最低,视为拟合效果最好的点。
另外增大训练样本规模同样也可以防止过拟合。
欠拟合:
其实个人觉得欠拟合基本上都会发生在训练刚开始的时候,经过不断训练之后欠拟合应该不怎么考虑了。。但是如果真的还是存在的话,可以通过增加网络复杂度或者在模型中增加多点特征点,这些都是很好解决欠拟合的方法。
岭回归与Lasso回归的出现是为了解决线性回归出现的过拟合以及在通过正规方程方法求解θ的过程中出现的(XTX)不可逆这两类问题的,这两种回归均通过在损失函数中引入正则化项来达到目的。
在日常机器学习任务中,如果数据集的特征比样本点还多, (XTX)−1的时候会出错。岭回归最先用来处理特征数多于样本数的情况,现在也用于在估计中加入偏差,从而得到更好的估计。这里通过引入λ限制了所有θ2之和,通过引入该惩罚项,能够减少不重要的参数,这个技术在统计学上也叫作缩减(shrinkage)。和岭回归类似,另一个缩减LASSO 也加入了正则项对回归系数做了限定。
为了防止过拟合(θ过大),在目标函数J(\theta)后添加复杂度惩罚因子,即正则项来防止过拟合。正则项可以使用L1-norm(Lasso)、L2-norm(Ridge),或结合L1-norm、L2-norm(Elastic Net)。
Lasso:使用L1-norm正则
Ridge:使用L2-norm正则
ElasticNet:结合l1-norm、l2-norm进行正则
简单的理解正则化:
关于第1点,过拟合指的是给定一堆数据,这堆数据带有噪声,利用模型去拟合这堆数据,可能会把噪声数据也给拟合了,这点很致命,一方面会造成模型比较复杂,另一方面,模型的泛化性能太差了,遇到了新的数据让你测试,你所得到的过拟合的模型,正确率是很差的。
关于第2点,本来解空间是全部区域,但通过正则化添加了一些约束,使得解空间变小了,甚至在个别正则化方式下,解变得稀疏了。这一点不得不提到一个图,相信我们都经常看到这个图,但貌似还没有一个特别清晰的解释,这里我尝试解释一下,图如下:
上图中左边为Lasso回归,右边为岭回归。红色的椭圆和蓝色的区域的切点就是目标函数的最优解,我们可以看到,如果是圆,则很容易切到圆周的任意一点,但是很难切到坐标轴上,因此没有稀疏;但是如果是菱形或者多边形,则很容易切到坐标轴上,因此很容易产生稀疏的结果。这也说明了为什么L1范式会是稀疏的。这样就解释了为什么lasso可以进行特征选择。岭回归虽然不能进行特征筛选,但是对θ的模做约束,使得它的数值会比较小,很大程度上减轻了overfitting的问题。
这里的β1,β2都是模型的参数,要优化的目标参数,蓝色部分区域,其实就是解空间,正如上面所说,这个时候,解空间“缩小了”,你只能在这个缩小了的空间中,寻找使得目标函数最小的β1,β2。再看看那红色的圆圈,再次提醒大家,这个坐标轴和特征(数据)没关系,它完全是参数的坐标系,每一个圆圈上,可以取无数个β1,β2,这些β1,β2有个共同的特点,用它们计算的目标函数值是相等的。那个红色的圆心,就是实际最优参数,但是由于我们对解空间做了限制,所以最优解只能在“缩小的”解空间中产生。
以两个变量为例,解释岭回归的几何意义:
1、没有约束项时。模型参数β1,β2已经经过标准化。残差平方和RSS可以表示为β1,β2的一个二次函数,数学上可以用一个抛物面表示。
2、岭回归时。约束项为β21+β22≤t,对应着投影为β1,β2平面上的一个圆,即下图中的圆柱。
可见岭回归解与原先的最小二乘解是有一定距离的。
线性回归算法模型很简单,每条数据有n个特征,每个特征对应着一个自己的权重值,与权重的乘积再加上一个偏置值,这个就是线性回归模型,公式如下:
为了方便后续写成矩阵的形式,我们这边可以稍作修改,令 w0=b,x0=1,就可以写成下边的形式:
假设现在有m个样本,写成矩阵的形式就是:
权重 w也可以写成矩阵的形式:
那么可以写成一种简单明了的方式:
ps: n代表特征数目,m代表样本数目
损失函数
损失函数是可以一定程度上衡量模型的好坏的一个算法,我们这里介绍一个在回归问题中比较常用的损失:均方误差(MSE)
其中 yi^是样本的预测值, yi是样本的实际值,可以看出当 cost值越小的时候,预测值越接近实际值。
优化器
算法在学习的过程中是要逐渐的去减少 cost的值的,那么如何减少损失函数的值呢,我们这里简单介绍一种优化器:梯度下降算法
假设我们的样本只有一个特征,且偏置项为0,那么我们的损失函数就可以写为:
可以看出这是一个关于 w的二次函数,图像如下:
(没了解过画图工具,从别人那里截的图,J(θ)就是我们的 cost(w), θ就对应我们的 w)
如果拓展到三维空间就是一个往下凹的曲面。梯度下降算法就是通过每次训练,更新w的值,使得每次更新之后,损失值变的更小。那么他是怎么更新的呢?我们需要自己定义一个初始的 w值,cost函数对 w求导,每次更新的时候都是在原来的基础上减去α∗dd(w)cost(w), α就是学习率,控制更新参数的快慢,可以看出 α值比较大的话,训练很快,但是很容易就跳过了最优解,但是 α太小又训练的很慢,这个就需要自己去适当的调整了。
在全部特征的情况下, cost(w)对各参数求导之后的公式为:
一共有n+1个参数,各参数同步更新。
参数
LinearRegression(fit_intercept=True, normalize=False, copy_X=True, n_jobs=None)
fit_intercept:是否有截据,如果没有则直线过原点;
normalize:是否将数据归一化;
copy_X:默认为True,当为True时,X会被copied,否则X将会被覆写;
n_jobs:默认值为1。计算时使用的核数
LinearRegression属性:
coef_:array,shape(n_features, ) or (n_targets, n_features)。回归系数(斜率)。
intercept_: 截距
LinearRegression方法:
fit(x,y,sample_weight=None):,x和y以矩阵的形式传入,sample_weight则是每条测试数据的权重,同样以矩阵方式传入(在版本0.17后添加了sample_weight)。
predict(x): 预测方法,用来返回预测值
get_params(deep=True): 返回对regressor 的设置值
score(X,y,sample_weight=None): 评分函数,将返回一个小于1的得分,可能会小于0
使用场景:
LinearRegression:只要数据线性相关,LinearRegression是我们的首选,如果发现拟合或者预测的不够好,再考虑其他的线性回归库
LinearRegression 损失函数
优点
1.建模速度快,不需要很复杂的计算,在数据量大的情况下依然运行速度很快
2.可解释性
缺点
1.不能很好的处理非线性数据
实例代码
# -*- coding: utf-8 -*-
import numpy as np
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error
#模拟数据
x = np.linspace(0, 10, 50)
noise = np.random.uniform(-2,2,size=50)
y = 5 * x + 6 + noise
#创建模型
liner = LinearRegression(fit_intercept=True,normalize=True,copy_X=True, n_jobs=1)
#拟合模型
liner.fit(np.reshape(x,(-1,1)),np.reshape(y,(-1,1)))
print(liner)
# 查看模型的斜率
print(liner.coef_)
# 查看模型的截距
print(liner.intercept_)
#得分越接近1越好
score = liner.score(np.reshape(x,(-1,1)),np.reshape(y,(-1,1)))
print(score)
# 均方误差
#预测
y_pred = liner.predict(np.reshape(x,(-1,1)))
lr_mse = mean_squared_error(np.reshape(y,(-1,1)), y_pred)
print(lr_mse)
plt.figure(figsize=(5,5))
plt.scatter(x,y)
plt.plot(x,y_pred, color="r")
plt.show()
参数
Ridge(alpha=1.0, fit_intercept=True, normalize=False, copy_X=True, max_iter=None, tol=0.001, solver='auto')
• alpha:指定λ\lambdaλ值,默认为1。
• fit_intercept:bool类型,是否需要拟合截距项,默认为True。
• normalize:bool类型,建模时是否对数据集做标准化处理,默认为False。
• copy_X:bool类型,是否复制自变量X的数值,默认为True。
• max_iter:指定模型的最大迭代次数。
• tol:指定模型收敛的阈值,默认为0.0001。
solver:求解器,有auto, svd, cholesky, sparse_cg, lsqr几种,一般我们选择auto,一些svd,cholesky也都是稀疏表示中常用的omp求解算法中的知识,大家有时间可以去了解。
方法和属性
clf.fit(X, y):输入训练样本数据X,和对应的标记y;
clf.predict(X):利用学习好的线性分类器,预测标记,一般在fit之后调用;
clf.corf_: 输入回归表示系数
岭(Ridge)回归再普通最小二乘法的损失函数中增加了额外的缩减惩罚项,以限制L2范数的平方项。
在这种情况下,X是将所有样本作为列向量的矩阵,w表示权重向量。系数α表示正则化的强弱正则化。
场景
RidgeCV(岭回归):只要数据线性相关,用LinearRegression拟合的不是很好,需要正则化,可以考虑使用RidgeCV回归, 如何输入特征的维度很高,而且是稀疏线性关系的话, RidgeCV就不太合适,考虑使用Lasso回归类家族。
RidgeCV(岭回归)损失函数
参数
RidgeCV(alphas=(0.1, 1.0, 10.0), fit_intercept=True, normalize=False, scoring=None, cv=None, gcv_mode=None, store_cv_values=False)
参数名:alphas
类型: numpy array of shape [n_alphas]
说明:α值的数组。正则化的力度,必须是正浮点数。正则化提升了问题的条件,减少了估计器的方差。较大的值指定了更强的正则化。在其他模型,比如LogisticRegression 或者LinearSVC,α对应C−1。
参数名:fit_intercept
类型:boolean
说明:是否计算该模型的截距。如果设置为False,将不会在计算中使用截距(比如,预处理数据已经中心化)
参数名:normalize
类型:boolean, optional, default False
说明:当fit_intercept设置为False时,该参数将会被忽略。如果为True,则回归前,回归变量X将会进行归一化,减去均值,然后除以L2范数。如果想要标准化,请在评估器(normalize参数为False)调用fit方法前调用sklean.preprocessing.StandardScaler,
参数名:scoring
类型:string, callable or None, optional, default: None
说明:一个字符串(见模型评估文档)或一个评估分数的可调用的对象/函数,对象/函数带有注册的评估器(estimator, X, y)
参数名:cv
类型:int, cross-validation generator or an iterable, optional
说明:确定交叉验证分裂策略。对cv的可能输入如下:
None 使用有效的留一交叉验证。
integer 指定折叠数。
- 用于交叉验证生成器的对象。
- 一种可重复的生成序列。
对于整数/无输入,如果y是二进制或多类,使用sklearn.model_selection.StratifiedKFold,否则使用sklearn.model_selection.KFold
参数名:gcv_mode
类型: {None, ‘auto’, ‘svd’, eigen’}, optional
说明:说明在执行通用交叉验证时使用的策略的标志。选项有:
auto 如果n_samples为> n_feature,或者当X为稀疏矩阵时,使用svd,否则使用eigen。
svd 用X奇异值分解的力计算(不适用于稀疏矩阵)
eigen 力的计算通过eigen分解 XTX
“auto”模式是默认的,它的目的是根据训练数据的形状和格式选择两个更廉价的选项。
参数名:store_cv_values
类型:boolean, default=False
说明:标记是否与每个alpha对应的交叉验证值应该存储在cv_values_属性中(见下面)。此标志仅与cv=None兼容(即使用通用交叉验证)。
属性
参数名:cv_values_
类型:array, shape = [n_samples, n_alphas] or shape = [n_samples, n_targets, n_alphas], optional
说明:每个alpha的交叉验证值(如果store_cv_values=True和cv=None)。在fit()被调用之后,这个属性将包含均方差(默认值)或{loss,score}func函数(如果在构造函数中提供)。
参数名:coef
类型: array, shape = [n_features] or [n_targets, n_features]
说明:权重向量
参数名:intercept_
类型:float | array, shape = (n_targets,)
说明:决策函数中的独立项,即截距,如果fit_intercept=False,则设置为0
参数名:alpha_
类型: float
说明:正则化参数估计。
实例代码
from sklearn.linear_model import Ridge
from sklearn.datasets import load_boston
from sklearn.model_selection import train_test_split
from sklearn.linear_model import RidgeCV
boston = load_boston()
X = boston.data
y = boston.target
# 把数据分为训练数据集和测试数据集(20%数据作为测试数据集)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=3)
model = Ridge(alpha=0.01, normalize=True)
model.fit(X_train, y_train)
# 查看模型的斜率
print(model.coef_)
# 查看模型的截距
print(model.intercept_)
train_score = model.score(X_train, y_train) # 模型对训练样本得准确性
test_score = model.score(X_test, y_test) # 模型对测试集的准确性
print(train_score)
print(test_score)
model = RidgeCV(alphas=[1.0, 0.5, 0.1, 0.05, 0.01, 0.005, 0.001, 0.0005, 0.0001], normalize=True)
model.fit(X_train, y_train)
# 查看模型的斜率
print(model.coef_)
# 查看模型的截距
print(model.intercept_)
train_score = model.score(X_train, y_train) # 模型对训练样本得准确性
test_score = model.score(X_test, y_test) # 模型对测试集的准确性
print(train_score)
print(test_score)
#最优alpha
print(model.alpha_)
参数
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’
)
• alpha:指定λ\lambdaλ值,默认为1。
• fit_intercept:bool类型,是否需要拟合截距项,默认为True。
• normalize:bool类型,建模时是否对数据集做标准化处理,默认为False。
• precompute:bool类型,是否在建模前计算Gram矩阵提升运算速度,默认为False。
• copy_X:bool类型,是否复制自变量X的数值,默认为True。
• max_iter:指定模型的最大迭代次数。
• tol:指定模型收敛的阈值,默认为0.0001。
• warm_start:bool类型,是否将前一次训练结果用作后一次的训练,默认为False。
• positive:bool类型,是否将回归系数强制为正数,默认为False。
• random_state:指定随机生成器的种子。
• selection:指定每次迭代选择的回归系数,如果为’random’,表示每次迭代中将随机更新回归系数;如果为’cyclic’,则每次迭代时回归系数的更新都基于上一次运算。
方法和属性
clf.fit(X, y):输入训练样本数据X,和对应的标记y;
clf.predict(X):利用学习好的线性分类器,预测标记,一般在fit之后调用;
clf.corf_: 输入回归表示系数
Lasso回归加入w的L1范数作为惩罚项,以确定系数中的数目较多的无用项(零值)
场景
ridge是l2正则化的线性回归,lasso则是带l1正则化的线性回归。进一步说,他们都同样的比线性回归多一个超参数需要调,alpha。所以有了RidgeCV,LassoCV的说法。也就是说我们必须找到合理的alpha,那么这个线性模型我们才能说是找好了。所以建议在用这两个模型时,尽量都用CV形式的,而不是用Lasso与Ridge。
LassoCV 损失函数
参数
LassoCV(eps=0.001, n_alphas=100, alphas=None, fit_intercept=True,
normalize=False, precompute=‘auto’, max_iter=1000, tol=0.0001,
copy_X=True, cv=None, verbose=False, n_jobs=1, positive=False,
random_state=None, selection=‘cyclic’
)
• eps:指代λ 最小值与最大值的商,默认为0.001。
• n_alphas:指定λ的个数,默认为100个。
• alphas:指定具体的λ列表用于模型的运算。
• fit_intercept:bool类型,是否需要拟合截距项,默认为True。
• normalize:bool类型,建模时是否对数据集做标准化处理,默认为False。
• precompute:bool类型,是否在建模前计算Gram矩阵提升运算速度,默认为False。
• max_iter:指定模型的最大迭代次数。
• tol:指定模型收敛的阈值,默认为0.0001。
• copy_X:bool类型,是否复制自变量X的数值,默认为True。
• cv:指定交叉验证的重数。
• verbose:bool类型,是否返回模型运行的详细信息,默认为False。
• n_jobs:指定使用的CPU数量,默认为1,如果为-1表示所有CPU用于交叉验证的运算。
• positive:bool类型,是否将回归系数强制为正数,默认为False。
• random_state:指定随机生成器的种子。
• selection:指定每次迭代选择的回归系数,如果为’random’,表示每次迭代中将随机更新回归系数;如果为’cyclic’,则每次迭代时回归系数的更新都基于上一次运算。
属性
参数名:cv_values_
类型:array, shape = [n_samples, n_alphas] or shape = [n_samples, n_targets, n_alphas], optional
说明:每个alpha的交叉验证值(如果store_cv_values=True和cv=None)。在fit()被调用之后,这个属性将包含均方差(默认值)或{loss,score}func函数(如果在构造函数中提供)。
参数名:coef
类型: array, shape = [n_features] or [n_targets, n_features]
说明:权重向量
参数名:intercept_
类型:float | array, shape = (n_targets,)
说明:决策函数中的独立项,即截距,如果fit_intercept=False,则设置为0
参数名:alpha_
类型: float
说明:正则化参数估计。
实例代码
rom sklearn.linear_model import Lasso
from sklearn.datasets import load_boston
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LassoCV
boston = load_boston()
X = boston.data
y = boston.target
# 把数据分为训练数据集和测试数据集(20%数据作为测试数据集)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=3)
model = Lasso(alpha=0.0001, normalize=True)
model.fit(X_train, y_train)
# 查看模型的斜率
print(model.coef_)
# 查看模型的截距
print(model.intercept_)
train_score = model.score(X_train, y_train) # 模型对训练样本得准确性
test_score = model.score(X_test, y_test) # 模型对测试集的准确性
print(train_score)
print(test_score)
model = LassoCV(alphas=[1.0, 0.5, 0.1, 0.05, 0.01, 0.005, 0.001, 0.0005, 0.0001, 0.00005, 0.00001], normalize=True)
model.fit(X_train, y_train)
# 查看模型的斜率
print(model.coef_)
# 查看模型的截距
print(model.intercept_)
train_score = model.score(X_train, y_train) # 模型对训练样本得准确性
test_score = model.score(X_test, y_test) # 模型对测试集的准确性
print(train_score)
print(test_score)
#最优alpha
print(model.alpha_)
参数
ElasticNet(self, alpha=1.0, l1_ratio=0.5, fit_intercept=True, normalize=False, precompute=False, max_iter=1000, copy_X=True, tol=1e-4, warm_start=False, positive=False, random_state=None, selection=’cyclic’)
• alpha 类型:float, optional 混合惩罚项的常数,morning是1,看笔记的得到有关这个参数的精确数学定义。alpha = 0等价于传统最小二乘回归,通过LinearRegression求解。因为数学原因,使用alpha = 0的lasso回归时不推荐的,如果是这样,你应该使用 LinearRegression 。*
• l1_ratio 类型:float 说明:弹性网混合参数,0 <= l1_ratio <= 1,对于 l1_ratio = 0,惩罚项是L2正则惩罚。对于 l1_ratio = 1是L1正则惩罚。对于 0
• fit_intercept:bool类型,是否需要拟合截距项,默认为True。
• normalize:bool类型,建模时是否对数据集做标准化处理,默认为False。
• precompute:bool类型,是否在建模前计算Gram矩阵提升运算速度,默认为False。
• copy_X:bool类型,是否复制自变量X的数值,默认为True。
• max_iter:指定模型的最大迭代次数。
• tol:指定模型收敛的阈值,默认为0.0001。
• warm_start:bool类型,是否将前一次训练结果用作后一次的训练,默认为False。
• positive:bool类型,是否将回归系数强制为正数,默认为False。
• random_state:指定随机生成器的种子。
• selection:指定每次迭代选择的回归系数,如果为’random’,表示每次迭代中将随机更新回归系数;如果为’cyclic’,则每次迭代时回归系数的更新都基于上一次运算。
方法和属性
clf.fit(X, y):输入训练样本数据X,和对应的标记y;
clf.predict(X):利用学习好的线性分类器,预测标记,一般在fit之后调用;
参数名:coef_
类型:array, shape (n_features,) | (n_targets, n_features)
说明:参数向量(损失函数表达式中的
参数名:sparse_coef_
类型:scipy.sparse matrix, shape (n_features, 1) | (n_targets, n_features)
说明:sparse_coef_ 是从coef_ 导出的只读属性
参数名:intercept_
类型:float | array, shape (n_targets,)
说明:决策函数中的独立项,即截距
参数名:n_iter_
类型:array-like, shape (n_targets,)
说明:由坐标下降求解器运行的,达到指定公差的迭代次数。
ElasticNet将Lasso和Ridge组成一个具有两种惩罚因素的单一模型:一个与L1范数成比例,另外一个与L2范数成比例。使用这种方式方法所得到的模型就像纯粹的Lasso回归一样稀疏,但同时具有与岭回归提供的一样的正则化能力。它的损失函数是:
从上面的公式可知,ElasticNet使用时需要提供α和β两个参数。在β中参数的名称为l1_ratio
场景
ElasticNetCV:对超参数a和p使用交叉验证,帮助我们选择合适的a和p
使用场景:ElasticNetCV类在我们发现用Lasso回归太过(太多特征被稀疏为0),而Ridge回归也正则化的不够(回归系数衰减太慢)的时候
ElasticNetCV 损失函数
参数
ElasticNetCV(self, alphas=(0.1, 0.01, 0.005, 0.0025, 0.001), l1_ratio=(0.1, 0.25, 0.5, 0.75, 0.8), fit_intercept=True, normalize=False, precompute=False, max_iter=1000, copy_X=True, tol=1e-4, warm_start=False, positive=False, random_state=None, selection=’cyclic’)
• alphas 类型:float, optional 混合惩罚项的常数,morning是1,看笔记的得到有关这个参数的精确数学定义。alpha = 0等价于传统最小二乘回归,通过LinearRegression求解。因为数学原因,使用alpha = 0的lasso回归时不推荐的,如果是这样,你应该使用 LinearRegression 。*
• l1_ratio 类型:float 说明:弹性网混合参数,0 <= l1_ratio <= 1,对于 l1_ratio = 0,惩罚项是L2正则惩罚。对于 l1_ratio = 1是L1正则惩罚。对于0< l1_ratio <1,惩罚是l1和L2的组合。
• fit_intercept:bool类型,是否需要拟合截距项,默认为True。
• normalize:bool类型,建模时是否对数据集做标准化处理,默认为False。
• precompute:bool类型,是否在建模前计算Gram矩阵提升运算速度,默认为False。
• copy_X:bool类型,是否复制自变量X的数值,默认为True。
• max_iter:指定模型的最大迭代次数。
• tol:指定模型收敛的阈值,默认为0.0001。
• warm_start:bool类型,是否将前一次训练结果用作后一次的训练,默认为False。
• positive:bool类型,是否将回归系数强制为正数,默认为False。
• random_state:指定随机生成器的种子。
• selection:指定每次迭代选择的回归系数,如果为’random’,表示每次迭代中将随机更新回归系数;如果为’cyclic’,则每次迭代时回归系数的更新都基于上一次运算。
属性
clf.fit(X, y):输入训练样本数据X,和对应的标记y;
clf.predict(X):利用学习好的线性分类器,预测标记,一般在fit之后调用;
参数名:coef_
类型:array, shape (n_features,) | (n_targets, n_features)
说明:参数向量(损失函数表达式中的
参数名:sparse_coef_
类型:scipy.sparse matrix, shape (n_features, 1) | (n_targets, n_features)
说明:sparse_coef_ 是从coef_ 导出的只读属性
参数名:intercept_
类型:float | array, shape (n_targets,)
说明:决策函数中的独立项,即截距
参数名:n_iter_
类型:array-like, shape (n_targets,)
说明:由坐标下降求解器运行的,达到指定公差的迭代次数。
实例代码
from sklearn.linear_model import ElasticNet
from sklearn.datasets import load_boston
from sklearn.model_selection import train_test_split
from sklearn.linear_model import ElasticNetCV
boston = load_boston()
X = boston.data
y = boston.target
# 把数据分为训练数据集和测试数据集(20%数据作为测试数据集)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=3)
model = ElasticNet(alpha=0.00001,l1_ratio=0.1, normalize=True)
model.fit(X_train, y_train)
# 查看模型的斜率sparse_coef_ 是从coef_ 导出的只读属性
print(model.coef_)
print(model.sparse_coef_)
# 查看模型的截距
print(model.intercept_)
train_score = model.score(X_train, y_train) # 模型对训练样本得准确性
test_score = model.score(X_test, y_test) # 模型对测试集的准确性
print(train_score)
print(test_score)
model = ElasticNetCV(alphas=[1.0, 0.5, 0.1, 0.05, 0.01, 0.005, 0.001, 0.0005, 0.0001, 0.00005, 0.00001], l1_ratio=(0.1, 0.25, 0.5, 0.75, 0.8), normalize=True)
model.fit(X_train, y_train)
# 查看模型的斜率
print(model.coef_)
# 查看模型的截距
print(model.intercept_)
train_score = model.score(X_train, y_train) # 模型对训练样本得准确性
test_score = model.score(X_test, y_test) # 模型对测试集的准确性
print(train_score)
print(test_score)
#最优alpha
print(model.alpha_)
print(model.l1_ratio_)
在sklearn中包含四种评价尺度,分别为mean_squared_error、mean_absolute_error、explained_variance_score 和 r2_score。
1、均方差(mean-squared-error)
2、平均绝对值误差(mean_absolute_error)
3.可释方差得分(explained_variance_score)
4.中值绝对误差(Median absolute error)
5.R2 决定系数(拟合优度)
模型越好:r2→1
模型越差:r2→0
可以使用三种方式来调用
第一种是直接从metrics中导入r2_score,输入预测值和真实值后打分。
第二种是直接从 线性回归LinearRegression的接口score来进行调用。
第三种是在交叉验证中,输入"r2"来调用。
用法示例
from sklearn.metrics import r2_score
y_true = [1,2,4]
y_pred = [1.3,2.5,3.7]
# 第一种是直接从metrics中导入r2_score,输入预测值和真实值后打分
r2_score(y_true,y_pred)
#第二种是直接从 线性回归LinearRegression的接口score来进行调用
linner.score(x_test,y_test)
#第三种是在交叉验证中,输入"r2"来调用
cross_val_score(linner, x_train, y_train, cv=5, scoring='r2').mean()
R方统计量
R方统计量是一种尺度不变的统计量,它给出了线性回归模型解释的目标变量的变化比例。
这可能看起来有点复杂,所以让我在这里把它分解。为了确定模型解释的目标变化比例,我们需要首先确定以下内容-
平方和(TSS)
目标变量的总变化是实际值与其平均值之差的平方和。
TSS或总平方和给出了Y的总变化量。我们可以看到它与Y的方差非常相似。虽然方差是实际值和数据点之间差的平方和的平均值,TSS是平方和的总和。
既然我们知道了目标变量的总变化量,我们如何确定模型解释的这种变化的比例?我们回到RSS。
残差平方和(RSS)
正如我们前面讨论的,RSS给出了实际点到回归线距离的总平方。残差,我们可以说是回归线没有捕捉到的距离。
因此,RSS作为一个整体给了我们目标变量中没有被我们的模型解释的变化。
R方
现在,如果TSS给出Y的总变化量,RSS给出不被X解释的Y的变化量,那么TSS-RSS给出了Y的变化,并且这部分变化是由我们的模型解释的!我们可以简单地再除以TSS,得到由模型解释的Y中的变化比例。这是我们的R方统计量!
R方=(TSS-RSS)/TSS
=解释变化/总变化
=1–未解释的变化/总变化
因此,R方给出了目标变量的可变性程度,由模型或自变量解释。如果该值为0.7,则意味着自变量解释了目标变量中70%的变化。
R方始终介于0和1之间。R方越高,说明模型解释的变化越多,反之亦然。
如果RSS值很低,这意味着回归线非常接近实际点。这意味着自变量解释了目标变量的大部分变化。在这种情况下,我们会有一个非常高的R方值。
相反,如果RSS值非常高,则意味着回归线远离实际点。因此,自变量无法解释目标变量中的大部分变量。这会给我们一个很低的R方值。
所以,这就解释了为什么R方值给出了目标变量的变化量。
关于R方统计量的问题
R方统计并不完美。事实上,它有一个主要缺陷。不管我们在回归模型中添加多少变量,它的值永远不会减少。
也就是说,即使我们在数据中添加冗余变量,R方的值也不会减少。它要么保持不变,要么随着新的自变量的增加而增加。
这显然没有意义,因为有些自变量在确定目标变量时可能没有用处。调整R方处理了这个问题。
调整R方统计量
调整R方考虑了用于预测目标变量的自变量数量。在这样做的时候,我们可以确定在模型中添加新的变量是否会增加模型的拟合度。
让我们看看调整R方的公式,以便更好地理解它的工作原理。
在这里,
n表示数据集中的数据点数量
k表示自变量的个数
R代表模型确定的R方值
因此,如果R方在增加一个新的自变量时没有显著增加,那么调整R方值实际上会减少。
另一方面,如果增加新的自变量,我们看到R方值显著增加,那么调整R方值也会增加。
如果我们在模型中加入一个随机自变量,我们可以看到R方值和调整R方值之间的差异。
如你所见,添加随机独立变量无助于解释目标变量的变化。我们的R方值保持不变。因此,给我们一个错误的指示,这个变量可能有助于预测输出。然而,调整R方值下降,表明这个新变量实际上没有捕捉到目标变量的趋势。
显然,当回归模型中存在多个变量时,最好使用调整R方。这将使我们能够比较具有不同数量独立变量的模型。