2.1.1收集数据集并选择合适的特征
from sklearn import datasets
boston = datasets.load_boston() # 返回一个类似于字典的类
X = boston.data
y = boston.target
features = boston.feature_names
boston_data = pd.DataFrame(X,columns=features)
boston_data["Price"] = y
boston_data.head()
各个特征的相关解释:
- CRIM:各城镇的人均犯罪率
- ZN:规划地段超过25,000平方英尺的住宅用地比例
- INDUS:城镇非零售商业用地比例
- CHAS:是否在查尔斯河边(=1是)
- NOX:一氧化氮浓度(/千万分之一)
- RM:每个住宅的平均房间数
- AGE:1940年以前建造的自住房屋的比例
- DIS:到波士顿五个就业中心的加权距离
- RAD:放射状公路的可达性指数
- TAX:全部价值的房产税率(每1万美元)
- PTRATIO:按城镇分配的学生与教师比例
- B:1000(Bk - 0.63)^2其中Bk是每个城镇的黑人比例
- LSTAT:较低地位人口
- Price:房价
2.1.2 选择度量模型性能的指标:
均方误差 :
MAE平均绝对误差 :决定系数 :
解释方差得分 :
更多度量方法可以点击【传送门】
2.1.3选择具体的模型并进行训练
2.1.3.1线性回归模型
回归这个概念是19世纪80年代由英国统计学家郎西斯.高尔顿在研究父子身高关系提出来的,他发现:在同一族群中,子代的平均身高介于父代的身高以及族群的平均身高之间。具体而言,高个子父亲的儿子的身高有低于其父亲身高的趋势,而矮个子父亲的儿子身高则有高于父亲的身高的趋势。也就是说,子代的身高有向族群平均身高”平均”的趋势,这就是统计学上”回归”的最初含义。
回归分析是一种预测性的建模技术,它研究的是因变量(目标)和自变量(特征)之间的关系。
这种技术通常用于预测分析,时间序列模型以及发现变量之间的因果关系。通常使用曲线/线来拟合数据点,目标是使曲线到数据点的距离差异最小。而线性回归就是回归问题中的一种,线性回归假设目标值与特征之间线性相关,即满足一个多元一次方程。通过构建损失函数,来求解损失函数最小时的参数w :
假设:数据集
(a)最小二乘估计:
我们需要衡量真实值𝑦𝑖yi与线性回归模型的预测值之间的差距,在这里我们和使用二范数的平方和来描述这种差距,即其实就是求最小值
(b)几何解释:
在线性代数中,我们知道两个向量a和b相互垂直可以得出:,而平面X的法向量为与平面X互相垂直,因此: 即
(c)概率视角:
假设噪声:
因此:
我们使用极大似然估计MLE对参数w进行估计:
sklearn的线性回归实例:
from sklearn import linear_model # 引入线性回归方法
lin_reg = linear_model.LinearRegression() # 创建线性回归的类
lin_reg.fit(X,y) # 输入特征X和因变量y进行训练
print("模型系数:",lin_reg.coef_) # 输出模型的系数
print("模型得分:",lin_reg.score(X,y)) # 输出模型的决定系数R^2
2.1.3.2线性回归的推广
前面的线性回归讨论的是因变量和自变量之间是一条直线的关系,这样做的模型过于简单理想化,很多时候数据呈现非线性关系的时候,拟合效果就很差了。这个时候,推广线性回归就很有必要了
(a)多项式回归
对于多项式的阶数d不能取过大,一般不大于3或者4,因为d越大,多项式曲线就会越光滑,在X的边界处有异常的波动。(图中的边界处的4阶多项式拟合曲线的置信区间(虚线表示置信区间)明显增大,预测效果的稳定性下降。)
模型介绍:【传送门】
from sklearn.preprocessing import PolynomialFeatures
X_arr = np.arange(6).reshape(3, 2)
print("原始X为:\n",X_arr)
poly = PolynomialFeatures(2)
print("2次转化X:\n",poly.fit_transform(X_arr))
poly = PolynomialFeatures(interaction_only=True)
print("2次转化X:\n",poly.fit_transform(X_arr))
(b)广义可加模型(GAM)
线性模型推广至非线性模型的一个框架,把训练集中每一个变量都用一个非线性函数代替,但是模型本身保持可加性。
模型介绍:【传送门】安装pygam:pip install pygam 或者 conda install pygam
from pygam import LinearGAM
gam = LinearGAM().fit(boston_data.drop('Price',axis=1), y)
gam.summary()
(c)回归树
- 基于树的回归方法主要是依据分层和分割的方式将特征空间划分为一系列简单的区域。
- 对某个给定的待预测的自变量,用他所属区域中训练集的平均数或者众数对其进行预测。
- 由于划分特征空间的分裂规则可以用树的形式进行概括,因此这类方法称为决策树方法。
- 决策树由结点(node)和有向边(diredcted edge)组成。
- 结点有两种类型:内部结点(internal node)和叶结点(leaf node)。
- 内部结点表示一个特征或属性,叶结点表示一个类别或者某个值。
- 区域等称为叶节点,将特征空间分开的点为内部节点。
建立回归树的过程大致可以分为以下两步:
- 将自变量的特征空间(即的可能取值构成的集合分割成个互不重叠的区域。
- 对落入区域的每个观测值作相同的预测,预测值等于上训练集的因变量的简单算术平均。
具体来说:
选择最优切分特征,以及该特征上的最优点:
遍历特征以及固定后遍历切分点,选择使得下式最小的
按照分裂特征空间:
- 继续调用步骤1,2直到满足停止条件,就是每个区域的样本数小于等于5
- 将特征空间划分为个不同的区域,生成回归树:
【从根节点开始,对样本的某一特征进行测试,根据测试结果,将样本分配到其子结点;这时,每一个子节点对应着该特征的一个取值。如此递归地对样本进行测试并分配,直至到达叶结点。】
如以下生成的关于运动员在棒球大联盟数据的回归树:
回归树与线性模型的比较:
线性模型的模型形式与树模型的模型形式有着本质的区别,具体而言,线性回归对模型形式做了如下假定:,而回归树则是
两种算法并没有优缺点的区分,如果数据能够用线性模型很好的表达,那就用线性模型,如果没办法用线性表达,那树形模型可能会有不错的效果。
图1和图2的区分,线性模型就能够很好的表达,这个时候树形模型表达较差 图3和图四的区分,黄颜色明显不是能用一根线能区分的,这个时候树形模型就能够很好的表示出来了。
树模型的优缺点:
- 树模型的解释性强,在解释性方面可能比线性回归还要方便。
- 树模型更接近人的决策方式。
- 树模型可以用图来表示,非专业人士也可以轻松解读。
- 树模型可以直接做定性的特征而不需要像线性回归一样哑元化。
- 树模型能很好处理缺失值和异常值,对异常值不敏感,但是这个对线性模型来说却是致命的。
- 树模型的预测准确性一般无法达到其他回归模型的水平,但是改进的方法很多。
sklearn使用回归树的实例:
AIP传送门
sklearn.tree.DecisionTreeRegressor(*, criterion=’mse’, splitter=’best’, max_depth=None, min_samples_split=2, min_samples_leaf=1, min_weight_fraction_leaf=0.0, max_features=None, random_state=None, max_leaf_nodes=None, min_impurity_decrease=0.0, min_impurity_split=None, presort=’deprecated’, ccp_alpha=0.0)
参数:(列举几个重要的,常用的,详情请看上面的AIP)
criterion:{“ mse”,“ friedman_mse”,“ mae”},默认=“ mse”。衡量分割标准的函数 。
splitter:{“best”, “random”}, default=”best”。分割方式。
max_depth:树的最大深度。
min_samples_split:拆分内部节点所需的最少样本数,默认是2。
min_samples_leaf:在叶节点处需要的最小样本数。默认是1。
min_weight_fraction_leaf:在所有叶节点处(所有输入样本)的权重总和中的最小加权分数。如果未提供sample_weight,则样本的权重相等。默认是0。from sklearn.tree import DecisionTreeRegressor
reg_tree = DecisionTreeRegressor(criterion = "mse",min_samples_leaf = 5)
reg_tree.fit(X,y)
reg_tree.score(X,y)
# 0.9376307599929274
(d)支持向量机回归(SVR)
在介绍支持向量回归SVR之前,我们先来了解下约束优化的相关知识:
约束优化问题(P):我们假设为满足以上条件的局部最优解,,我们的目的就是要找到与,满足不等式和等式约束的集合成为可行域,记作。
- KKT条件(最优解的一阶必要条件)
因为KKT条件是最优化的相关内容,在本次开源学习中并不是重点,因此在这里我用一个更加简单的例子说明KKT条件,严格的证明请参见凸优化相关书籍。
在这个例子中,我们考虑:(为我们的最优解)
- 对偶理论
- 为什么要引入对偶问题呢?是因为原问题与对偶问题就像是一个问题两个角度去看,如利润最大与成本最低等。有时侯原问题上难以解决,但是在对偶问题上就会变得很简单。再者,任何一个原问题在变成对偶问题后都会变成一个凸优化的问题。
- 支持向量回归SVR
在线性回归的理论中,每个样本点都要计算平方损失,但是SVR却是不一样的。SVR认为:落在的
邻域空间中的样本点不需要计算损失,这些都是预测正确的,其余的落在邻域空间以外的样本才需要计算损失,因此:
引入拉格朗日函数:
sklearn中使用SVR实例:
传送门【官网AIP】
sklearn.svm.SVR(*, kernel=’rbf’, degree=3, gamma=’scale’, coef0=0.0, tol=0.001, C=1.0, epsilon=0.1, shrinking=True, cache_size=200, verbose=False, max_iter=-1)
- 参数:
kernel:核函数,{‘linear’, ‘poly’, ‘rbf’, ‘sigmoid’, ‘precomputed’}, 默认=’rbf’。(后面会详细介绍)
degree:多项式核函数的阶数。默认 = 3。
C:正则化参数,默认=1.0。(后面会详细介绍)
epsilon:SVR模型允许的不计算误差的邻域大小。默认0.1。
from sklearn.svm import SVR
from sklearn.preprocessing import StandardScaler # 标准化数据
from sklearn.pipeline import make_pipeline # 使用管道,把预处理和模型形成一个流程
reg_svr = make_pipeline(StandardScaler(), SVR(C=1.0, epsilon=0.2))
reg_svr.fit(X, y)
reg_svr.score(X,y)
# 0.7024525421955277
2.1.4 优化基础模型
我们通常把数据分为训练集和测试集。在训练集中,我们通常要达到的目的是:使得损失函数为最小值。在实际问题中,我们可以使得损失函数在训练集最小化为0。
如:在线性回归中,我加入非常多的高次项,使得我们模型在训练集的每一个数据点都恰好位于曲线上,那这时候模型在训练集的损失值也就是误差为0。
但是这样做带来的后果就是,模型的鲁棒性特别的低。我们做模型的目的是为了更好的预测,而不是过度的对已有经验的总结。就和《冰淇淋与犯罪率》的故事一样。
2.1.4.1 训练均方误差与测试均方误差:
在回归中,我们最常用的评价指标为均方误差。
其中是样本应用建立的模型预测的结果。训练集上的误差称为 训练均方误差,测试集上的误差称为 测试均方误差 。我们在模型拟合的时候,重点关注测试均方误差,我们的目的是用训练集的数据去优化测试均方误差,使其最小。
一些观点认为通过训练误差最小化来选择模型也是可行的,但是存在一个致命的缺点。如图:
一个模型的训练均方误差最小时,不能保证测试均方误差同时也很小。当我们的模型的训练均方误差达到很小时,测试均方误差反而很大。
模型在训练误差很小,但是测试均方误差很大时,我们称这种情况叫模型的过拟合
2.1.4.2 偏差-方差的权衡
从上图的测试均方误差曲线可以看到:测试均方误差曲线呈现U型曲线,这表明了在测试误差曲线中有两种力量在互相博弈。可以证明:
我们的测试均方误差的期望值可以分解为的方差、的偏差平方 和 误差项。
为了使得模型的测试均方误差达到最小值,也就是同时最小化偏差的平方和方差。由于我们知道偏差平方和方差本身是非负的,因此测试均方误差的期望不可能会低于误差的方差,因此我们称为建模任务的难度,这个量在我们的任务确定后是无法改变的,也叫做不可约误差。
那么模型的方差和偏差的平方和究竟是什么呢?
所谓模型的方差就是:用不同的数据集去估计时,估计函数的改变量。
举个例子:我们想要建立一个线性回归模型,可以通过输入中国人身高去预测我们的体重。但是显然我们没有办法把全中国13亿人做一次人口普查,拿到13亿人的身高体重去建立模型。我们能做的就是从13亿中抽1000个样本进行建模,我们对这个抽样的过程重复100遍,就会得到100个1000人的样本集。我们使用线性回归模型估计参数就能得到100个线性回归模型。由于样本抽取具有随机性,我们得到的100个模型不可能参数完全一样,那么这100个模型之间的差异就叫做方差
显然,我们希望得到一个稳定的模型,也就是在不同的样本集估计的模型都不会相差太大,即要求的方差越小越好。一般来说,模型的复杂度越高,f的方差就会越大。 如加入二次项的模型的方差比线性回归模型的方差要大。
另一方面,模型的偏差是指:为了选择一个简单的模型去估计真实函数所带入的误差。
假如真实的数据X与Y的关系是二次关系(),但是我们选择了线性模型进行建模,那由于模型的复杂度引起的这种误差我们称为偏差,它的构成是复杂的。
偏差度量了学习算法的期望预测与真实结果的偏离程度。
偏差度量的是单个模型的学习能力。
方差度量的是同一个模型在不同数据集上的稳定性。
“偏差-方差分解”说明:泛化性能是由学习算法的能力、数据的充分性以及学习任务本身的难度所共同决定的。给定学习任务,为了取得好的泛化性能,则需使偏差较小,即能够充分拟合数据,并且使方差较小,即使得数据扰动产生的影响小。
一般而言,增加模型的复杂度,会增加模型的方差,但是会减少模型的偏差,我们要找到一个方差—偏差的权衡,使得测试均方误差最小。
2.1.4.3 特征提取
在前面的讨论中,我们已经明确一个目标,就是:我们要选择一个测试误差达到最小的模型。但是实际上我们很难对实际的测试误差做精确的计算,因此我们要对测试误差进行估计,估计的方式有两种:训练误差修正与交叉验证。
(a)训练误差修正:
前面的讨论我们已经知道,测试误差先减后增。<br /> 因此,我们先构造一个特征较多的模型使其过拟合,此时训练误差很小而测试误差很大,那这时我们加入关于特征个数的惩罚。<br /> 因此,当我们的训练误差随着特征个数的增加而减少时,惩罚项因为特征数量的增加而增大,抑制了训练误差随着特征个数的增加而无休止地减小。<br /> 具体的数学量如下:<br /> ![](https://cdn.nlark.com/yuque/__latex/82799c438fc21f868f55854579f4f645.svg#card=math&code=C_p%20%3D%20%5Cfrac%7B1%7D%7BN%7D%28RSS%20%20%2B%20%202d%5Chat%7B%5Csigma%7D%5E2%29&height=37&width=165)其中d为模型特征个数,![](https://cdn.nlark.com/yuque/__latex/83f8a17cced106cc0194fd381751ee9d.svg#card=math&code=RSS%20%3D%20%5Csum%5Climits_%7Bi%3D1%7D%5E%7BN%7D%28y_i-%5Chat%7Bf%7D%28x_i%29%29%5E2&height=53&width=177) ,![](https://cdn.nlark.com/yuque/__latex/b78e925bca3e2e013171cd1298b68db6.svg#card=math&code=%5Chat%7B%5Csigma%7D%5E2&height=19&width=16)为模型预测误差的方差的估计值,即残差的方差。 <br />![image.png](https://cdn.nlark.com/yuque/0/2021/png/2610909/1616405733605-e87d10d1-c1ed-4abf-a436-19766463210f.png#align=left&display=inline&height=52&margin=%5Bobject%20Object%5D&name=image.png&originHeight=52&originWidth=360&size=7639&status=done&style=none&width=360)
(b)交叉验证:
前面讨论的对训练误差修正得到测试误差的估计是间接方法,这种方法的桥梁是训练误差,而交叉验证则是对测试误差的直接估计。交叉验证比训练误差修正的优势在于:能够给出测试误差的一个直接估计。在这里只介绍K折交叉验证:我们把训练样本分成K等分,然后用K-1个样本集当做训练集,剩下的一份样本集为验证集去估计由K-1个样本集得到的模型的精度,这个过程重复K次取平均值得到测试误差的一个估计𝐶𝑉(𝐾)=1𝐾∑𝑖=1𝐾𝑀𝑆𝐸𝑖CV(K)=1K∑i=1KMSEi。5折交叉验证如下图:(蓝色的是训练集,黄色的是验证集)<br />![image.png](https://cdn.nlark.com/yuque/0/2021/png/2610909/1616409876643-ac88a0b1-ac78-4d58-be53-e77b02899e8d.png#align=left&display=inline&height=341&margin=%5Bobject%20Object%5D&name=image.png&originHeight=341&originWidth=702&size=20548&status=done&style=none&width=702)<br />在测试误差能够被合理的估计出来以后,我们做特征选择的目标就是:从p个特征中选择m个特征,使得对应的模型的测试误差的估计最小。对应的方法有:最优子集选择 和 向前逐步选择。通过计算RSS进行迭代,每次选择RSS值最小的模型,最后选择测试误差最小的模型作为最优模型。
2.1.4.4 压缩估计(正则化)
对回归的系数进行约束或者加罚的技巧对p个特征的模型进行拟合,显著降低模型方差。具体来说,就是将回归系数往零的方向压缩,这也就是为什么叫压缩估计的原因了。
(a)岭回归(L2正则化的例子):
在线性回归中,我们的损失函数为 我们在线性回归的损失函数的基础上添加对系数的约束或者惩罚,即:
调节参数的大小是影响压缩估计的关键, 越大惩罚的力度越大,系数则越趋近于0,反之,选择合适的对模型精度来说十分重要。岭回归通过牺牲线性回归的无偏性降低方差,有可能使得模型整体的测试误差较小,提高模型的泛化能力。
(b)Lasso回归(L1正则化的例子):
岭回归的一个很显著的特点是:将模型的系数往零的方向压缩,但是岭回归的系数只能呢个趋于0但无法等于0,换句话说,就是无法做特征选择。能否使用压缩估计的思想做到像特征最优子集选择那样提取出重要的特征呢?答案是肯定的!我们只需要对岭回归的优化函数做小小的调整就行了,我们使用系数向量的L1范数替换岭回归中的L2范数:
为什么Losso能做到特征选择而岭回归却不能呢个做到呢?(如图:左边为lasso,右边为岭回归)
椭圆形曲线为RSS等高线,菱形和圆形区域分别代表了L1和L2约束,Lsaao回归和岭回归都是在约束下的回归,因此最优的参数为椭圆形曲线与菱形和圆形区域相切的点。但是Lasso回归的约束在每个坐标轴上都有拐角,因此当RSS曲线与坐标轴相交时恰好回归系数中的某一个为0,这样就实现了特征提取。反观岭回归的约束是一个圆域,没有尖点,因此与RSS曲线相交的地方一般不会出现在坐标轴上,因此无法让某个特征的系数为0,因此无法做到特征提取。
2.1.4.5 降维
到目前为止,我们所讨论的方法对方差的控制有两种方式:一种是使用原始变量的子集,另一种是将变量系数压缩至零。
但是这些方法都是基于原始特征 得到的。现在我们探讨一类新的方法:将原始的特征空间投影到一个低维的空间实现变量的数量变少 。
如:将二维的平面投影至一维空间。机器学习领域中所谓的降维就是指采用某种映射方法,将原高维空间中的数据点映射到低维度的空间中。
降维的本质是学习一个映射函数,其中x是原始数据点的表达,目前最多使用向量表达形式。y是数据点映射后的低维向量表达,通常y的维度小于x的维度(当然提高维度也是可以的)。
f可能是显式的或隐式的、线性的或非线性的。
目前大部分降维算法处理向量表达的数据,也有一些降维算法处理高阶张量表达的数据。之所以使用降维后的数据表示是因为在原始的高维空间中,包含有冗余信息以及噪音信息,在实际应用例如图像识别中造成了误差,降低了准确率;而通过降维,我们希望减少 冗余信息 所造成的误差,提高识别(或其他应用)的精度。又或者希望通过降维算法来寻找数据内部的本质结构特征。在很多算法中,降维算法成为了数据预处理的一部分,如PCA。事实上,有一些算法如果没有降维预处理,其实是很难得到很好的效果的。 (摘自:rosenor1博客)
主成分分析(PCA)
主成分分析的思想:通过最大投影方差 将原始空间进行重构,即由特征相关重构为无关,即落在某个方向上的点(投影)的方差最大。在进行下一步推导之前,我们先把样本均值和样本协方差矩阵推广至矩阵形式:
可以看到:为的特征值,为的特征向量。因此我们只需要对中心化后的协方差矩阵进行特征值分解,得到的特征向量即为投影方向。如果需要进行降维,那么只需要取p的前M个特征向量即可。
实训代码
#定义向前逐步回归函数
def forward_select(data,target):
variate=set(data.columns) #将字段名转换成字典类型
variate.remove(target) #去掉因变量的字段名
selected=[]
current_score,best_new_score=float('inf'),float('inf') #目前的分数和最好分数初始值都为无穷大(因为AIC越小越好)
#循环筛选变量
while variate:
aic_with_variate=[]
for candidate in variate: #逐个遍历自变量
formula="{}~{}".format(target,"+".join(selected+[candidate])) #将自变量名连接起来
aic=ols(formula=formula,data=data).fit().aic #利用ols训练模型得出aic值
aic_with_variate.append((aic,candidate)) #将第每一次的aic值放进空列表
aic_with_variate.sort(reverse=True) #降序排序aic值
best_new_score,best_candidate=aic_with_variate.pop() #最好的aic值等于删除列表的最后一个值,以及最好的自变量等于列表最后一个自变量
if current_score>best_new_score: #如果目前的aic值大于最好的aic值
variate.remove(best_candidate) #移除加进来的变量名,即第二次循环时,不考虑此自变量了
selected.append(best_candidate) #将此自变量作为加进模型中的自变量
current_score=best_new_score #最新的分数等于最好的分数
print("aic is {},continuing!".format(current_score)) #输出最小的aic值
else:
print("for selection over!")
break
formula="{}~{}".format(target,"+".join(selected)) #最终的模型式子
print("final formula is {}".format(formula))
model=ols(formula=formula,data=data).fit()
return(model)
import statsmodels.api as sm #最小二乘
from statsmodels.formula.api import ols #加载ols模型
forward_select(data=boston_data,target="Price")
lm=ols("Price~LSTAT+RM+PTRATIO+DIS+NOX+CHAS+B+ZN+CRIM+RAD+TAX",data=boston_data).fit()
lm.summary()
Notes: [1] Standard Errors assume that the covariance matrix of the errors is correctly specified. [2] The condition number is large, 1.47e+04. This might indicate that there are strong multicollinearity or other numerical problems.
(a)岭回归实例分享
sklearn.linear_model.ridge_regression(X, y, alpha, *, sample_weight=None, solver=’auto’, max_iter=None, tol=0.001, verbose=0, random_state=None, return_n_iter=False, return_intercept=False, check_input=True)
https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.ridge_regression.html?highlight=rid#sklearn.linear_model.ridge_regression
- 参数:
alpha:较大的值表示更强的正则化。浮点数
sample_weight:样本权重,默认无。
solver:求解方法,{‘auto’, ‘svd’, ‘cholesky’, ‘lsqr’, ‘sparse_cg’, ‘sag’, ‘saga’}, 默认=’auto’。“ svd”使用X的奇异值分解来计算Ridge系数。’cholesky’使用标准的scipy.linalg.solve函数通过dot(XT,X)的Cholesky分解获得封闭形式的解。’sparse_cg’使用scipy.sparse.linalg.cg中的共轭梯度求解器。作为一种迭代算法,对于大规模数据(可能设置tol和max_iter),此求解器比“ Cholesky”更合适。 lsqr”使用专用的正则化最小二乘例程scipy.sparse.linalg.lsqr。它是最快的,并且使用迭代过程。“ sag”使用随机平均梯度下降,“ saga”使用其改进的无偏版本SAGA。两种方法都使用迭代过程,并且当n_samples和n_features都很大时,通常比其他求解器更快。请注意,只有在比例大致相同的要素上才能确保“ sag”和“ saga”快速收敛。您可以使用sklearn.preprocessing中的缩放器对数据进行预处理。最后五个求解器均支持密集和稀疏数据。但是,当fit_intercept为True时,仅’sag’和’sparse_cg’支持稀疏输入。 ```python from sklearn import linear_model reg_rid = linear_model.Ridge(alpha=.5) reg_rid.fit(X,y) reg_rid.score(X,y)
0.739957023371629
<a name="G887C"></a>
### (b)Lasso实例分享
class sklearn.linear_model.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')<br />[https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.Lasso.html?highlight=lasso#sklearn.linear_model.Lasso](https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.Lasso.html?highlight=lasso#sklearn.linear_model.Lasso)
- 参数:<br />alpha:正则化强度,1.0代表标准最小二乘。<br />fit_intercept:是否计算模型截距。默认true。<br />normalize:是否标准化,默认false。<br />positive:是否强制系数为正,默认false。
```python
from sklearn import linear_model
reg_lasso = linear_model.Lasso(alpha = 0.5)
reg_lasso.fit(X,y)
reg_lasso.score(X,y)
# 0.7140164719858566
2.1.5 调参(对模型超参数进行调优)
岭回归对线性回归的优化在于在线性回归的损失函数中加入L2正则化项从而牺牲无偏性降低方差。但是,大家是否想过这样的问题:在L2正则化中参数𝜆λ应该选择多少?是0.01、0.1、还是1?到目前为止,我们只能凭经验或者瞎猜,能不能找到一种方法找到最优的参数λ?事实上,找到最佳参数的问题本质上属于最优化的内容,因为从一个参数集合中找到最佳的值本身就是最优化的任务之一,我们脑海中浮现出来的算法无非就是:梯度下降法、牛顿法等无约束优化算法或者约束优化算法,但是在具体验证这个想法是否可行之前,我们必须先认识两个最本质概念的区别。
2.1.5.1 参数与超参数
使用最小二乘法或者梯度下降法等最优化算法优化出来的数我们称为参数,类似于一样;
我们无法使用最小二乘法或者梯度下降法等最优化算法优化出来的数我们称为超参数。
模型参数是模型内部的配置变量,其值可以根据数据进行估计。
- 进行预测时需要参数。
- 它参数定义了可使用的模型。
- 参数是从数据估计或获悉的。
- 参数通常不由编程者手动设置。
- 参数通常被保存为学习模型的一部分。
- 参数是机器学习算法的关键,它们通常由过去的训练数据中总结得出 。
模型超参数是模型外部的配置,其值无法从数据中估计。 - 超参数通常用于帮助估计模型参数。
- 超参数通常由人工指定。
- 超参数通常可以使用启发式设置。
超参数经常被调整为给定的预测建模问题。
我们前面(4)部分的优化都是基于模型本身的具体形式的优化,那本次(5)调整的内容是超参数,也就是取不同的超参数的值对于模型的性能有不同的影响。(a)网格搜索GridSearchCV
网格搜索:【sklearn传送门】
网格搜索结合管道:【sklearn传送门】
网格搜索的思想非常简单,比如你有2个超参数需要去选择,那你就把所有的超参数选择列出来分别做排列组合。
举个例子: 和 ,要挑选出最优解,就有以下组合
然后针对每组超参数分别建立一个模型,然后选择测试误差最小的那组超参数。换句话说,我们需要从超参数空间中寻找最优的超参数,很像一个网格中找到一个最优的节点,因此叫网格搜索。(b)随机搜索 RandomizedSearchCV
随机搜索:【sklearn传送门】
随机搜索法结果比稀疏化网格法稍好(有时候也会极差,需要权衡)。参数的随机搜索中的每个参数都是从可能的参数值的分布中采样的。与网格搜索相比,这有两个主要优点:可以独立于参数数量和可能的值来选择计算成本。
- 添加不影响性能的参数不会降低效率。
(c)实战代码
下面我们使用SVR的例子,结合管道来进行调优: ```python %%time我们先来对未调参的SVR进行评价:
import numpy as np from sklearn.svm import SVR # 引入SVR类 from sklearn.pipeline import make_pipeline # 引入管道简化学习流程 from sklearn.preprocessing import StandardScaler # 由于SVR基于距离计算,引入对数据进行标准化的类 from sklearn.model_selection import GridSearchCV # 引入网格搜索调优 from sklearn.model_selection import cross_val_score # 引入K折交叉验证 from sklearn import datasets
boston = datasets.load_boston() # 返回一个类似于字典的类 X = boston.data y = boston.target features = boston.feature_names pipe_SVR = make_pipeline(StandardScaler(),SVR()) score1 = cross_val_score(estimator=pipe_SVR, X = X, y = y, scoring = ‘r2’, cv = 10) # 10折交叉验证 print(“CV accuracy: %.3f +/- %.3f” % ((np.mean(score1)),np.std(score1)))
CV accuracy: 0.187 +/- 0.649
Wall time: 129 ms
下面我们使用网格搜索来对SVR调参:
```python
%%time
from sklearn.pipeline import Pipeline
pipe_svr = Pipeline([("StandardScaler",StandardScaler()),
("svr",SVR())])
param_range = [0.0001,0.001,0.01,0.1,1.0,10.0,100.0,1000.0]
param_grid = [{"svr__C":param_range,"svr__kernel":["linear"]}, # 注意__是指两个下划线,一个下划线会报错的
{"svr__C":param_range,"svr__gamma":param_range,"svr__kernel":["rbf"]}]
gs = GridSearchCV(estimator=pipe_svr,
param_grid = param_grid,
scoring = 'r2',
cv = 10) # 10折交叉验证
gs = gs.fit(X,y)
print("网格搜索最优得分:",gs.best_score_)
print("网格搜索最优参数组合:\n",gs.best_params_)
# 网格搜索最优得分: 0.6081303070817127
# 网格搜索最优参数组合:
# {'svr__C': 1000.0, 'svr__gamma': 0.001, 'svr__kernel': 'rbf'}
# Wall time: 45.1 s
下面我们使用随机搜索来对SVR调参:
%%time
from sklearn.model_selection import RandomizedSearchCV
from scipy.stats import uniform # 引入均匀分布设置参数
pipe_svr = Pipeline([("StandardScaler",StandardScaler()),
("svr",SVR())])
distributions = dict(svr__C=uniform(loc=1.0, scale=4), # 构建连续参数的分布
svr__kernel=["linear","rbf"], # 离散参数的集合
svr__gamma=uniform(loc=0, scale=4))
rs = RandomizedSearchCV(estimator=pipe_svr,
param_distributions = distributions,
scoring = 'r2',
cv = 10) # 10折交叉验证
rs = rs.fit(X,y)
print("随机搜索最优得分:",rs.best_score_)
print("随机搜索最优参数组合:\n",rs.best_params_)
# 随机搜索最优得分: 0.30290066558976186
# 随机搜索最优参数组合:
# {'svr__C': 1.2960877824563282, 'svr__gamma': 2.589621129687447, 'svr__kernel': 'linear'}
#
经过我们不懈的努力,从收集数据集并选择合适的特征、选择度量模型性能的指标、选择具体的模型并进行训练以优化模型到评估模型的性能并调参,我们认识到了如何使用sklearn构建简单回归模型。在本章的最后,我们会给出一个具体的案例,整合回归的内容。下面我们来看看机器学习另外一类大问题:分类。与回归一样,分类问题在机器学习的地位非常重要,甚至有的地方用的比回归问题还要多,因此分类问题是十分重要的!