sklearnNormalization - juedaiyuer/researchNote GitHub Wiki

#sklearn正则化#

正则化的过程是将每个样本缩放到单位范数(每个样本的范数为1),如果后面要使用如二次型(点积)或者其它核方法计算两个样本之间的相似性这个方法会很有用

sklearn.preprocessing

主要思想

对每个样本计算其p,也就是范数,然后对该样本中每个元素除以该范数

处理的结果使得每个处理后的样本的范数(l1-norm,l2-norm)等于1

主要应用

文本分类和聚类中。例如,对于两个TF-IDF向量的l2-norm进行点积,就可以得到这两个向量的余弦相似性

范数定义

ml/norm.png

计算公式

||x||p=(|x1|^p+|x2|^p+...)^1/p

##sklearn中的调用##

使用preprocessing.normalize()函数对指定数据进行转换

>>> from sklearn import preprocessing
>>> import numpy as np
>>> X = [[ 1., -1.,  2.],
...      [ 2.,  0.,  0.],
...      [ 0.,  1., -1.]]
>>> X_normalized = preprocessing.normalize(X, norm='l2')
>>> X_normalized
array([[ 0.40824829, -0.40824829,  0.81649658],
       [ 1.        ,  0.        ,  0.        ],
       [ 0.        ,  0.70710678, -0.70710678]])

使用processing.Normalizer()类实现对训练集和测试集的拟合和转换

>>> normalizer = preprocessing.Normalizer().fit(X)
>>> normalizer
Normalizer(copy=True, norm='l2')
>>> normalizer.transform(X)
array([[ 0.40824829, -0.40824829,  0.81649658],
       [ 1.        ,  0.        ,  0.        ],
       [ 0.        ,  0.70710678, -0.70710678]])
>>> normalizer.transform([-1.,  1., 0.](/juedaiyuer/researchNote/wiki/-1.,--1.,-0.))
array([-0.70710678,  0.70710678,  0.        ](/juedaiyuer/researchNote/wiki/-0.70710678,--0.70710678,--0.--------))

可以直接调用之后,开始了解相关的背景知识...

##监督学习最小化目标函数##

ml/SupervisedLMinObjFunction.png

第一项L衡量模型(分类或回归)对第i个样本的预测值和真实的标签之间的误差。因为我们的模型是要拟合我们的训练样本,所以要求这一项最小。不仅要保证训练误差最小,更希望模型的测试误差小。所以加入了第二项,也就是对参数w的规则化函数来约束模型尽量的简单

###Loss函数###

机器学习的大部分带参模型都和这个不但形似,而且神似。是的,其实大部分无非就是变换这两项而已。

不同的loss函数,具有不同的拟合特性

Square loss:最小二乘

Hinge Loss:SVM

exp-loss:Boosting

log-loss:Logistic regression

...

###规则项Ω(w)###

规则化项可以是模型参数向量的范数,论文中常见的都聚集在:零范数、一范数、二范数、迹范数、Frobenius范数和核范数等等


##L1,L2正则化介绍##

监督机器学习问题:规则化参数的同时最小化误差(minimizeyour error while regularizing your parameters)

最小化误差是为了让我们的模型拟合我们的训练数据,而规则化参数是防止我们的模型过分拟合我们的训练数据

因为参数太多,会导致我们的模型复杂度上升,容易过拟合,也就是我们的训练误差会很小。但训练误差小并不是我们的最终目标,我们的目标是希望模型的测试误差小,也就是能准确的预测新的样本。所以,我们需要保证模型“简单”的基础上最小化训练误差,这样得到的参数才具有好的泛化性能(也就是测试误差也小)

模型简单

通过规则函数实现,规则项使用约束我们的模型特性,将人的先验知识融入到模型的学习中,将学习到的模型具有人想要的特性,例如稀疏,低秩,平滑...

人的先验知识

要知道,有时候人的先验是非常重要的。前人的经验会让你少走很多弯路,这就是为什么我们平时学习最好找个大牛带带的原因。一句点拨可以为我们拨开眼前乌云,还我们一片晴空万里,醍醐灌顶。对机器学习也是一样,如果被我们人稍微点拨一下,它肯定能更快的学习相应的任务。只是由于人和机器的交流目前还没有那么直接的方法,目前这个媒介只能由规则项来担当了。

多角度看待规则化

规则化符合奥卡姆剃刀(Occam's razor)原理。这名字好霸气,razor!不过它的思想很平易近人:在所有可能选择的模型中,我们应该选择能够很好地解释已知数据并且十分简单的模型。从贝叶斯估计的角度来看,规则化项对应于模型的先验概率。民间还有个说法就是,规则化是结构风险最小化策略的实现,是在经验风险上加一个正则化项(regularizer)或惩罚项(penalty term)

不仅要训练误差小,而且要测量误差小

从贝叶斯估计的角度来看,规则化项对应于模型的先验概率

正则化模型

正则化就是把额外的约束或者惩罚项加到已有模型(损失函数)上,以防止过拟合并提高泛化能力。损失函数由原来的E(X,Y)变为E(X,Y)+alpha||w||,w是模型系数组成的向量(有些地方也叫参数parameter,coefficients),||·||一般是L1或者L2范数,alpha是一个可调的参数,控制着正则化的强度。alpha过大容易欠拟合,alpha过小容易过拟合。当用在线性模型上时,L1正则化和L2正则化也称为Lasso和Ridge

L1:向量中各个元素的绝对值之和 =》非零元素较少 =》 稀疏化

L2:向量中各个元素的平方和的开放 =》每个元素都很小 =》防止过拟合

线性模型

  • L1正则化 Lasso
  • L2正则化 Ridge

##L0范数##

L0范数是指向量中非0的元素的个数。如果我们用L0范数来规则化一个参数矩阵W的话,就是希望W的大部分元素都是0。这太直观了,太露骨了吧,换句话说,让参数W是稀疏的。OK,看到了“稀疏”二字,大家都应该从当下风风火火的“压缩感知”和“稀疏编码”中醒悟过来,原来用的漫山遍野的“稀疏”就是通过这玩意来实现的。但你又开始怀疑了,是这样吗?看到的papers世界中,稀疏不是都通过L1范数来实现吗?脑海里是不是到处都是||W||1影子呀!几乎是抬头不见低头见。没错,这就是这节的题目把L0和L1放在一起的原因,因为他们有着某种不寻常的关系。那我们再来看看L1范数是什么?它为什么可以实现稀疏?为什么大家都用L1范数去实现稀疏,而不是L0范数呢?


##L1范数##

L1范数和L0范数可以实现稀疏,L1因具有比L0更好的优化求解特性而被广泛应用

L1范数是指向量中各个元素绝对值之和,也有个美称叫“稀疏规则算子”(Lasso regularization)。现在我们来分析下这个价值一个亿的问题:为什么L1范数会使权值稀疏?有人可能会这样给你回答“它是L0范数的最优凸近似”。实际上,还存在一个更美的回答:任何的规则化算子,如果他在Wi=0的地方不可微,并且可以分解为一个“求和”的形式,那么这个规则化算子就可以实现稀疏。这说是这么说,W的L1范数是绝对值,|w|在w=0处是不可微,但这还是不够直观,这里因为我们需要和L2范数进行对比分析

既然L0可以实现稀疏,为什么不用L0,而要用L1

一是因为L0范数很难优化求解(NP难问题),二是L1范数是L0范数的最优凸近似,而且它比L0范数要容易优化求解。所以大家才把目光和万千宠爱转于L1范数

###线性模型时-Lasso###

L1正则化将系数w的l1范数作为惩罚项加到损失函数上,由于正则项非零,这就迫使那些弱的特征所对应的系数变成0。因此L1正则化往往会使学到的模型很稀疏(系数w经常为0),这个特性使得L1正则化成为一种很好的特征选择方法。

Scikit-learn为线性回归提供了Lasso,为分类提供了L1逻辑回归。

from sklearn.linear_model import Lasso
from sklearn.preprocessing import StandardScaler
from sklearn.datasets import load_boston
import numpy as np

boston = load_boston()
scaler = StandardScaler()
X = scaler.fit_transform(boston["data"])
Y = boston["target"]
names = boston["feature_names"]

lr = Lasso(alpha=.3)
lr.fit(X, Y)


#A helper method for pretty-printing linear models
def pretty_print_linear(coefs, names = None, sort = False):
  if names == None:
    names = ["X%s" % x for x in range(len(coefs))]
  lst = zip(coefs, names)
  if sort:
    lst = sorted(lst,  key = lambda x:-np.abs(x[0]))
  return " + ".join("%s * %s" % (round(coef, 3), name)
                   for coef, name in lst)

print "Lasso model: ", pretty_print_linear(lr.coef_, names, sort = True)

运行结果

Lasso model:  -3.707 * LSTAT + 2.992 * RM + -1.757 * PTRATIO + -1.081 * DIS + -0.7 * NOX + 0.631 * B + 0.54 * CHAS + -0.236 * CRIM + 0.081 * ZN + -0.0 * INDUS + -0.0 * AGE + 0.0 * RAD + -0.0 * TAX

可以看出,很多特征的系数都是0.如果继续增加alpha的值,得到的模型就会越来越稀疏,即越来越多的特征系数会变成0。

比如说,alpha=.7之后,得到的结果如下

Lasso model:  -3.589 * LSTAT + 2.879 * RM + -1.497 * PTRATIO + 0.403 * B + 0.252 * CHAS + -0.0 * CRIM + 0.0 * ZN + -0.0 * INDUS + -0.0 * NOX + -0.0 * AGE + -0.0 * DIS + -0.0 * RAD + -0.0 * TAX

然而,L1正则化像非正则化线性模型一样也是不稳定的,如果特征集合中具有相关联的特征,当数据发生细微变化时也有可能导致很大的模型差异。


##L2范数##

除了L1范数,还有一种更受宠幸的规则化范数是L2范数: ||W||2。它也不逊于L1范数,它有两个美称,在回归里面,有人把有它的回归叫“岭回归”(Ridge Regression),有人也叫它“权值衰减weight decay”。这用的很多吧,因为它的强大功效是改善机器学习里面一个非常重要的问题:过拟合。至于过拟合是什么,上面也解释了,就是模型训练时候的误差很小,但在测试的时候误差很大,也就是我们的模型复杂到可以拟合到我们的所有训练样本了,但在实际预测新的样本的时候,糟糕的一塌糊涂。通俗的讲就是应试能力很强,实际应用能力很差。擅长背诵知识,却不懂得灵活利用知识

###过拟合###

Linear regression的一个例子(房价问题)

ml/20150227164609242.png

欠拟合(underfitting High-bias)

过拟合(overfitting High-variance)

如果模型复杂(可以拟合任意的复杂函数),它可以让我们的模型拟合所有的数据点,也就是基本上没有误差。对于回归来说,就是我们的函数曲线通过了所有的数据点

过度拟合的问题通常发生在变量(特征)过多的时候,这种情况下训练出的方程总是能很好的拟合训练数据,也就是说,我们的代价函数可能非常接近于0或者就为0。

但是,这样的曲线千方百计的去拟合训练数据,这样会导致它无法泛化到新的数据样本中,以至于无法预测新样本价格。在这里,术语"泛化"指的是一个假设模型能够应用到新样本的能力。新样本数据是指没有出现在训练集中的数据。

类似的情况也适用于逻辑回归

ml/logisticRegressionOverfit.png)

过多的变量(特征),同时只有非常少的训练数据,会导致出现过度拟合的问题

过拟合的处理

减少选取变量的数量

正则化

####损失函数####

依然用到上图

ml/20150227164609242.png

优化目标,尽量减少代价函数的均方误差。加上惩罚项,从而使参数θ3和θ4足够的小,比如说1000乘以θ3的平方,再加上1000乘以θ4的平方,最小化该函数,只能让θ3和θ4尽可能的小,θ3和θ4接近于0

实际上,这些参数的值越小,通常对应于越光滑的函数,也就是更加简单的函数。因此 就不易发生过拟合的问题

修改代价函数,在后面添加一项,当我们添加一个额外的正则化项的时候,我们收缩了每个参数

正则化参数λ

控制两个不同的目标中的平衡关系,平衡拟合训练目标和保持参数值较小的目标。从而保持假设的形式相对简单,来避免过度的拟合

  1. 训练使假设更好的拟合训练数据
  2. 保持参数值较小,通过正则化项

为什么L2范数可以防止过拟合

L2范数是指向量各元素的平方和然后求平方根。我们让L2范数的规则项||W||2最小,可以使得W的每个元素都很小,都接近于0,但与L1范数不同,它不会让它等于0,而是接近于0。而越小的参数说明模型越简单,越简单的模型则越不容易产生过拟合现象

为什么越小的参数说明模型越简单?

个人理解可能是:限制了参数很小,实际上就限制了多项式某些分量的影响很小(看上面线性回归的模型的那个拟合的图),这样就相当于减少参数个数。

为什么过拟合的时候系数会很大?

如下图所示,过拟合,就是拟合函数需要顾忌每一个点,最终形成的拟合函数波动很大。在某些很小的区间里,函数值的变化很剧烈。这就意味着函数在某些小区间里的导数值(绝对值)非常大,由于自变量值可大可小,所以只有系数足够大,才能保证导数值很大。

L2范数的好处

  • 学习理论的角度,防止过拟合,提高模型的泛化能力
  • 优化计算的角度,L2范数有助于处理条件数condition number不好的情况下矩阵求逆很困难的问题 数值分析:矩阵求逆

###线性模型时-Ridge regression###

L2正则化将系数向量的L2范数添加到了损失函数中。由于L2惩罚项中系数是二次方的,这使得L2和L1有着诸多差异,最明显的一点就是,L2正则化会让系数的取值变得平均。对于关联特征,这意味着他们能够获得更相近的对应系数。还是以Y=X1+X2为例,假设X1和X2具有很强的关联,如果用L1正则化,不论学到的模型是Y=X1+X2还是Y=2X1,惩罚都是一样的,都是2alpha。但是对于L2来说,第一个模型的惩罚项是2alpha,但第二个模型的是4*alpha。可以看出,系数之和为常数时,各系数相等时惩罚是最小的,所以才有了L2会让各个系数趋于相同的特点。

可以看出,L2正则化对于特征选择来说一种稳定的模型,不像L1正则化那样,系数会因为细微的数据变化而波动。所以L2正则化和L1正则化提供的价值是不同的,L2正则化对于特征理解来说更加有用:表示能力强的特征对应的系数是非零。

from sklearn.linear_model import Ridge
from sklearn.metrics import r2_score
from sklearn.linear_model import LinearRegression
import numpy as np
size = 100


#A helper method for pretty-printing linear models
def pretty_print_linear(coefs, names = None, sort = False):
  if names == None:
    names = ["X%s" % x for x in range(len(coefs))]
  lst = zip(coefs, names)
  if sort:
    lst = sorted(lst,  key = lambda x:-np.abs(x[0]))
  return " + ".join("%s * %s" % (round(coef, 3), name)
                   for coef, name in lst)


#We run the method 10 times with different random seeds
for i in range(10):
    print "Random seed %s" % i
    np.random.seed(seed=i)
    X_seed = np.random.normal(0, 1, size)
    X1 = X_seed + np.random.normal(0, .1, size)
    X2 = X_seed + np.random.normal(0, .1, size)
    X3 = X_seed + np.random.normal(0, .1, size)
    Y = X1 + X2 + X3 + np.random.normal(0, 1, size)
    X = np.array([X1, X2, X3]).T


    lr = LinearRegression()
    lr.fit(X,Y)
    print "Linear model:", pretty_print_linear(lr.coef_)

    ridge = Ridge(alpha=10)
    ridge.fit(X,Y)
    print "Ridge model:", pretty_print_linear(ridge.coef_)
    print

运行结果

Random seed 0
Linear model: 0.728 * X0 + 2.309 * X1 + -0.082 * X2
Ridge model: 0.938 * X0 + 1.059 * X1 + 0.877 * X2

Random seed 1
Linear model: 1.152 * X0 + 2.366 * X1 + -0.599 * X2
Ridge model: 0.984 * X0 + 1.068 * X1 + 0.759 * X2

Random seed 2
Linear model: 0.697 * X0 + 0.322 * X1 + 2.086 * X2
Ridge model: 0.972 * X0 + 0.943 * X1 + 1.085 * X2

Random seed 3
Linear model: 0.287 * X0 + 1.254 * X1 + 1.491 * X2
Ridge model: 0.919 * X0 + 1.005 * X1 + 1.033 * X2

Random seed 4
Linear model: 0.187 * X0 + 0.772 * X1 + 2.189 * X2
Ridge model: 0.964 * X0 + 0.982 * X1 + 1.098 * X2

Random seed 5
Linear model: -1.291 * X0 + 1.591 * X1 + 2.747 * X2
Ridge model: 0.758 * X0 + 1.011 * X1 + 1.139 * X2

Random seed 6
Linear model: 1.199 * X0 + -0.031 * X1 + 1.915 * X2
Ridge model: 1.016 * X0 + 0.89 * X1 + 1.091 * X2

Random seed 7
Linear model: 1.474 * X0 + 1.762 * X1 + -0.151 * X2
Ridge model: 1.018 * X0 + 1.039 * X1 + 0.901 * X2

Random seed 8
Linear model: 0.084 * X0 + 1.88 * X1 + 1.107 * X2
Ridge model: 0.907 * X0 + 1.071 * X1 + 1.008 * X2

Random seed 9
Linear model: 0.714 * X0 + 0.776 * X1 + 1.364 * X2
Ridge model: 0.896 * X0 + 0.903 * X1 + 0.98 * X2

不同的数据上线性回归得到的模型(系数)相差甚远,但对于L2正则化模型来说,结果中的系数非常的稳定,差别较小,都比较接近1,能够反映出数据的内在结构

##稀疏的好处##

###特征选择Feature Selection###

稀疏规则化趋之若鹜的一个关键原因在于它能实现特征的自动选择

特征X的绝大部分都是和最终的输出y没有关系或者不提供任何信息。最小化目标函数的时候考虑这些额外的特征,虽然可以获得更小的训练误差,但是在预测新的样本时,这些额外的特征会干扰到y的预测。它会自动的过滤掉这些额外的特征,本质上是将这些特征的权值重置为0

###可解释性 Interpretability###

模型更容易解读

譬如某种病的概率p,收集到的数据x维度是1000.稀疏化之后,参数非零的便于这种病有密切的联系;如果没有稀疏,1000维度的哪一项对这个疾病的关系度最高呢?


##L2和L1的差别##

##正则化的趣味解读##

作者:刑无刀 链接:https://www.zhihu.com/question/20700829/answer/21156998 来源:知乎 著作权归作者所有,转载请联系作者获得授权。

数学原理我不细说,google能得到一大坨解释,以及其他各位牛人也都回答了,奥坎姆剃刀这类概念我也不说,相信题主早就知道。我想你就差一个俗气的解释,那么我来几个俗气的解释。

解释之前,先说明这样做的目的:如果一个模型我们只打算对现有数据用一次就不再用了,那么正则化没必要了,因为我们没打算在将来他还有用,正则化的目的是为了让模型的生命更长久,把它扔到现实的数据海洋中活得好,活得久。

俗气的解释1: 让模型参数不要在优化的方向上纵欲过度。《红楼梦》里,贾瑞喜欢王熙凤得了相思病,病榻中得到一枚风月宝鉴,可以进入和心目中的女神XXOO,它脑子里的模型目标函数就是“最大化的爽”,所以他就反复去拟合这个目标,多次XXOO,于是人挂掉了,如果给他加一个正则化,让它爽,又要控制爽的频率,那么他可以爽得更久。

俗气的解释2: 假如马化腾心中的商业模型优化目标是让腾讯发展得更好,他的模型只有一个特征,就是张小龙,根据他的目标以及已有样本,它应该给张小龙赋予更大的权重,就可以一直让模型的表现朝这个目标前进,但是,突然有一天马化腾意识到:这样下去不行啊,他的权重大得没边的话,根本不可持续啊,他要是走了,他要是取代我了。于是马化腾就需要在优化这个目标的时候给这个唯一的特征加一个正则化参数,让权重不要过大,从而使得整个模型能够既朝着设定目标走,又不至于无法持续。

俗气的解释3: 我们这群技术男在公司里,如果模型目标是提高自身能力并最终能够在公司有一席之地,理想的优化方法是提高各种牛逼算法,各种高大上的计算平台的熟悉程度,尽量少开无谓的会议,少接领导扯淡的需求,但是如果只是这些的话,很可能在这个公司呆不太久,因为太关注自己的特征权重了,那么如果这个公司其实非常适合提升自己的能力,那么要能在这里呆久点,就得适当限制自己这些特征的权重绝对值,不要那么绝对坚持用到牛逼算法,偶尔也处理处理领导的扯淡需求,平衡一下,你的模型才能泛化得更广。

最后,我还是正本清源一下,正经再简单解释一下正则化,以下内容来自PRML前三章,具体页数记不清了。

上图中的模型是线性回归,有两个特征,要优化的参数分别是w1和w2,左图的正则化是l2,右图是l1。蓝色线就是优化过程中遇到的等高线,一圈代表一个目标函数值,圆心就是样本观测值(假设一个样本),半径就是误差值,受限条件就是红色边界(就是正则化那部分),二者相交处,才是最优参数。可见右边的最优参数只可能在坐标轴上,所以就会出现0权重参数,使得模型稀疏。这个图告诉我们,如果你太绝对相信那个目标了,沉迷其中,那些还没遇到的样本一来,你拔不出来就挂掉了。

最后, regularize这个词更多的意思是“使系统化”,“使体系化”,也就是说不要走极端,要建立和谐社会,科学发展观。

================================== 再补充一个角度: 正则化其实就是对模型的参数设定一个先验,这是贝叶斯学派的观点,不过我觉得也可以一种理解。 L1正则是laplace先验,l2是高斯先验,分别由参数sigma确定。 求不要追究sigma是不是也有先验,那一路追究下去可以天荒地老。

##source##

##知乎上的评论##

邓子明