美文网首页收入即学习
2020-05-17 第八章 岭回归与Lasso回归模型(pyt

2020-05-17 第八章 岭回归与Lasso回归模型(pyt

作者: 程凉皮儿 | 来源:发表于2020-05-17 17:50 被阅读0次

    岭回归与Lasso回归模型

    01 线性回归模型的短板

    背景知识

    根据线性回归模型的参数估计公式β=(X^′X)^−1X^′y可知,得到β的前提是矩阵X^′X可逆,但在实际应用中,可能会出现自变量个数多于样本量或者自变量间存在多重共线性的情况,即X^′X的行列式为0。此时将无法根据公式计算回归系数的估计值β。

    02 岭回归与Lasso回归的系数求解

    岭回归模型

    为解决多元线性回归模型中可能存在的不可逆问题,统计学家提出了岭回归模型。该模型解决问题的思路就是在线性回归模型的目标函数之上添加l2正则项(也称为惩罚项)。

    • 在线性回归模型的目标函数之上添加𝑙2正则项,其中𝜆为非负数
    • 𝜆=0时,目标函数退化为线性回归模型的目标函数
    • 𝜆→+∞时,通过缩减回归系数使𝛽趋近于0
    • λl2正则项平方的系数,用于平衡模型方差(回归系数的方差)和偏差

    参数β的求解

    具体方程推导就不列出了

    模型方差与偏差的理解

    image.png

    随着λ的增大,模型方差会减小(因为矩阵(X^′X+λI)的行列式随λ的增加在增加,使得矩阵的逆就会逐渐减小,进而岭回归系数被“压缩”而变小)而偏差会增大。

    03 系数求解的几何意义

    几何意义

    image.png

    以二维空间为例(即自变量仅包含x1x2两个),左半边的半椭圆体代表了∑_{i=1}^n(y_{i}−β_{0}−∑_{j=1}^2x_{ij}β_j)^2的部分,它是关于两个系数的二次函数;圆柱体代表了β_1^2+β_2^2≤t的部分;
    右半边为二维坐标下的映射图,对于线性回归模型来说,抛物面的中心黑点代表模型的最小二乘解,当附加β_1^2+β_2^2≤t时,抛物面与圆面构成的交点就是岭回归模型的系数解。
    公式推导比较抽象。

    04 Lasso回归的变量选择

    05 岭回归与Lasso回归的应用实战

    岭回归模型的应用

    λ值的确定--可视化法

    由于岭回归模型的系数是关于λ值的函数,因此可以通过绘制不同的λ值和对应回归系数的折线图确定合理的λ值。
    一般而言,当回归系数随着λ值的增加而趋近于稳定的点时就是所要寻找的λ值。
    β=(X^′X+λI)^−1X^′y
    用法

    Ridge(alpha=1.0, fit_intercept=True, normalize=False, copy_X=True, 
              max_iter=None, tol=0.001, solver='auto', random_state=None)
    
    alpha:用于指定lambda值的参数,默认该参数为1
    fit_intercept:bool类型参数,是否需要拟合截距项,默认为True
    normalize:bool类型参数,建模时是否需要对数据集做标准化处理,默认为False
    copy_X:bool类型参数,是否复制自变量X的数值,默认为True
    max_iter:用于指定模型的最大迭代次数
    tol:用于指定模型收敛的阈值
    solver:用于指定模型求解最优化问题的算法,默认为'auto',表示模型根据数据集自动选择算法
    random_state:用于指定随机数生成器的种子
    

    核心代码

    import pandas as pd
    import numpy as np
    from sklearn import model_selection
    from sklearn.linear_model import Ridge,RidgeCV
    import matplotlib.pyplot as plt
    
    # 读取糖尿病数据集
    diabetes = pd.read_excel('./diabetes.xlsx', sep = '')
    # 构造自变量(剔除患者性别、年龄和因变量)
    predictors = diabetes.columns[2:-1]
    # 将数据集拆分为训练集和测试集
    X_train, X_test, y_train, y_test = model_selection.train_test_split(diabetes[predictors], diabetes['Y'], 
                                                                        test_size = 0.2, random_state = 1234 )
                                                                        
    # 构造不同的Lambda值
    Lambdas = np.logspace(-5, 2, 200)
    # 构造空列表,用于存储模型的偏回归系数
    ridge_cofficients = []
    # 循环迭代不同的Lambda值
    for Lambda in Lambdas:
        ridge = Ridge(alpha = Lambda, normalize=True)
        ridge.fit(X_train, y_train)
        ridge_cofficients.append(ridge.coef_)
    
    # 绘制Lambda与回归系数的关系
    # 中文乱码和坐标轴负号的处理
    plt.rcParams['font.sans-serif'] = ['Helvetica']
    plt.rcParams['axes.unicode_minus'] = False
    # 设置绘图风格
    plt.style.use('ggplot')
    plt.plot(Lambdas, ridge_cofficients)
    # 对x轴作对数变换
    plt.xscale('log')
    # 设置折线图x轴和y轴标签
    plt.xlabel('Lambda')
    plt.ylabel('Cofficients')
    # 图形显示
    plt.show()
    
    Figure_1.png

    解读
    图中的每条折线代表了不同的变量,对于比较突出的喇叭形折线,一般代表该变量存在多重共线性;
    从图中可知,当λ值逼近于0时,各变量对应的回归系数应该与线性回归模型的最小二乘解完全一致;随着λ值的不断增加,各回归系数的取值会迅速缩减为0;
    按照λ值的选择标准,发现λ值在0.01附近时,绝大多数变量的回归系数趋于稳定,故认为λ值可以选择在0.01附近;

    λ值的确定--交叉验证法

    交叉验证的思想

    • 首先将数据集拆分成k个样本量大体相当的数据组(如图中的第一行),并且每个数据组与其他组都没有重叠的观测;
    • 然后从k组数据中挑选k−1组数据用于模型的训练,剩下的一组数据用于模型的测试(如图中的第二行);
    • 以此类推,将会得到k种训练集和测试集。在每一种训练集和测试集下,都会对应一个模型及模型得分(如均方误差)。

    用法

    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:用于指定多个lambda值的元组或数组对象,默认该参数包含0.1、1和10三种值。
    fit_intercept:bool类型参数,是否需要拟合截距项,默认为True。
    normalize:bool类型参数,建模时是否需要对数据集做标准化处理,默认为False。
    scoring:指定用于评估模型的度量方法。
    cv:指定交叉验证的重数。
    gcv_mode:用于指定执行广义交叉验证的方法,当样本量大于特征数或自变量矩阵X为稀疏矩阵时,该参数选用'auto';当该参数为'svd'时,表示通过矩阵X的奇异值分解方法执行广义交叉验证;当该参数为'engin'时,则表示通过矩阵X'X的特征根分解方法执行广义交叉验证。
    store_cv_values:bool类型参数,是否在每一个Lambda值下都保存交叉验证得到的评估信息,默认为False,只有当参数cv为None时有效。
    

    示例

    # 岭回归模型的交叉验证
    # 设置交叉验证的参数,对于每一个Lambda值,都执行10重交叉验证
    ridge_cv = RidgeCV(alphas = Lambdas, normalize=True, scoring='neg_mean_squared_error', cv = 10)
    # 模型拟合
    ridge_cv.fit(X_train, y_train)
    # 返回最佳的lambda值
    ridge_best_Lambda = ridge_cv.alpha_
    ridge_best_Lambda
    

    结果为0.014649713983072863

    糖尿病数据的预测

    # 导入第三方包中的函数
    from sklearn.metrics import mean_squared_error
    # 基于最佳的Lambda值建模
    ridge = Ridge(alpha = ridge_best_Lambda, normalize=True)
    ridge.fit(X_train, y_train)
    # 返回岭回归系数
    pd.Series(index = ['Intercept'] + X_train.columns.tolist(),data = [ridge.intercept_] + ridge.coef_.tolist())
    # 预测
    ridge_predict = ridge.predict(X_test)
    # 预测效果验证
    RMSE = np.sqrt(mean_squared_error(y_test,ridge_predict))
    RMSE
    

    结果为53.11911788753519

    Lasso回归的系数求解

    Lasso回归模型

    岭回归模型解决线性回归模型中矩阵X^′X不可逆的办法是添加l2正则的惩罚项,但缺陷在于始终保留建模时的所有变量,无法降低模型的复杂度。对于此,Lasso回归采用了l1正则的惩罚项。
    J(β)=∑(y−Xβ)^2+λ‖β‖_1=∑(y−Xβ)^2+∑λ|β|
    具体公式推导不列出

    几何意义

    image.png

    以二维空间为例,左半边的半椭圆体代表∑_{i=1}^n(y_i−β_0−∑_{j=1}^2x_{ij}β_j)^2的部分,它是关于两个系数的二次函数;正方体则代表了|β_1|+|β_2|≤t$的部分;

    将LASSO回归的惩罚项映射到二维空间的话,就会形成“角”,一旦“角”与抛物面相交,就会导致β_1为0,进而实现变量的删除。而且相比于圆面,l1正则项的方框顶点更容易与抛物面相交,起到变量筛选的效果;

    λ值的确定--可视化法

    用法

    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:用于指定模型的最大迭代次数,默认为1000
    tol:用于指定模型收敛的阈值,默认为0.0001。
    warm_start:bool类型参数,是否将前一次的训练结果用作后一次的训练,默认为False。
    positive:bool类型参数,是否将回归系数强制为正数,默认为False。
    random_state:用于指定随机数生成器的种子。
    selection:指定每次迭代时所选择的回归系数,如果为'random',表示每次迭代中将随机更新回归系数;如果为'cyclic',则表示每次迭代时回归系数的更新都基于上一次运算
    

    核心代码示例

    # 导入第三方模块中的函数
    from sklearn.linear_model import Lasso,LassoCV
    # 构造空列表,用于存储模型的偏回归系数
    lasso_cofficients = []
    for Lambda in Lambdas:
        lasso = Lasso(alpha = Lambda, normalize=True, max_iter=10000)
        lasso.fit(X_train, y_train)
        lasso_cofficients.append(lasso.coef_)
    
    # 绘制Lambda与回归系数的关系
    plt.plot(Lambdas, lasso_cofficients)
    # 对x轴作对数变换
    plt.xscale('log')
    # 设置折线图x轴和y轴标签
    plt.xlabel('Lambda')
    plt.ylabel('Cofficients')
    # 显示图形
    plt.show()
    
    Figure_2.png

    解读
    图中的每条折线代表了不同的变量,对于比较突出的喇叭形折线,一般代表该变量存在多重共线性;
    从图中可知,当λ值逼近于0时,各变量对应的回归系数应该与线性回归模型的最小二乘解完全一致;随着λ值的不断增加,各回归系数的取值会迅速缩减为0;
    λ值落在0.05附近时,绝大多数变量的回归系数趋于稳定,所以,基本可以锁定合理的λ值范围;

    λ值的确定--交叉验证法

    用法

    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,指代Lambda的最小值与最大值之商
    n_alphas:指定正则项系数Lambda的个数,默认为100个
    alphas:指定具体的Lambda值列表用于模型的运算
    fit_intercept:bool类型参数,是否需要拟合截距项,默认为True
    normalize:bool类型参数,建模时是否需要对数据集做标准化处理,默认为False
    precompute:bool类型参数,是否在建模前,通过计算Gram矩阵提升运算速度,默认为False
    max_iter:指定模型最大的迭代次数,默认为1000次
    tol:用于指定模型收敛的阈值,默认为0.001
    copy_X:bool类型参数,是否复制自变量X的数值,默认为True
    cv:指定交叉验证的重数
    verbose:bool类型参数,是否返回模型运行的详细信息,默认为False
    n_jobs:指定交叉验证过程中使用的CPU数量,即是否需要并行处理,默认为1表示不并行运行,如果为-1,表示将所有的CPU用于交叉验证的运算
    positive:bool类型参数,是否将回归系数强制为正数,默认为False
    random_state:用于指定随机数生成器的种子
    selection:指定每次迭代时所选择的回归系数,如果为'random',表示每次迭代中将随机更新回归系数;如果为'cyclic',则表示每次迭代时回归系数的更新都基于上一次运算
    

    示例

    # LASSO回归模型的交叉验证
    lasso_cv = LassoCV(alphas = Lambdas, normalize=True, cv = 10, max_iter=10000)
    lasso_cv.fit(X_train, y_train)
    # 输出最佳的lambda值
    lasso_best_alpha = lasso_cv.alpha_
    lasso_best_alpha
    

    结果为0.06294988990221888

    # 基于最佳的lambda值建模
    lasso = Lasso(alpha = lasso_best_alpha, normalize=True, max_iter=10000)
    lasso.fit(X_train, y_train)
    # 返回LASSO回归的系数
    pd.Series(index = ['Intercept'] + X_train.columns.tolist(),data = [lasso.intercept_] + lasso.coef_.tolist())
    
    # 预测
    lasso_predict = lasso.predict(X_test)
    # 预测效果验证
    RMSE = np.sqrt(mean_squared_error(y_test,lasso_predict))
    RMSE
    

    结果为53.061437258225745
    糖尿病数据的预测结果53.048714552744023
    与前面的岭回归预测结果类似。

    相关文章

      网友评论

        本文标题:2020-05-17 第八章 岭回归与Lasso回归模型(pyt

        本文链接:https://www.haomeiwen.com/subject/ytpsohtx.html