「日拱一码」142 Lasso调参注意事项与技巧
目录
核心参数 alpha(正则化强度)
优化相关参数:max_iter, tol, selection
其他重要参数
调参流程总结
代码示例
核心参数 alpha(正则化强度)
- 含义:这是 Lasso 模型中最重要的参数。
alpha控制着 L1 正则化的强度。alpha越大,惩罚越重,模型系数会被压缩得越厉害,更多的系数会变为 0(特征选择更激进),模型越简单(高偏差,低方差)。alpha越小,惩罚越轻,模型越接近普通的线性回归,可能保留更多特征(低偏差,高方差)。 - 技巧:
- 必须使用交叉验证:绝不能凭感觉设置一个
alpha。必须使用LassoCV或GridSearchCV在验证集上寻找最佳值。 - 搜索范围:通常在一个很大的对数尺度范围内进行搜索,例如
np.logspace(-4, 2, 50)(即从 0.0001 到 100)。 - 观察路径:使用
lasso_path或LassoCV的alphas_和mse_path_属性绘制正则化路径,直观看到系数随alpha变化而收缩至 0 的过程。
- 必须使用交叉验证:绝不能凭感觉设置一个
优化相关参数:max_iter, tol, selection
当数据特征非常多或特征间相关性较强时,优化过程可能变得困难。
-
max_iter(最大迭代次数):- 注意:如果模型没有收敛,Scikit-learn 会发出警告。这意味着在给定的
max_iter内,坐标下降算法未能找到最优解。 - 技巧:遇到不收敛警告时,首先尝试增大
max_iter,例如从 1000 增加到 5000 或 10000。
- 注意:如果模型没有收敛,Scikit-learn 会发出警告。这意味着在给定的
-
tol(优化容忍度):- 注意:它定义了优化算法停止的准则。如果两次迭代间参数更新的变化小于
tol,则认为已经收敛。 - 技巧:如果确信模型需要更精细的优化,可以减小
tol(例如从1e-4到1e-5)。但这会增加计算成本。通常和max_iter配合调整。
- 注意:它定义了优化算法停止的准则。如果两次迭代间参数更新的变化小于
-
selection(系数更新方式):cyclic(循环):按顺序依次更新每个特征系数。random(随机):随机选择特征系数进行更新。- 技巧:当特征数量极大且预期只有少量特征重要时,
‘random'通常收敛得更快。这也是将selection='random'设为默认值的原因。如果追求确定性结果(每次运行一样),则使用‘cyclic'。
其他重要参数
-
precompute(预计算Gram矩阵):- 注意:预计算
X.T.dot(X)可以加速优化过程。 - 技巧:通常设置为
True或‘auto'(让算法决定)。如果特征数n_features远大于样本数n_samples,预计算可能效率不高,此时设置为False。
- 注意:预计算
-
warm_start(热启动):- 注意:当设置为
True时,用上一次拟合的解作为本次训练的初始化。 - 技巧:在需要探索多个
alpha值时非常有用(例如自己写循环或使用LassoCV时),因为热启动可以利用上一个alpha的解,加速收敛。如果你只是用GridSearchCV一次性搜索,它内部会自动处理,此处设置可能无影响。
- 注意:当设置为
-
positive(强制系数为正):- 注意:将系数约束为非负数。
- 技巧:仅在业务逻辑要求特征对目标变量只有正向影响时使用。这是一个强假设,会限制模型,但有时能提高可解释性。
-
fit_intercept(拟合截距):- 注意:除非确信数据已经中心化(均值为0),否则永远应该设置为
True。
- 注意:除非确信数据已经中心化(均值为0),否则永远应该设置为
调参流程总结
- 数据预处理:标准化!Lasso 对特征的尺度非常敏感。必须使用
StandardScaler对特征进行标准化(均值为0,方差为1),否则系数大小无法直接比较,正则化也会不公平。目标变量y通常不需要标准化。 - 核心搜索 (
alpha):使用LassoCV在宽泛的范围内进行交叉验证,找到大致最优的alpha。 - 处理收敛问题:如果
LassoCV有不收敛警告,增大max_iter。 - 精细搜索:在最优
alpha附近,可以结合GridSearchCV进行更精细的搜索,并同时调整max_iter和tol。 - 评估与验证:在测试集上评估最终模型的性能,并检查选中的特征是否符合业务逻辑。
代码示例
import numpy as np
import matplotlib.pyplot as plt
from sklearn.linear_model import Lasso, LassoCV
from sklearn.datasets import make_regression
from sklearn.model_selection import train_test_split, GridSearchCV
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import mean_squared_error, r2_scoreX, y = make_regression(n_samples=1000, n_features=100, n_informative=10,noise=0.5, random_state=42)
# n_informative=10 表示只有10个是真正有用的特征,其余90个是噪音,适合Lasso进行特征选择X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test) # 注意:测试集用训练集的均值和方差进行转换# 设置一个宽泛的 alpha 搜索范围(对数尺度)
alphas = np.logspace(-3, 1, 50) # 从 0.001 到 10# 创建 LassoCV 对象,使用5折交叉验证
lasso_cv = LassoCV(alphas=alphas, cv=5, max_iter=5000, random_state=42, selection='random')
lasso_cv.fit(X_train_scaled, y_train)print(f"最佳 alpha (来自 LassoCV): {lasso_cv.alpha_:.6f}") # 0.020236
print(f"交叉验证最佳分数 (R2): {lasso_cv.score(X_train_scaled, y_train):.4f}") # 1.0000# 定义参数网格
param_grid = {'alpha': np.logspace(np.log10(lasso_cv.alpha_ / 2), np.log10(lasso_cv.alpha_ * 2), 20),'max_iter': [5000, 10000],'tol': [1e-4, 1e-5]
}# 创建基础Lasso模型
base_lasso = Lasso(random_state=42, selection='random')
grid_search = GridSearchCV(estimator=base_lasso, param_grid=param_grid,scoring='neg_mean_squared_error', cv=5, n_jobs=-1)
grid_search.fit(X_train_scaled, y_train)print(f"\n最佳参数 (来自 GridSearchCV): {grid_search.best_params_}")
best_model = grid_search.best_estimator_# 使用 LassoCV 的模型进行评估
y_pred_cv = lasso_cv.predict(X_test_scaled)
mse_cv = mean_squared_error(y_test, y_pred_cv)
r2_cv = r2_score(y_test, y_pred_cv)# 使用 GridSearchCV 的模型进行评估
y_pred_grid = best_model.predict(X_test_scaled)
mse_grid = mean_squared_error(y_test, y_pred_grid)
r2_grid = r2_score(y_test, y_pred_grid)print("\n=== 模型在测试集上的性能 ===")
print(f"LassoCV 模型 - MSE: {mse_cv:.4f}, R2: {r2_cv:.4f}") # MSE: 0.2558, R2: 1.0000
print(f"GridSearchCV 模型 - MSE: {mse_grid:.4f}, R2: {r2_grid:.4f}") # MSE: 0.2572, R2: 1.0000