Ridge和Lasso回归:Python Scikit-Learn的完整指南

本文通过实例讲解如何使用scikit-learn进行Ridge回归和Lasso回归,对比两种方法在防止过拟合上的作用,包括如何调整超参数α,以及在不同数据集上的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文将通过一个例子来讲述怎么用scikit-learn来学习Ridge回归和Lasso回归,这两种特殊的线性回归模型  。

1.简介

一般线性回归我们用均方误差作为损失函数,也就是最小二乘法,但是为了防止模型的过拟合,我们在建立线性模型的时候经常需要加入正则化项,一般有L1正则化和L2正则化。

线性回归的L1正则化通常称为Lasso回归,线性回归的L2正则化通常称为Ridge回归,它和一般线性回归的区别是在损失函数上增加了一个L2正则化的项。

2.损失函数

Lasso回归的L1正则化的项有一个常数系数α来调节损失函数的均方差项和正则化项的权重,损失函数表达式如下:

J ( θ ) = 1 2 ( X θ − Y ) T ( X θ − Y ) + α ∣ ∣ θ ∣ ∣ 1 J(\mathbf\theta) = \frac{1}{2}(\mathbf{X\theta} - \mathbf{Y})^T(\mathbf{X\theta} - \mathbf{Y}) + \alpha||\theta||_1 J(θ)=21(XθY)T(XθY)+αθ1

其中α为常数系数,需要进行调优, ∣ ∣ θ ∣ ∣ 1 ||\theta||_1 θ1 是L1正则化,是对前面的参数加了一个惩罚项,如果 θ \theta θ 取值教大,则优化函数受到较大惩罚。
因此,Lasso回归缩小了系数,有助于降低模型复杂度和多重共线性。

Ridge回归的正则化项是L2范数,而Lasso回归的正则化项是L1范数。具体Ridge回归的损失函数表达式如下:

J ( θ ) = 1 2 ( X θ − Y ) T ( X θ − Y ) + 1 2 α ∣ ∣ θ ∣ ∣ 2 2 J(\mathbf\theta) = \frac{1}{2}(\mathbf{X\theta} - \mathbf{Y})^T(\mathbf{X\theta} - \mathbf{Y}) + \frac{1}{2}\alpha||\theta||_2^2 J(θ)=21(XθY)T(XθY)+21αθ22

其中α为常数系数,需要进行调优, ∣ ∣ θ ∣ ∣ 2 ||\theta||_2 θ2 是L1正则化,是对前面的参数加了一个惩罚项。

Ridge回归在不抛弃任何一个特征的情况下,缩小了回归系数,使得模型相对而言比较的稳定,但和Lasso回归比,这会使得模型的特征留的特别多,模型解释性差。

3. Scikit-Learn Ridge回归实战

使用Boston house data 的数据集进行模型的拟合。

模型拟合
import matplotlib.pyplot as plt
import numpy as np 
import pandas as pd
import matplotlib
matplotlib.rcParams.update({'font.size': 12})
from sklearn.datasets import load_boston
from sklearn.cross_validation import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.linear_model import Ridge
 #加载数据集
boston=load_boston() 
boston_df=pd.DataFrame(boston.data,columns=boston.feature_names)
print(boston_df.info())
boston_df.head(3)
boston_df.describe()

# 增加一个 Price 属性作为目标值
boston_df['Price']=boston.target
#print (boston_df.head(3))
#newX 训练数据的属性值
newX=boston_df.drop('Price',axis=1)
#newY 训练数据的target值
newY=boston_df['Price']

#交叉验证 分割数据集  30% 数据作为测试
X_train,X_test,y_train,y_test=train_test_split(newX,newY,test_size=0.3,random_state=3)

#线性模型
lr = LinearRegression()
lr.fit(X_train, y_train)

# alpha系数越大,惩罚越大
rr = Ridge(alpha=0.01) 
rr.fit(X_train, y_train)

# 使用较大的alpha值
rr100 = Ridge(alpha=100) 
rr100.fit(X_train, y_train)

train_score=lr.score(X_train, y_train)
test_score=lr.score(X_test, y_test)

Ridge_train_score = rr.score(X_train,y_train)
Ridge_test_score = rr.score(X_test, y_test)

Ridge_train_score100 = rr100.score(X_train,y_train)
Ridge_test_score100 = rr100.score(X_test, y_test)

print ("linear regression train score:", train_score)
print ("linear regression test score:", test_score)
print ("ridge regression train score low alpha:", Ridge_train_score)
print ("ridge regression test score low alpha:", Ridge_test_score)
print ("ridge regression train score high alpha:", Ridge_train_score100)
print ("ridge regression test score high alpha:", Ridge_test_score100)

#图形化展示 rr.coef_--->模型系数
# markers 为显示的图形
# alpha控制透明度,0为完全透明,1为不透明
plt.plot(rr.coef_,alpha=0.7,linestyle='none',marker='+',markersize=5,color='red',label=r'Ridge; $\alpha = 0.01$',zorder=7)
plt.plot(rr100.coef_,alpha=0.5,linestyle='none',marker='d',markersize=6,color='blue',label=r'Ridge; $\alpha = 100$') 
plt.plot(lr.coef_,alpha=0.4,linestyle='none',marker='o',markersize=7,color='green',label='Linear Regression')

plt.xlabel('Coefficient Index',fontsize=16)
plt.ylabel('Coefficient Magnitude',fontsize=16)
plt.legend(fontsize=13,loc=4)
plt.show()

对上图做个简单解释:

  1. 在X轴中我们使用系数索引(0-12),对于波士顿数据,有13个特征。
  2. 当α的取比较小的值(0.01),此时模型系数受到较少限制时,系数幅度几乎与线性回归相同。
  3. 当较大α(100)值,我们看到系数指数为3,4,5的时候,与线性回归情况相比,幅度要小得多。这是使用Ridge回归缩小系数幅度的示例。
超参数α选择

要使用Ridge回归,我们必须要指定超参数 α,你也许有疑问 α 到底改设置成多少?

实际上我们并不知道超参数 α 取多少最好,实际研究是需要在多组自选的α中选择一个最优的。

scikit-learn 提供了一个交叉验证选择最优 α 的 API,可以使用这个API来选择 α 参数,假设我们想在这10个 α 值中选择一个最优的值,代码如下:

from sklearn.linear_model import RidgeCV
ridgecv = RidgeCV(alphas=[0.01, 0.1, 0.5, 1, 5, 7, 10, 30,100, 200])
ridgecv.fit(X_train, y_train)
ridgecv.alpha_  # 0.1 

输出结果为:0.1 ,说明在我们给定的这组超参数中, 0.1是最优的 α 值。

4. Scikit-Learn Lasso回归实战

Lasso 回归的正则化项是L1范数,跟 Ridge 回归唯一的区别是不考虑系数的平方,而是考虑幅度。

这种类型的正则化(L1)可以导致零系数,对于输出的评估,一些特征被完全忽略。

因此,Lasso回归不仅有助于减少过度拟合,而且可以帮助我们进行特征选择。

就像Ridge回归一样,正则化参数 α 可以被控制,接下来是使用 sklearn 中的癌症数据集看看效果。不使用上面的波士顿房屋数据,是因为癌症数据集有30个特征属性,而波士顿房屋数据只有13个特征属性。当特征属性比较多的时候,我们可以通过改变正则化参数使用Lasso回归的特征参数的选择。

import math 
import matplotlib.pyplot as plt 
import pandas as pd
import numpy as np

from sklearn.linear_model import Lasso
from sklearn.linear_model import LinearRegression
from sklearn.datasets import load_breast_cancer
from sklearn.cross_validation import train_test_split
cancer = load_breast_cancer()
#cancer.keys()
cancer_df = pd.DataFrame(cancer.data, columns=cancer.feature_names)
#cancer_df.head(3)
X = cancer.data
Y = cancer.target
X_train,X_test,y_train,y_test=train_test_split(X,Y, test_size=0.3, random_state=31)

lasso = Lasso() # 默认alpha =1 
lasso.fit(X_train,y_train)

train_score=lasso.score(X_train,y_train)
test_score=lasso.score(X_test,y_test)

coeff_used = np.sum(lasso.coef_!=0)
print("training score:", train_score )
print ("test score: ", test_score)
print ("number of features used: ", coeff_used)

lasso001 = Lasso(alpha=0.01, max_iter=10e5)
lasso001.fit(X_train,y_train)

train_score001=lasso001.score(X_train,y_train)
test_score001=lasso001.score(X_test,y_test)

coeff_used001 = np.sum(lasso001.coef_!=0)
print ("training score for alpha=0.01:", train_score001 )
print ("test score for alpha =0.01: ", test_score001)
print ("number of features used: for alpha =0.01:", coeff_used001)

lasso00001 = Lasso(alpha=0.0001, max_iter=10e5)
lasso00001.fit(X_train,y_train)

train_score00001=lasso00001.score(X_train,y_train)
test_score00001=lasso00001.score(X_test,y_test)

coeff_used00001 = np.sum(lasso00001.coef_!=0)
print ("training score for alpha=0.0001:", train_score00001 )
print( "test score for alpha =0.0001: ", test_score00001)
print ("number of features used: for alpha =0.0001:", coeff_used00001)

lr = LinearRegression()
lr.fit(X_train,y_train)
lr_train_score=lr.score(X_train,y_train)
lr_test_score=lr.score(X_test,y_test)
print ("LR training score:", lr_train_score )
print ("LR test score: ", lr_test_score)

plt.subplot(1,2,1)
plt.plot(lasso.coef_,alpha=0.7,linestyle='none',marker='*',markersize=5,color='red',label=r'Lasso; $\alpha = 1$',zorder=7) # alpha here is for transparency
plt.plot(lasso001.coef_,alpha=0.5,linestyle='none',marker='d',markersize=6,color='blue',label=r'Lasso; $\alpha = 0.01$') # alpha here is for transparency

plt.xlabel('Coefficient Index',fontsize=16)
plt.ylabel('Coefficient Magnitude',fontsize=16)
plt.legend(fontsize=13,loc=4)
plt.subplot(1,2,2)
plt.plot(lasso.coef_,alpha=0.7,linestyle='none',marker='*',markersize=5,color='red',label=r'Lasso; $\alpha = 1$',zorder=7) # alpha here is for transparency
plt.plot(lasso001.coef_,alpha=0.5,linestyle='none',marker='d',markersize=6,color='blue',label=r'Lasso; $\alpha = 0.01$') # alpha here is for transparency
plt.plot(lasso00001.coef_,alpha=0.8,linestyle='none',marker='v',markersize=6,color='black',label=r'Lasso; $\alpha = 0.00001$') # alpha here is for transparency
plt.plot(lr.coef_,alpha=0.7,linestyle='none',marker='o',markersize=5,color='green',label='Linear Regression',zorder=2)
plt.xlabel('Coefficient Index',fontsize=16)
plt.ylabel('Coefficient Magnitude',fontsize=16)
plt.legend(fontsize=13,loc=4)
plt.tight_layout()
plt.show()
对上图做个简单解释:
  1. Lasso 回归中的正则化参数的默认值(alpha)为1;
  2. 在默认参数的时候,在癌症数据集中的30个特征中,仅使用了4个特征(系数的非零值);
  3. 训练和测试的分数(仅有4个特征)都很低,得出结论,该默认模型不适合癌症数据集;
  4. 通过减少alpha和增加迭代次数来减少这种不足,当 alpha = 0.01,非零特征= 10,训练和测试分数增加;
  5. 首先看左边的一张图,对于α= 1,我们可以看到大多数系数为零或接近零,而 α= 0.01 就多了特征;
  6. 当我们把 α= 0.0001,非零特征属性数为 22,训练和测试分数与基本线性回归情况相同了;
5. 总结

为了防止模型的过拟合,在建立线性模型的时候经常需要加入(L1、L2)正则化项,也就是对应Lasso和Ridge回归模型,这两种特殊的线性回归模型都有默认的参数以及超参数,在实际运用的过程中一般使用交叉验证选择最优参数,这样可以提高模型的泛化能力。

### Lasso回归中超参数调节方法 Lasso回归中的超参数主要是指正则化强度 \( \lambda \),其决定了模型中正则化项的影响程度。较大的 \( \lambda \) 值会使更多回归系数被压缩为零,从而使模型更简单并实现特征选择;而较小的 \( \lambda \) 值会让模型更接近普通的线性回归[^4]。 为了找到最优的 \( \lambda \) 值,通常采用以下几种方法: #### 1. **交叉验证** 交叉验证是最常用的超参数调优技术之一。通过将数据划分为训练集验证集,可以在不同的 \( \lambda \) 值下评估模型性能,并选取使验证误差最小的那个 \( \lambda \)[^2]。具体来说,可以使用 K 折交叉验证 (K-Fold Cross Validation) 来提高结果的稳定性。 ```python from sklearn.linear_model import LassoCV import numpy as np # 创建带有内置交叉验证功能的Lasso模型 lasso_cv = LassoCV(cv=5, random_state=0) # 使用数据拟合模型 X, y = load_data() # 加载数据 lasso_cv.fit(X, y) # 输出最佳λ值 best_lambda = lasso_cv.alpha_ print(f"Best lambda value: {best_lambda}") ``` 上述代码展示了如何利用 `sklearn` 中的 `LassoCV` 类来进行自动化交叉验证以寻找最佳 \( \lambda \) 值[^3]。 #### 2. **网格搜索** 另一种常用的技术是网格搜索 (Grid Search),它通过对预定义的一系列候选 \( \lambda \) 值逐一尝试,最终选出表现最好的那个。这种方法虽然计算成本较高,但在某些情况下能够提供更高的精度。 ```python from sklearn.model_selection import GridSearchCV from sklearn.linear_model import Lasso param_grid = {'alpha': np.logspace(-4, 1, 50)} # 定义α范围 grid_search = GridSearchCV(Lasso(), param_grid, cv=5) grid_search.fit(X, y) optimal_alpha = grid_search.best_params_['alpha'] print(f"Optimal alpha found via Grid Search: {optimal_alpha}") ``` 此代码片段说明了如何设置一个合理的 \( \alpha \) (对应于 \( \lambda \))取值区间并通过 `GridSearchCV` 找到最合适的值。 #### 3. **随机搜索** 当超参数空间较大时,随机搜索 (Randomized Search) 可能是一个更快的选择。相比于穷举式的网格搜索,随机搜索仅从指定分布中抽取有限数量的组合进行测试,因此效率更高。 --- ### 总结 在实际应用中,推荐优先考虑基于交叉验证的方法(如 `LassoCV`),因为它们既高效又易于实施。同时需要注意的是,在执行任何类型的超参数调整之前,应始终对输入变量进行标准化处理,以便不同尺度下的特征不会干扰优化过程。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值