2019独角兽企业重金招聘Python工程师标准>>>
Introduction
线性回归(Linear regressions)和对率回归(Logistic regressions)是人们学习算法的第一个预测模型。因此它们很常见,还有许多分析人员认为它们是仅有的回归模型,部分分析师认为它们是所有回归模型中最重要的。
事实上有无数的回归模型都能被使用,每种形式的回归模型都有它独特且重要的应用场景。在这篇文章里我以简单的方式解释最常用的7种回归模型,通过这篇文章,我希望人们对回归模型有一种广泛性的了解,取而代之的是希望能在每个场景合适的使用linear / logistic regression。
Table of Contents
- 什么是回归分析?
- 为什么使用回归分析?
- 有什么类型的回归?
- Linear Regression
- Logistic Regression
- Polynomial Regression
- Stepwise Regression
- Ridge Regression
- Lasso Regression
- ElasticNet Regression
- 如何正确的选择回归模型?
什么是回归分析?
回归分析是预测模型技术中的一种形式,它探讨的是因变量(target)和独立变量(predictor)之间的关系。这个技术常用于进行预测、时间序列模型和在两变量之间寻找因果效应的关系。譬如,使用回归能最好的研究道路交通事故和司机鲁莽驾驶的关系。
回归分析是建模和分析数据的一类重要的工具。这里,我们使用曲线/直线来拟合这些数据点,某些方法是数据点到曲线/直线的距离偏差最小,在接下来的部分我将说明更多的细节。
为什么使用回归分析?
如上所述,回归分析是评估两个或更多变量之间的关系。让我们使用一个简单的例子进行理解:
如我所说,你想基于当前的经济状况去评估公司的销售额的增长,公司最近的数据表明在当前的经济条件下出现2到5倍的增长,利用这个发现,我们能基于当前或过去的信息来预测公司未来的销售情况。
这有使用回归分析的几点好处:
1.它表明了因变量和独立变量之间的重要关系;
2.它表明的是多个独立变量对因变量影响的强度。
回归分析还使我们能比较变量在不同程度上影响,如价格变动对促销活动的影响。这样有利于市场研究员/数据分析师/数据科学家在建立模型的时候排除并评估出最好的变量。
我们有多少种回归技术?
有很多的回归技术可用于预测中,大多数的回归由3个指标所衡量(自变量的数目,因变量的类型以及回归线的形状),在后面我们对这3个指标进行更加详细的讨论。
对于有创造性的人,你可以创造新的回归,就需要组合以前没有使用过的参数。在你开始之前,让我们来了解最常用的回归:
1. 线性回归(Linear Regression)
它是广泛为人所知的模型技术之一。线性回归常被选用在线性预测模型中,在这个模型中,因变量是连续的,自变量可以是连续或离散的,回归线的性质是线性的。
线性回归使用最佳拟合直线建立因变量(Y)和一个或多个独立变量(X)之间的关系(也成为回归线)
它是被方程式:Y = a + b*X + e 所表示,这里 a 为截距,b 为斜率和 e 为误差项。这个方程式能基于给定的预测变量来预测目标变量的值。
简单的线性回归与多元线性回归的区别在于,多元线性回归有多个(>1)独立变量,而简单线性回归只有1个独立变量。现在,我们如何获得最佳拟合线?
1). 如何获得最佳拟合线(a和b的值)?
这个目标可以容易的由最小二乘法完成,最小二乘法是拟合回归线最常用的方法,它通过最小化每个数据点到线的垂直偏差的平方和来计算观察数据的最佳拟合线。因为偏差是一个平方,当相加时,在正值和负值之间没有抵消。
minω∥Xω−y∥22
我们可以使用R平方来评估模型性能。要了解有关这些指标的更多详细信息,您可以阅读:模型性能指标第1部分,第2部分。
2). 要点:
* 独立变量和因变量之间必须存在线性关系;
* 多元回归具有多重共线性,自相关,异方差性;
* 线性回归对异常值非常敏感。它可以严重影响回归线和最终的预测值;
* 多重共线性可以增加系数估计值(系数)的方差,并使该估计值对模型中的微小变化非常敏感。结果是系数估计值不稳定;
* 在多个独立变量的情况下,我们可以采用前向选择,反向消除和逐步方法来选择最重要的自变量。
2. 对率回归(Logistic Regression)
逻辑回归用于发现事件的概率=成功和事件的事件=失败。当因变量是二进制(0/1,True / False,是/否)时,我们应该使用逻辑回归。这里,Y的值的范围从0到1,并且它可以由以下等式表示。
odds= p/(1-p) = probability of event occurrence / probability of not event occurrence
ln(odds) = ln(p/(1-p))
logit(p) = ln(p/(1-p)) = b0+b1X1+b2X2+b3X3….+bkXk
上面,p是有特征存在的概率。你应该问的是“为什么我们在方程中使用log?”。
因为我们这里用二项分布(因变量),我们需要选择最适合这种分布的链接函数。并且,它是logit函数。在上面的等式中,选择参数用来最大化这些观察样本的似然值,而不是最小化平方误差的和(类似于普通回归)。
要点
* 它被广泛的用于分类问题;
* 逻辑回归不需要依赖变量和自变量之间的线性关系。它可以处理各种类型的关系,因为它对预测的胜率使用非线性对数(log)变换;
* 为了避免过拟合和欠拟合,我们应该使用所有的有意义的变量。确保这种做法的一个好方法是使用逐步法来估计逻辑回归;
* 它需要大量的样本,因为最大似然估计在小样本上比普通最小二乘方更弱;
* 自变量之间不应该彼此相关,即没有多共性。然而,我们在分析和模型时包含分类变量的交互效应(相互之间有影响);
* 如果因变量的值是有序的,那么它被称为有序逻辑回归;
* 如果因变量是多类,则称为多分类Logistic回归。
3. 多元回归
如果自变量的幂大于1,则回归方程是多项式回归方程。下面的方程式表示多项式方程:
y=a+b∗x2
在这种回归技术中,最佳拟合线并不是直线。它是一条拟合数据点的曲线。
要点
* 虽然可能存在用较高次多项式去拟合较低次多项式的误差,这可能导致过拟合。绘制出数据点与拟合曲线之间的拟合图来确保曲线拟合问题的性质。这里有一个如何绘制的例子可以帮助理解:
- 特别注意曲线向两端,看看这些形状和趋势是否有意义。更高的多项式可以最终在外推上产生更多的结果。
4. 逐步回归
当我们处理多个自变量时常使用这种形式的回归。在这种技术中,独立变量的选择是借助于自动过程完成的,其不用涉及到人类干预。
它的专长是通过观察统计值,如R平方,t统计和AIC度量来辨别重要变量。逐步回归基本上适合回归模型,通过基于指定标准一次一个地添加/删除共变量。下面列出了一些最常用的逐步回归方法:
- 标准逐步回归做两件事。它根据需要为每个步骤添加和删除预测变量;
- 向前选择从模型中的最重要的预测变量开始,并为每个步骤添加变量;
- 向后消除从模型中的所有预测变量开始,并删除每个步骤中的最低有效变量。
该建模技术的目的是利用最小数量的预测变量来最大化预测能力。它是处理更高维度数据集的方法之一。
5. Ridge Regression
Ridge回归是当数据受多重共线性(自相关变量高度相关)时常使用的技术。在多重共线性中,即使最小二乘估计(OLS)是无偏的,它们的方差很大,这偏离了观察值远离真实值。通过对回归估计增加一定程度的偏差,Ridge回归减小了标准误差。
上面,我们看到了线性回归方程,它可以表示为:
y=a+b∗x
这个方程也有一个误差项。完整方程式变为:
y=a+b*x+e (error term), [error term is the value needed to correct for a prediction error between the observed and predicted value]
=> y=a+y= a+ b1x1+ b2x2+....+e, for multiple independent variables.
在线性方程中,预测误差可以分解为两个子分量。第一是由于偏差,第二是由于方差。由于这两个或两个分量中的任一个都可能发生预测误差。在这里,我们将讨论由于方差导致的错误。
Ridge回归通过收缩参数λ(lambda)来解决多重共线性问题。看看下面的方程。
=argminβ∈Rp∥y−Xβ∥22Loss+λ∥β∥22Penelty
在这个方程中,我们有两个组成部分。第一个是最小二乘项,另一个是β2(β平方)的总和乘以lambda,其中β是系数。这被添加到最小二乘项以便收缩具有非常低的方差参数。
要点
* 该回归的假设与最小二乘回归相同,除非不假设数据集正态性;
* 它收缩系数的值,但不会达到零,这表明没有特征选择特征;
* 这是一个正则化方法,并使用l2正则化。
6. Lasso Regression
与Ridge回归类似,Lasso(最小绝对收缩和选择算子)也惩罚回归系数的绝对大小。此外,它能够减少变化性和提高线性回归模型的准确性。看看下面的方程:
β=argminβ∈Rp∥y−Xβ∥22Loss+λ∥β∥1Penelty
Lasso回归与Ridge回归的区别在于,它使用的是绝对值惩罚函数而不是平方惩罚函数。这使惩罚(或等价地约束估计的绝对值的和)值导致一些参数估计精确地为零。使用更大的惩罚会让估计进一步的收缩到绝对零。这导致在给定的n个变量中作变量选择。
要点
* 该回归的假设与最小二乘回归相同,除非不假设正态性;
* 它将系数收缩为零(正好为零),这有助于特征选择;
* 这是一个正则化方法,使用l1正则化;
* 如果一批预测变量是高度相关,则Lasso只挑选其中一个,并将其他缩减为零。
7. ElasticNet Regression
ElasticNet是Lasso和Ridge回归技术的混合模型。它是用L1和L2作为正则化训练的。当有多个相关的特征时,Elastic-net是有用的,Lasso可能随机选择其中一个,Elastic-net很可能选择两个。
β^=argminβ(∥y−Xβ∥2+λ2∥β∥2+λ1∥β∥1)
在Lasso和Ridge之间折衷的实际优点是它允许Elastic-Net继承一些Ridge的稳定性。
要点
* 它鼓励在高度相关变量之间的群效应;
* 对所选变量的数量没有限制;
* 它可能遭受双倍收缩率。
如何正确的选择回归模型?
当你只知道一两种技术时生活通常很简。我知道一个培训机构告诉他们的学生:如果结果是连续的就应用线性回归。 如果是二元态的就使用逻辑回归!然而,我们可用的选项数量越多,选择正确的选项就越困难。类似的情况发生在回归模型。
在多种类型的回归模型中,重要的是基于独立和因变量的类型、数据的维度和数据的一些其他基本特征来选择最适合的技术。 以下是您应该练习选择正确回归模型的关键因素:
- 数据探索是建立预测模型的必要组成部分。它应该是你选择正确的模型之前的第一步,如识别变量的关系和影响;
- 为了比较不同模型的拟合程度,我们可以分析不同的指标,如参数的重要性统计、R平方、调整r平方、AIC、BIC和误差项。另一个是Mallow的Cp标准。这本质上是通过将模型与所有可能的子模型(或仔细选择它们)进行比较来检查模型中的可能偏差;
- 交叉验证是评估用于预测的模型的最佳方式。这里您将数据集分为两组(训练集和验证集)。观测值和预测值之间的简单均方差给出一个预测精度的指标;
- 如果您的数据集有多个混杂变量,您不应选择用自动模型选择的方法,因为您不想同时将它们放在一个模型中;
- 这也将取决于你的目标。与高度统计学显着的模型相比,一个相对不强大的模型更容易实现;
- 回归正则化方法(Lasso,Ridge和ElasticNet)在具有高维度和多重共线性的数据集变量上效果更好。
结束语
现在,我希望你对回归有一个总体概述。确定使用哪种技术的最佳方法之一是检查变量族,即离散或连续。
在本文中,我讨论了7种类型的回归和每种技术相关的一些关键点。作为这个行业的新人,我建议你学习这些技术,然后在你的模型中实现它们。
1
线性回归的拟合优度
在进行线性回归中,均需要对回归的拟合效果进行评价。一般通过两个指标进行评价:判定系数(即:R方)、估计标准误差(即:误差项的标准差的估计值)。
2
判定系数
一元回归、多元回归均需要用判定系数来评价其拟合程度。
多重判定系数(multiple coefficient of determination)是多元回归中回归平方和占总平方和的比例,反映了在因变量y的总变异中回归方程所能解释的比例。
需要注意
自变量个数的增加将影响到因变量中被回归方程所解释的变异比例,即会影响判定系数(R方)的大小。当增加自变量时,会使残差平方和减少,从而使R方变大。
也就是说,如果模型中增加一个自变量,即使这个自变量在统计上并不显著,R方也会变大。因此,为避免增加自变量而高估R方,统计学家提出用样本量(n)和自变量的个数(k)去调整R方,计算出调整的多重判定系数(调整的R方),公式略。
调整R方的解释
调整R方的解释与R方类似,不同的是:调整R方同时考虑了样本量(n)和回归中自变量的个数(k)的影响,这使得调整R方永远小于R方,而且调整R方的值不会由于回归中自变量个数的增加而越来越接近1。
因此,在多元回归分析中,通常用调整的多重判定系数来评价拟合效果。
暗藏玄机:R方的平方根
R方的平方根称为多重相关系数,也称为复相关系数,它度量了因变量同k个自变量的相关程度。
注:SPSS中进行相关分析,一般只能得到两两之间的相关系数,因此,若要求复相关系数,可在多元回归中实现!
3
估计标准误差
多元回归中的估计标准误差是对误差项的标准差的一个估计值,在衡量多元回归方程的拟合优度方面起着重要作用。
估计标准误差的含义是根据自变量x1、x2、…、xk来预测因变量y时的平均预测误差。
实例讲解
研究肺活量与身高、体重、胸围的线性模型(此处默认采用进入法作为自变量筛选方法)。主要展示结果中模型拟合优度的解释。
SPSS操作步骤及结果如下:
模型拟合优度的结果解释:
模型汇总的表中,有R方、调整R方、估计的标准误差三个指标。
1)多重判定系数(R Square)R方=0.752,其实际意义是:在肺活量的变异中,能被身高、体重和胸围的多元回归方程所解释的比例为75.2%。R方的平方根就是肺活量与三个自变量(身高、体重和胸围)的复相关系数。
2)调整的多重判定系数(调整的R方)=0.565,其实际意义是:在用样本量和模型中自变量的个数进行调整后,在肺活量的变异中,能被身高、体重和胸围的多元回归方程所解释的比例为56.5%。
3)估计的标准误差=591.277,其实际含义是:根据所建立的多元回归方程,用身高、体重和胸围来预测肺活量时,平均预测误差为591.277毫升。
松哥说:多元线性回归中经常需要对拟合效果进行评价,不可避免会碰到R方与调整R方的结果解释。看过本期之后,你再也不会傻傻分不清了。但是线性模型的优劣判定,不仅仅就看调整R方哦,还有共线性的判定、残差的识别等等呢!一起加油吧!
参考文章http://blog.csdn.net/lynnucas/article/details/47947943
转自:http://blog.csdn.net/jteng/article/details/40823675
此处模型选择我们只考虑模型参数数量,不涉及模型结构的选择。
很多参数估计问题均采用似然函数作为目标函数,当训练数据足够多时,可以不断提高模型精度,但是以提高模型复杂度为代价的,同时带来一个机器学习中非常普遍的问题——过拟合。所以,模型选择问题在模型复杂度与模型对数据集描述能力(即似然函数)之间寻求最佳平衡。
人们提出许多信息准则,通过加入模型复杂度的惩罚项来避免过拟合问题,此处我们介绍一下常用的两个模型选择方法——赤池信息准则(Akaike Information Criterion,AIC)和贝叶斯信息准则(Bayesian Information Criterion,BIC)。
AIC是衡量统计模型拟合优良性的一种标准,由日本统计学家赤池弘次在1974年提出,它建立在熵的概念上,提供了权衡估计模型复杂度和拟合数据优良性的标准。
通常情况下,AIC定义为:
其中k是模型参数个数,L是似然函数。从一组可供选择的模型中选择最佳模型时,通常选择AIC最小的模型。
当两个模型之间存在较大差异时,差异主要体现在似然函数项,当似然函数差异不显著时,上式第一项,即模型复杂度则起作用,从而参数个数少的模型是较好的选择。
一般而言,当模型复杂度提高(k增大)时,似然函数L也会增大,从而使AIC变小,但是k过大时,似然函数增速减缓,导致AIC增大,模型过于复杂容易造成过拟合现象。目标是选取AIC最小的模型,AIC不仅要提高模型拟合度(极大似然),而且引入了惩罚项,使模型参数尽可能少,有助于降低过拟合的可能性。
BIC(Bayesian InformationCriterion)贝叶斯信息准则与AIC相似,用于模型选择,1978年由Schwarz提出。训练模型时,增加参数数量,也就是增加模型复杂度,会增大似然函数,但是也会导致过拟合现象,针对该问题,AIC和BIC均引入了与模型参数个数相关的惩罚项,BIC的惩罚项比AIC的大,考虑了样本数量,样本数量过多时,可有效防止模型精度过高造成的模型复杂度过高。
其中,k为模型参数个数,n为样本数量,L为似然函数。kln(n)惩罚项在维数过大且训练样本数据相对较少的情况下,可以有效避免出现维度灾难现象。
SparseMatrix
Spark的mllib包中提供了机器学习的两种基本数据类型: DenseMatrix(稠密)和 SparseMatrix(稀疏),在初始化对象的时候可以使用Matrices伴生对象产生,先看下示例代码:
import org.apache.spark.mllib.linalg.{Matrix, Matrices}
// Create a dense matrix ((1.0, 2.0), (3.0, 4.0), (5.0, 6.0))
val dm: Matrix = Matrices.dense(3, 2, Array(1.0, 3.0, 5.0, 2.0, 4.0, 6.0))
// Create a sparse matrix ((9.0, 0.0), (0.0, 8.0), (0.0, 6.0))
val sm: Matrix = Matrices.sparse(3, 2, Array(0, 1, 3), Array(0, 2, 1), Array(9, 6, 8))
对于DenseMatrix的初始化参数不难理解,定义行数,列数以及所有元素值,(注,列式优先存储),然后并产生DenseMatrix矩阵;
而对于SparseMatrix的初始化参数有点难理解,并非是我们常见的三元组存储方式,可以先看看源码的定义:
关于参数numRows(行数),numCols(列数),rowIndices(行向索引),values(元素值),这些好理解,难懂的是colPtrs参数,这里通过一图来解释这个参数意义所在。
此部分主要关于MLlib的基础数据结构
1、本地向量
MLlib的本地向量主要分为两种,DenseVector和SparseVector,顾名思义,前者是用来保存稠密向量,后者是用来保存稀疏向量,其创建方式主要有一下三种(三种方式均创建了向量(1.0, 0.0, 2.0):
[plain] view plain copy
- import org.apache.spark.mllib.linalg.{Vector, Vectors}
- //创建一个稠密向量
- val dv : Vector = Vector.dense(1.0,0.0,3.0);
- //创建一个稀疏向量(第一种方式)
- val sv1: Vector = Vector.sparse(3, Array(0,2), Array(1.0,3.0));
- //创建一个稀疏向量(第二种方式)
- val sv2 : Vector = Vector.sparse(3, Seq((0,1.0),(2,3.0)))
对于稠密向量:很直观,你要创建什么,就加入什么,其函数声明为Vector.dense(values : Array[Double])
对于稀疏向量,当采用第一种方式时,3表示此向量的长度,第一个Array(0,2)表示的索引,第二个Array(1.0, 3.0)与前面的Array(0,2)是相互对应的,表示第0个位置的值为1.0,第2个位置的值为3
对于稀疏向量,当采用第二种方式时,3表示此向量的长度,后面的比较直观,Seq里面每一对都是(索引,值)的形式。
tips:由于scala中会默认包含scal.collection.immutalbe.Vector,所以当使用MLlib中的Vector时,需要显式的指明import路径
2、向量标签
向量标签和向量是一起的,简单来说,可以理解为一个向量对应的一个特殊值,这个值的具体内容可以由用户指定,比如你开发了一个算法A,这个算法对每个向量处理之后会得出一个特殊的标记值p,你就可以把p作为向量标签。同样的,更为直观的话,你可以把向量标签作为行索引,从而用多个本地向量构成一个矩阵(当然,MLlib中已经实现了多种矩阵)
其使用代码为:
[plain] view plain copy
- import org.apache.spark.mllib.linag.Vectors
- import org.apache.spark.mllib.regression.LabeledPoint
- val pos = LabeledPoint(1.0, Vectors.dense(1.0, 0.0, 3.0))
对于pos变量,第一个参数1.0的具体含义只有你自己知道咯,可以使行索引,可以使特殊值神马的
从文件中直接读入一个LabeledPoint
MLlib提供了一种快捷的方法,可以让用户直接从文件中读取LabeledPoint格式的数据。规定其输入文件的格式为:
[html] view plain copy
- label index1:value1 index2:value2.....
然后通过
[html] view plain copy
- val test : RDD[LabeledPoint] = MLUtils.loadLibSVMFile(sc, "path")
直接读入即可。
3、本地矩阵
既然是算数运算包,肯定少不了矩阵包,先上代码:
[plain] view plain copy
- import org.apache.spark.mllib.linalg.{Matrix, Matrices}
- val dm : Matrix = Matrices.dense(3,2, Array(1.0,3.0,5.0,2.0,4.0,6.0))
上面的代码段创建了一个稠密矩阵:
1.0 | 2.0 |
3.0 | 4.0 |
5.0 | 6.0 |
很明显,创建的时候是将原来的矩阵按照列变成一个一维矩阵之后再初始化的。
tips:注意,我们创建的是稠密矩阵,不幸的事,MLlib中并没有提供稀疏矩阵的实现,官方说在后续版本中会提供。
4、分布式矩阵
MLlib提供了三种分布式矩阵的实现,依据你数据的不同的特点,你可以选择不同类型的数据:
a、RowMatrix
RowMatrix矩阵只是将矩阵存储起来,要注意的是,此种矩阵不能按照行号访问。(我也不知道为什么这样鸟。。)
[plain] view plain copy
- import org.apache.spark.mllib.linalg.Vector
- import org.apache.spark.mllib.linalg.distributed.RowMatrix
- val rows: RDD[Vector] = ...//
- val mat: RowMatrix = new RowMatrix(rows)
- val m = mat.numRows()
- val n = mat.numCols()
RowMatrix要从RDD[Vector]构造,m是mat的行数,n是mat的列
Multivariate summary statistics
顾名思义,这个类里面包含了矩阵中的很多常见信息,怎么使用呢?
[plain] view plain copy
- import org.apache.spark.mllib.linalg.Matrix
- import org.apache.spark.mllib.linalg.distributed.RowMatrix
- import org.apache.spark.mllib.stat.MultivariateStatisticalSummary
- val mat: RowMatrix = ..
- val summy : MultivariateStatisticalSummary = mat.computeColumnSummaryStatistics()
- println(summy.mean)//平均数
通过这个类,可以得到平均数,矩阵中非0个数,具体的数据看看帮助文档
b、IndexedRowMatrix
IndexedRowMatrix矩阵和RowMatrix矩阵的不同之处在于,你可以通过索引值来访问每一行。其他的,没啥区别。。
c、CoordinateMatrix
当你的数据特别稀疏的时候怎么办?采用这种矩阵吧。先上代码:
[plain] view plain copy
- import org.apache.spark.mllib.linalg.distributed.{CoordinatedMatrix, MatrixEntry}
- val entries : RDD[MatrixEntry] = ..
- val mat: CoordinateMatrix = new CoordinateMatrix(entries)
CoordinateMatrix矩阵中的存储形式是(row,col,value),就是原始的最稀疏的方式,所以如果矩阵比较稠密,别用这种数据格式
正则化(Regularization)是机器学习中抑制过拟合问题的常用算法,常用的正则化方法是在损失函数(Cost Function)中添加一个系数的l1−norm或l2−norm
项,用来抑制过大的模型参数,从而缓解过拟合现象。
l1−norm
的正则项还具有特征选择的能力,而l2−norm的正则项没有。直观上,对于小于1的模型参数,l1−norm的惩罚力度要远远大于l2−norm的惩罚力度,这是l1−norm
特征选择能力的直接驱动。
带正则化的逻辑回归模型(Logistc Regression)损失函数如下式:
J(w)=−Log(1m∑i=1m(p(x(i)))y(i)(1−p(x(i)))1−y(i))+λ2m∥w∥22(1)
下面以梯度下降法和牛顿法为例,说明带正则项的训练算法:
1. 梯度下降法
w(k+1)=w(k)−α∇J(w(k))
系数w
的更新公式为:
w(k+1)=w(k)−α1m∑i=1m(p(x(i))−y(i))x(i)−λmw(k)=w(k)(1−λm)−α1m∑i=1m(p(x(i))−y(i))x(i)
可见,正则化后的迭代算法和没有正则化的迭代形式非常像,唯一的差别在与每次迭代都要多减去一个λmw(k)
。相当于如果当前的wj已经比较大了,那么,w
要先多减去一点,然按梯度方向进行迭代。
另外,上式的正则化项与m
成反比,也就是说,样本数越大,过拟合的问题越小,正则化的作用越弱。
2. 牛顿法
w(k+1)=w(k)−H−1(w(k))∇J(w(k))
引入l2-norm正则项后,一阶导数和Hessian矩阵如下所示:
∇J=1m∑i=1m((p(x(i))−y(i))x(i))−λmw(k)
H=1m∑i=1mp(x(i))(1−p(x(i)))x(i)(x(i))T+λm⎡⎣⎢⎢⎢0000010000...00001⎤⎦⎥⎥⎥
与梯度下降法类似,正则化在牛顿法中也是起到惩罚大的wj
的作用。另外,由于加了正则化项,原来不可逆的Hessian矩阵也变的可逆了。
The problem of overfitting
Linear Regression 和 Logistic Regression 可以解决很多的现实问题,但是有时它们也会遇到一些问题,那就是Overfitting(过拟合)的问题,可能会导致它们的效果变差。
解决过拟合问题的一个可行途径是 Regularization(正规化)的技术,它可以改善或减少过度拟合的问题,从而使算法的表现更好(更接近现实中的表现)。
先说明什么是过拟合问题:(用预测房价的例子)
在上面我们训练了三个hypothesis 从低次(左)到高次(右)
第一个图说明:数据中表现是租房价格随着面积趋于稳定(越往右越平缓),但拟合曲线却不这么认为,曲线表明房价和面积成正比。所以拟合曲线不能很好的表现数据。这个问题是欠拟合问题(underfitting)也可称为高偏差(high bias)问题,意思是它没有很好的拟合训练数据,拟合曲线对数据有非常大的偏差。
第三个图说明:拟合曲线很好的拟合了数据,这个样本只有四个数据,用一个四次多项式,我们可以很好的拟合数据(可以说没有任何的偏差,拟合曲线对所有的样本都进行了正确的预测)但我们比不认为它是一个好模型。这个问题是过拟合问题(overfitting)也可称为高方差(high variance)问题,这会面临函数太过庞大的问题。
第二个图说明:正好合适。
过拟合就是说:训练的方程总数能很好的拟合训练数据,代价函数J(θ)几乎为零。它对训练集的拟合太好了,以至于它在新的数据上泛化能力不足,指的是一个假设模型能够应用到新样本的能力不足。
在逻辑回归中我们也面临这样的问题,可以看到第一个图是欠拟合,第三个图是过拟合,在只有很少参数的情况下,参数少于三个时,我们可以通过画图来识别欠拟合问题和过拟合问题。
避免overfitting的办法有两个:
1.减少选取的变量数量:用人工选取特征(效率低),用算法选取特征.缺点是:在舍弃特征的同时,也把其中包含的信息一并舍弃。
2.应用regularization 技术。
Cost Function
正规化的思想其实就是对参数做惩罚,让拟合曲线变的更圆滑,有更强的泛化能力。
在上图中,加入了对 theta3 和 theta4 的惩罚,拟合曲线由蓝色变成粉红色,而且最后得到的theta3 和 theta4 大概接近于零。
更一般的表示是
这是在Linear regression 和 Logisitic regression 中广泛应用的增加了正规化的代价函数的表现形式。
λ是正规化参数,它在两个目标之间做平衡,一是想让假设更好的拟合训练数据(即代价函数变小) ,二是保持参数值较小,防止其过拟合。
当λ大时,惩罚加重,更好的实现第二个目标,使假设的形式保持简单
当λ小时,更好的实现第一个目标,但过拟合风险加大
当λ很大时,所有被惩罚的项都趋于零,这时假设就会欠拟合
Regularization 在 Linear regression 中的应用
线性回归有两种方法求解拟合曲线的参数:
1.梯度下降法
在加入正规化的思想后优化代价函数:
梯度下降变成:
在这里把theta0单独拿出来,因为在正规化中没有theta0 这一项,在实际操作中也可以加入对 theta0 的惩罚,但对最后的结果不会有太大的影响。
对其做变形:
可以看到加入正规化后梯度函数可以被分成两部分,后一部分是我们已经知道的,而前一部分是说每次更新theta(j)时,我们都对上一轮的theta(j)做了一个处理,具体就是把它和一个小于1大于0的数相乘(相当于对参数进行了压缩,然后在更新)。
2. 正规方程法
这是求解参数的另一种方法,可以看到,加入正规化方法后,相当于在原来的方程中多加了一项就是,λ乘一个单位矩阵。
加入正规化项还有一个好处,就是以前正规方程法中有一个限制,要处理的数据集矩阵一定要是非奇异的(XTX要可逆),而现在加入正规化项后,没有了这个限制。
Regularization 在 Logistic regression 中的应用
没有加入正规化项的代价函数:
加入正规化项后代价函数变成:
应用梯度下降算法求 theta 的值:
正则化方法:防止过拟合,提高泛化能力
在训练数据不够多时,或者overtraining时,常常会导致overfitting(过拟合)。其直观的表现如下图所示,随着训练过程,网络在training data上的error渐渐减小,但是在验证集上的error却反而渐渐增大——因为训练出来的网络过拟合了训练集,对训练集外的数据却不work。
为了防止overfitting,可以用的方法有很多,下文就将以此展开。有一个概念需要先说明,在机器学习算法中,我们常常将原始数据集分为三部分:training data、validation data,testing data。这个validation data是什么?它其实就是用来避免过拟合的,在训练过程中,我们通常用它来确定一些超参数(比如根据validation data上的accuracy来确定early stopping的epoch大小、根据validation data确定learning rate等等)。那为啥不直接在testing data上做这些呢?因为如果在testing data做这些,那么随着训练的进行,我们的网络实际上就是在一点一点地overfitting我们的testing data,导致最后得到的testing accuracy没有任何参考意义。因此,training data的作用是计算梯度更新权重,validation data如上所述,testing data则给出一个accuracy以判断网络的好坏。
避免过拟合的方法有很多:early stopping、数据集扩增(Data augmentation)、正则化(Regularization)包括L1、L2(L2 regularization也叫weight decay),dropout。
L2 regularization(权重衰减)
L2正则化就是在代价函数后面再加上一个正则化项:
C0代表原始的代价函数,后面那一项就是L2正则化项,它是这样来的:所有参数w的平方的和,除以训练集的样本大小n。λ就是正则项系数,权衡正则项与C0项的比重。另外还有一个系数1/2,1/2经常会看到,主要是为了后面求导的结果方便,后面那一项求导会产生一个2,与1/2相乘刚好凑整。
L2正则化项是怎么避免overfitting的呢?我们推导一下看看,先求导:
可以发现L2正则化项对b的更新没有影响,但是对于w的更新有影响:
在不使用L2正则化时,求导结果中w前系数为1,现在w前面系数为 1?ηλ/n ,因为η、λ、n都是正的,所以 1?ηλ/n小于1,它的效果是减小w,这也就是权重衰减(weight decay)的由来。当然考虑到后面的导数项,w最终的值可能增大也可能减小。
另外,需要提一下,对于基于mini-batch的随机梯度下降,w和b更新的公式跟上面给出的有点不同:
对比上面w的更新公式,可以发现后面那一项变了,变成所有导数加和,乘以η再除以m,m是一个mini-batch中样本的个数。
到目前为止,我们只是解释了L2正则化项有让w“变小”的效果,但是还没解释为什么w“变小”可以防止overfitting?人们普遍认为:更小的权值w,从某种意义上说,表示网络的复杂度更低,对数据的拟合刚刚好(这个法则也叫做奥卡姆剃刀)。而在实际应用中,也验证了这一点,L2正则化的效果往往好于未经正则化的效果。
L1 regularization
在原始的代价函数后面加上一个L1正则化项,即所有权重w的绝对值的和,乘以λ/n(这里不像L2正则化项那样,需要再乘以1/2,具体原因上面已经说过。)
同样先计算导数:
上式中sgn(w)表示w的符号。那么权重w的更新规则为:
比原始的更新规则多出了η * λ * sgn(w)/n这一项。当w为正时,更新后的w变小。当w为负时,更新后的w变大——因此它的效果就是让w往0靠,使网络中的权重尽可能为0,也就相当于减小了网络复杂度,防止过拟合。
另外,上面没有提到一个问题,当w为0时怎么办?当w等于0时,|W|是不可导的,所以我们只能按照原始的未经正则化的方法去更新w,这就相当于去掉η*λ*sgn(w)/n这一项,所以我们可以规定sgn(0)=0,这样就把w=0的情况也统一进来了。(在编程的时候,令sgn(0)=0,sgn(w>0)=1,sgn(w<0)=-1)
Dropout
L1、L2正则化是通过修改代价函数来实现的,而Dropout则是通过修改神经网络本身来实现的,它是在训练网络时用的一种技巧(trike)。它的流程如下:
假设我们要训练上图这个网络,在训练开始时,我们随机地“删除”一半的隐层单元,视它们为不存在,得到如下的网络:
保持输入输出层不变,按照BP算法更新上图神经网络中的权值(虚线连接的单元不更新,因为它们被“临时删除”了)。
以上就是一次迭代的过程,在第二次迭代中,也用同样的方法,只不过这次删除的那一半隐层单元,跟上一次删除掉的肯定是不一样的,因为我们每一次迭代都是“随机”地去删掉一半。第三次、第四次……都是这样,直至训练结束。
以上就是Dropout,它为什么有助于防止过拟合呢?可以简单地这样解释,运用了dropout的训练过程,相当于训练了很多个只有半数隐层单元的神经网络(后面简称为“半数网络”),每一个这样的半数网络,都可以给出一个分类结果,这些结果有的是正确的,有的是错误的。随着训练的进行,大部分半数网络都可以给出正确的分类结果,那么少数的错误分类结果就不会对最终结果造成大的影响。
更加深入地理解,可以看看Hinton和Alex两牛2012的论文《ImageNet Classification with Deep Convolutional Neural Networks》
数据集扩增(data augmentation)
“有时候不是因为算法好赢了,而是因为拥有更多的数据才赢了。”
不记得原话是哪位大牛说的了,hinton?从中可见训练数据有多么重要,特别是在深度学习方法中,更多的训练数据,意味着可以用更深的网络,训练出更好的模型。
既然这样,收集更多的数据不就行啦?如果能够收集更多可以用的数据,当然好。但是很多时候,收集更多的数据意味着需要耗费更多的人力物力,有弄过人工标注的同学就知道,效率特别低,简直是粗活。
所以,可以在原始数据上做些改动,得到更多的数据,以图片数据集举例,可以做各种变换,如:
-
将原始图片旋转一个小角度
-
添加随机噪声
-
一些有弹性的畸变(elastic distortions),论文《Best practices for convolutional neural networks applied to visual document analysis》对MNIST做了各种变种扩增。
-
截取(crop)原始图片的一部分。比如DeepID中,从一副人脸图中,截取出了100个小patch作为训练数据,极大地增加了数据集。感兴趣的可以看《Deep learning face representation from predicting 10,000 classes》.
更多数据意味着什么?
用50000个MNIST的样本训练SVM得出的accuracy94.48%,用5000个MNIST的样本训练NN得出accuracy为93.24%,所以更多的数据可以使算法表现得更好。在机器学习中,算法本身并不能决出胜负,不能武断地说这些算法谁优谁劣,因为数据对算法性能的影响很大。
转载请注明出处:http://blog.csdn.net/u012162613/article/details/44261657
LASSO回归
2016-10-10 20:46
作者简介:
侯澄钧,毕业于俄亥俄州立大学运筹学博士项目, 目前在美国从事个人保险产品(Personal Line)相关的数据分析,统计建模,产品算法优化方面的工作。
目录:
-
模型简介
-
线性回归
-
Logistic回归
-
Elstic Net模型家族简介
-
学习资料
1.模型简介
Kaggle网站 (https://www.kaggle.com/ )成立于2010年,是当下最流行的进行数据发掘和预测模型竞赛的在线平台。 与Kaggle合作的公司可以在网站上提出一个问题或者目标,同时提供相关数据,来自世界各地的计算机科学家、统计学家和建模爱好者,将受领任务,通过比较模型的某些性能参数,角逐出优胜者。 通过大量的比赛,一系列优秀的数据挖掘模型脱颖而出,受到广大建模者的认同,被普遍应用在各个领域。 在保险行业中用于拟合广义线性模型的LASSO回归就是其中之一。
LASSO回归的特点是在拟合广义线性模型的同时进行变量筛选(Variable Selection)和复杂度调整(Regularization)。 因此,不论目标因变量(dependent/response varaible)是连续的(continuous),还是二元或者多元离散的(discrete), 都可以用LASSO回归建模然后预测。 这里的变量筛选是指不把所有的变量都放入模型中进行拟合,而是有选择的把变量放入模型从而得到更好的性能参数。 复杂度调整是指通过一系列参数控制模型的复杂度,从而避免过度拟合(Overfitting)。 对于线性模型来说,复杂度与模型的变量数有直接关系,变量数越多,模型复杂度就越高。 更多的变量在拟合时往往可以给出一个看似更好的模型,但是同时也面临过度拟合的危险。 此时如果用全新的数据去验证模型(Validation),通常效果很差。 一般来说,变量数大于数据点数量很多,或者某一个离散变量有太多独特值时,都有可能过度拟合。
LASSO回归复杂度调整的程度由参数λ来控制,λ越大对变量较多的线性模型的惩罚力度就越大,从而最终获得一个变量较少的模型。 LASSO回归与Ridge回归同属于一个被称为Elastic Net的广义线性模型家族。 这一家族的模型除了相同作用的参数λ之外,还有另一个参数α来控制应对高相关性(highly correlated)数据时模型的性状。 LASSO回归α=1,Ridge回归α=0,一般Elastic Net模型0<α<1。 这篇文章主要介绍LASSO回归,所以我们集中关注α=1的情况,对于另外两种模型的特点和如何选取最优α值,我会在第四节做一些简单阐述。
目前最好用的拟合广义线性模型的R package是glmnet,由LASSO回归的发明人,斯坦福统计学家Trevor Hastie领衔开发。 它的特点是对一系列不同λ值进行拟合,每次拟合都用到上一个λ值拟合的结果,从而大大提高了运算效率。 此外它还包括了并行计算的功能,这样就能调动一台计算机的多个核或者多个计算机的运算网络,进一步缩短运算时间。
下面我们就通过一个线性回归和一个Logistic回归的例子,了解如何使用glmnet拟合LASSO回归。 另外,之后的系列文章我打算重点介绍非参数模型(nonparametric model)中的一种,Gradient Boosting Machine。 然后通过一个保险行业的实例,分享一些实际建模过程中的经验,包括如何选取和预处理数据,如何直观得分析自变量与因变量之间的关系,如何避免过度拟合,以及如何衡量和选取最终模型等。
2.线性回归
我们从最简单的线性回归(Linear Regression)开始了解如何使用glmnet拟合LASSO回归模型,所以此时的连接函数(Link Function)就是恒等,或者说没有连接函数,而误差的函数分布是正态分布。
首先我们装载glmnet package,然后读入试验用数据“LinearExample.RData”,下载链接(https://github.com/chengjunhou/Tutorial/blob/master/LASSO/LinearExample.RData):
library(glmnet) load("LinearExample.RData")
之后在workspace里我们会得到一个100×20的矩阵x作为输入自变量,100×1的矩阵y作为目标因变量。 矩阵x代表了我们有100个数据点,每个数据点有20个统计量(feature)。现在我们就可以用函数glmnet()建模了:
fit = glmnet(x, y, family="gaussian", nlambda=50, alpha=1)
好,建模完毕,至此结束本教程 :)
觉得意犹未尽的朋友可以接着看下面的内容。
参数family规定了回归模型的类型:
family="gaussian"适用于一维连续因变量(univariate)
family="mgaussian"适用于多维连续因变量(multivariate)
family="poisson"适用于非负次数因变量(count)
family="binomial"适用于二元离散因变量(binary)
family="multinomial"适用于多元离散因变量(category)
参数nlambda=50让算法自动挑选50个不同的λ值,拟合出50个系数不同的模型。 alpha=1输入α值,1是它的默认值。 值得注意的是,glmnet只能接受数值矩阵作为模型输入,如果自变量中有离散变量的话,需要把这一列离散变量转化为几列只含有0和1的向量,这个过程叫做One Hot Encoding。通过下面这个小例子,你可以了解One Hot Encoding的原理以及方法:
df=data.frame(Factor=factor(1:5), Character=c("a","a","b","b","c"), Logical=c(T,F,T,T,T), Numeric=c(2.1,2.3,2.5,4.1,1.1)) model.matrix(~., df) ## (Intercept) Factor2 Factor3 Factor4 Factor5 Characterb Characterc ## 1 1 0 0 0 0 0 0 ## 2 1 1 0 0 0 0 0 ## 3 1 0 1 0 0 1 0 ## 4 1 0 0 1 0 1 0 ## 5 1 0 0 0 1 0 1 ## LogicalTRUE Numeric ## 1 1 2.1 ## 2 0 2.3 ## 3 1 2.5 ## 4 1 4.1 ## 5 1 1.1 ## attr(,"assign") ## [1] 0 1 1 1 1 2 2 3 4 ## attr(,"contrasts") ## attr(,"contrasts")$Factor ## [1] "contr.treatment" ## ## attr(,"contrasts")$Character ## [1] "contr.treatment" ## ## attr(,"contrasts")$Logical ## [1] "contr.treatment"
除此之外,如果我们想让模型的变量系数都在同一个数量级上,就需要在拟合前对数据的每一列进行标准化(standardize),即对每个列元素减去这一列的均值然后除以这一列的标准差。这一过程可以通过在glmnet()函数中添加参数standardize = TRUE来实现。
回到我们的拟合结果fit。作为一个R对象,我们可以把它当作很多函数的输入。比如说,我们可以查看详细的拟合结果:
print(fit) ## ## Call: glmnet(x = x, y = y, family = "gaussian", alpha = 1, nlambda = 50) ## ## Df %Dev Lambda ## [1,] 0 0.0000 1.631000 ## [2,] 2 0.1476 1.351000 ## [3,] 2 0.2859 1.120000 ## [4,] 4 0.3946 0.927900 ## [5,] 5 0.5198 0.768900 ## [6,] 6 0.6303 0.637100 ## [7,] 6 0.7085 0.528000 ## [8,] 7 0.7657 0.437500 ## [9,] 7 0.8081 0.362500 ## [10,] 7 0.8373 0.300400 ## [11,] 7 0.8572 0.248900 ## [12,] 8 0.8721 0.206300 ## [13,] 8 0.8833 0.170900 ## [14,] 8 0.8909 0.141600 ## [15,] 8 0.8962 0.117400 ## [16,] 9 0.8999 0.097250 ## [17,] 9 0.9027 0.080590 ## [18,] 10 0.9046 0.066780 ## [19,] 11 0.9065 0.055340 ## [20,] 15 0.9081 0.045850 ## [21,] 16 0.9095 0.038000 ## [22,] 17 0.9105 0.031490 ## [23,] 18 0.9113 0.026090 ## [24,] 19 0.9119 0.021620 ## [25,] 19 0.9123 0.017910 ## [26,] 19 0.9126 0.014840 ## [27,] 19 0.9128 0.012300 ## [28,] 19 0.9129 0.010190 ## [29,] 19 0.9130 0.008446 ## [30,] 19 0.9131 0.006999 ## [31,] 20 0.9131 0.005800 ## [32,] 20 0.9131 0.004806 ## [33,] 20 0.9132 0.003982 ## [34,] 20 0.9132 0.003300 ## [35,] 20 0.9132 0.002735 ## [36,] 20 0.9132 0.002266
每一行代表了一个模型。列Df是自由度,代表了非零的线性模型拟合系数的个数。 列%Dev代表了由模型解释的残差的比例,对于线性模型来说就是模型拟合的R2(R-squred)。它在0和1之间,越接近1说明模型的表现越好,如果是0,说明模型的预测结果还不如直接把因变量的均值作为预测值来的有效。 列lambda当然就是每个模型对应的λλ值。 我们可以看到,随着lambda的变小,越来越多的自变量被模型接纳进来,%Dev也越来越大。 第31行时,模型包含了所有20个自变量,%Dev也在0.91以上。 其实我们本应该得到50个不同的模型,但是连续几个%Dev变化很小时glmnet()会自动停止。 分析模型输出我们可以看到当Df大于9的时候,%Dev就达到了0.9,而且继续缩小lambda,即增加更多的自变量到模型中,也不能显著提高%Dev。 所以我们可以认为当$0.1时,得到的包含9个自变量的模型,可以相当不错的描述这组数据。
我们也可以通过指定λ值,抓取出某一个模型的系数:
coef(fit, s=c(fit$lambda[16],0.1)) ## 21 x 2 sparse Matrix of class "dgCMatrix" ## 1 2 ## (Intercept) 0.150672014 0.150910983 ## V1 1.322088892 1.320532088 ## V2 . . ## V3 0.677692624 0.674955779 ## V4 . . ## V5 -0.819674385 -0.817314761 ## V6 0.523912698 0.521565712 ## V7 0.007293509 0.006297101 ## V8 0.321450451 0.319344250 ## V9 . . ## V10 . . ## V11 0.145727982 0.142574921 ## V12 . . ## V13 . . ## V14 -1.061733786 -1.060031309 ## V15 . . ## V16 . . ## V17 . . ## V18 . . ## V19 . . ## V20 -1.025371209 -1.021771038
需要注意的是,我们把指定的λ值放在s=里,因为在后面Logistic回归的部分我们还用到了s="lambda.min"的方法指定λ的值。 当指定的λ值不在fit$lambda中时,对应的模型系数由Linear Interpolation近似得到。 我们还可以做图观察这50个模型的系数是如何变化的:
plot(fit, xvar="lambda", label=TRUE)
图中的每一条曲线代表了每一个自变量系数的变化轨迹,纵坐标是系数的值,下横坐标是log(λ),上横坐标是此时模型中非零系数的个数。 我们可以看到,黑线代表的自变量1在λ值很大时就有非零的系数,然后随着λ值变小不断变大。 我们还可以尝试用xvar=“norm”和xvar=“dev”切换下横坐标。
接下来当然就是指定λ值,然后对新数据进行预测了:
nx = matrix(rnorm(5*20),5,20) predict(fit, newx=nx, s=c(fit$lambda[16],0.1)) ## 1 2 ## [1,] 1.677334 1.669136 ## [2,] 1.308665 1.308562 ## [3,] -1.091936 -1.089214 ## [4,] -2.587534 -2.582384 ## [5,] 3.747690 3.735114
下面我们再来看几个glmnet()函数的其他功能。 使用upper.limits和lower.limits,我们可以指定模型系数的上限与下限:
lfit=glmnet(x, y, lower=-.7, upper=.5) plot(lfit, xvar="lambda", label=TRUE)
上限与下限可以是一个值,也可以是一个向量,向量的每一个值作为对应自变量的参数上下限。 有时,在建模之前我们就想凸显某几个自变量的作用,此时我们可以调整惩罚参数。 每个自变量的默认惩罚参数是1,把其中的某几个量设为0将使得相应的自变量不遭受任何惩罚:
p.fac = rep(1, 20) p.fac[c(5, 10, 15)] = 0 pfit = glmnet(x, y, penalty.factor=p.fac) plot(pfit, xvar="lambda", label = TRUE)
我们可以看到,自变量5/10/15的系数一直不为0,而其他的参数系数绝对值随着λ值变小而变大。
3.Logistic回归
当面对离散因变量时,特别是面对二元因变量(Yes/No)这样的问题时,Logistic回归被广泛使用。 此时我们用family="binomial"来应对这种目标因变量是二项分布(binomial)的情况。
试验用数据“LogisticExample.RData”里储存了100×30的矩阵x,和元素是0/1长度是100的向量y,下载链接(https://github.com/chengjunhou/Tutorial/blob/master/LASSO/LogisticExample.RData):
load("LogisticExample.RData")
我们可以用上一节介绍的glmnet()函数来拟合模型,然后选取最优的λ值。但是在这种方法下,所有数据都被用来做了一次拟合,这很有可能会造成过拟合的。在这种情况下,当我们把得到的模型用来预测全新收集到的数据时,结果很可能会不尽如人意。 所以只要条件允许,我们都会用交叉验证(Cross Validation)拟合进而选取模型,同时对模型的性能有一个更准确的估计。
cvfit = cv.glmnet(x, y, family = "binomial", type.measure = "class")
这里的type.measure是用来指定交叉验证选取模型时希望最小化的目标参量,对于Logistic回归有以下几种选择:
type.measure=deviance 使用deviance,即-2倍的Log-likelihood
type.measure=mse 使用拟合因变量与实际应变量的mean squred error
type.measure=mae 使用mean absolute error
type.measure=class 使用模型分类的错误率(missclassification error)
type.measure=auc 使用area under the ROC curve,是现在最流行的综合考量模型性能的一种参数
除此之外,在cv.glmnet()里我们还可以用nfolds指定fold数,或者用foldid指定每个fold的内容。 因为每个fold间的计算是独立的,我们还可以考虑运用并行计算来提高运算效率,使用parallel=TRUE可以开启这个功能。 但是我们需要先装载package doParallel。 下面我们给出在Windows操作系统和Linux操作系统下开启并行计算的示例:
library(doParallel) # Windows System cl <- makeCluster(6) registerDoParallel(cl) cvfit = cv.glmnet(x, y, family = "binomial", type.measure = "class", parallel=TRUE) stopCluster(cl) # Linux System registerDoParallel(cores=8) cvfit = cv.glmnet(x, y, family = "binomial", type.measure = "class", parallel=TRUE) stopImplicitCluster()
同样的,我们可以绘制cvfit对象:
plot(cvfit)
因为交叉验证,对于每一个λ值,在红点所示目标参量的均值左右,我们可以得到一个目标参量的置信区间。 两条虚线分别指示了两个特殊的λ值:
c(cvfit$lambda.min, cvfit$lambda.1se) ## [1] 0.02578548 0.04945423
lambda.min是指在所有的λ值中,得到最小目标参量均值的那一个。 而lambda.1se是指在lambda.min一个方差范围内得到最简单模型的那一个λ值。 因为λ值到达一定大小之后,继续增加模型自变量个数即缩小λ值,并不能很显著的提高模型性能,lambda.1se给出的就是一个具备优良性能但是自变量个数最少的模型。 同样的,我们可以指定λ值然后进行预测:
predict(cvfit, newx=x[1:5,], type="response", s="lambda.1se") ## 1 ## [1,] 0.2671902 ## [2,] 0.8653125 ## [3,] 0.6252242 ## [4,] 0.1851518 ## [5,] 0.6409101
这里的type有以下几种选择:
type=link 给出线性预测值,即进行Logit变换之前的值
type=response 给出概率预测值,即进行Logit变换之后的值
type=class 给出0/1预测值
type=coefficients 罗列出给定λ值时的模型系数
type=coefficients 罗列出给定λ值时,不为零模型系数的下标
另外,当已有了一个模型之后,我们又得到了几个新的自变量,如果想知道这些新变量能否在第一个模型的基础上提高模型性能,可以把第一个模型的预测因变量作为一个向量放到函数选项offset中,再用glmnet或者cv.glmnet进行拟合。
4.Elstic Net模型家族简介
在这一节我们会了解一些关于Elastic Net模型家族的理论。首先我们先来看看一般线性Elastic Net模型的目标函数:
目标函数的第一行与传统线性回归模型完全相同,即我们希望得到相应的自变量系数β,以此最小化实际因变量y与预测应变量βx之间的误差平方和。 而线性Elastic Net与线性回归的不同之处就在于有无第二行的这个约束,线性Elastic Net希望得到的自变量系数是在由t控制的一个范围内。 这一约束也是Elastic Net模型能进行复杂度调整,LASSO回归能进行变量筛选和复杂度调整的原因。 我们可以通过下面的这张图来解释这个道理:
先看左图,假设一个二维模型对应的系数是β1和β2,然后是最小化误差平方和的点,即用传统线性回归得到的自变量系数。 但我们想让这个系数点必须落在蓝色的正方形内,所以就有了一系列围绕的同心椭圆,其中最先与蓝色正方形接触的点,就是符合约束同时最小化误差平方和的点。 这个点就是同一个问题LASSO回归得到的自变量系数。 因为约束是一个正方形,所以除非相切,正方形与同心椭圆的接触点往往在正方形顶点上。而顶点又落在坐标轴上,这就意味着符合约束的自变量系数有一个值是0。 所以这里传统线性回归得到的是β1和β2都起作用的模型,而LASSO回归得到的是只有β2有作用的模型,这就是LASSO回归能筛选变量的原因。
而正方形的大小就决定了复杂度调整的程度。假设这个正方形极小,近似于一个点,那么LASSO回归得到的就是一个只有常量(intercept)而其他自变量系数都为0的模型,这是模型简化的极端情况。 由此我们可以明白,控制复杂度调整程度的λ值与约束大小t是呈反比的,即λ值越大对参数较多的线性模型的惩罚力度就越大,越容易得到一个简单的模型。
另外,我们之前提到的参数α就决定了这个约束的形状。刚才提到LASSO回归(α=1)的约束是一个正方形,所以更容易让约束后的系数点落在顶点上,从而起到变量筛选或者说降维的目的。 而Ridge回归(α=0)的约束是一个圆,与同心椭圆的相切点会在圆上的任何位置,所以Ridge回归并没有变量筛选的功能。 相应的,当几个自变量高度相关时,LASSO回归会倾向于选出其中的任意一个加入到筛选后的模型中,而Ridge回归则会把这一组自变量都挑选出来。 至于一般的Elastic Net模型(0<α<1),其约束的形状介于正方形与圆形之间,所以其特点就是在任意选出一个自变量或者一组自变量之间权衡。
下面我们就通过Logistic回归一节的例子,来看看这几种模型会得到怎样不同的结果:
# CV for 11 alpha value for (i in 0:10) { assign(paste("cvfit", i, sep=""), cv.glmnet(x, y, family="binomial", type.measure="class", alpha=i/10)) } # Plot Solution Paths par(mfrow=c(3,1)) plot(cvfit10, main="LASSO") plot(cvfit0, main="Ridge") plot(cvfit5, main="Elastic Net")
通过比较可以看出,Ridge回归得到的模型一直都有30个自变量,而α=0.5时的Elastic Net与LASSO回归有相似的性能。
5.学习资料
本文的图片来自Trevor Hastie教授的著作“The Elements of Statistical Learning”,我觉得这本书在parametric model这一方向的阐述尤其精彩,对于其他数据挖掘方向也有十分全面的介绍。
更全面关于glmnet的应用,可以参考 https://web.stanford.edu/~hastie/glmnet/glmnet_alpha.html ,本文的两个例子也出自这篇vignette。
关于Elastic Net模型家族的特点和优劣,可以参考 http://www4.stat.ncsu.edu/~post/josh/LASSO_Ridge_Elastic_Net_-_Examples.html 。