逻辑回归模型L1正则化(Lasso)实现与结果解读技术咨询
L1正则化逻辑回归的实现优化与问题解答
一、初始代码的合理性分析
你的初始实现存在几个关键问题,导致结果不可靠:
- 每次循环重新划分训练测试集:不同alpha对应的模型在完全不同的训练/测试数据上评估,无法公平比较不同正则化强度的效果,结果随机性极强。
- 数据泄露:在划分数据集前就用全量数据拟合
StandardScaler,会把测试集的统计信息(均值、方差)带入训练过程,导致模型泛化能力的估计偏乐观。 - 单轮评估不稳定:仅用一次训练测试拆分的对数似然选择alpha,容易受随机拆分的影响,无法得到稳定的最优正则化参数。
二、数据缩放的正确时机
绝对不能在划分训练测试集前对全数据集做缩放!正确流程是:
- 先划分
X_train, X_test, Y_train, Y_test - 用
X_train的特征部分拟合StandardScaler - 用拟合好的scaler分别缩放
X_train和X_test的特征
这样能避免测试集信息泄露,保证模型评估的客观性。
三、Alpha值选择方式的可行性
你最初用循环遍历alpha+单轮拆分评估的方式不可行,建议改用交叉验证(比如sklearn的LogisticRegressionCV):
- 交叉验证会在训练集内部多次拆分,对每个alpha计算平均性能指标,结果更稳定
LogisticRegressionCV会自动选择交叉验证中最优的C值(注意sklearn中C = 1/alpha,C越大正则化强度越弱)
四、更新后代码的问题修正与解答
1. 代码中的错误修正
你的更新代码里有一个严重错误:不能用测试集去拟合lasso_model_best!测试集的作用是评估模型泛化能力,不是用来训练的。正确流程是:
X_train, X_test, Y_train, Y_test = train_test_split(DM, Y, train_size=0.8) AlphasToTest = np.arange(0.01, 10, 0.01) # 转换为sklearn的C参数(C = 1/alpha) Cs = 1 / AlphasToTest scaler = StandardScaler() # 仅用训练集拟合scaler scaler.fit(X_train[:, 1:]) ScaledDM_train = scaler.transform(X_train[:, 1:]) # 用交叉验证选择最优C lasso_model_cv = LogisticRegressionCV( penalty='l1', solver='saga', Cs=Cs, cv=5, scoring='neg_log_loss', max_iter=1000 ) lasso_model_cv.fit(ScaledDM_train, Y_train.ravel()) best_C = lasso_model_cv.C_[0] # 用最优C在完整训练集上拟合最终模型 lasso_model_best = LogisticRegression( penalty='l1', solver='saga', C=best_C, max_iter=1000 ) lasso_model_best.fit(ScaledDM_train, Y_train.ravel()) # 用测试集评估模型 ScaledDM_test = scaler.transform(X_test[:, 1:]) y_pred_proba = lasso_model_best.predict_proba(ScaledDM_test) test_neg_log_loss = log_loss(Y_test, y_pred_proba)
2. 获取Lasso逻辑回归的p值
sklearn的LogisticRegression(带L1正则化)默认不提供p值,原因是正则化改变了系数的统计分布,传统基于无正则化模型的p值假设不再成立。如果需要近似获取显著性指标,可采用以下方法:
方法1:筛选特征后用无正则化模型计算p值
先用Lasso选出非零系数的特征,再用statsmodels的无正则化逻辑回归拟合这些特征,得到p值:import statsmodels.api as sm # 获取Lasso选中的特征索引 selected_features_idx = np.where(lasso_model_best.coef_[0] != 0)[0] # 提取训练集中的选中特征,加上常数项 X_train_selected = sm.add_constant(ScaledDM_train[:, selected_features_idx]) # 拟合无正则化逻辑回归 model = sm.Logit(Y_train, X_train_selected) result = model.fit() print(result.summary()) # 查看p值注意:这种方法仅能作为参考,因为Lasso筛选后的特征可能仍存在共线性,且正则化的影响未完全消除。
方法2:Bootstrapping近似显著性
通过多次重采样训练数据,拟合Lasso模型,统计每个特征系数不为零的频率,频率越高说明特征越稳定:n_bootstrap = 1000 coef_counts = np.zeros(ScaledDM_train.shape[1]) for _ in range(n_bootstrap): # 重采样训练数据 idx = np.random.choice(len(Y_train), len(Y_train), replace=True) X_boot = ScaledDM_train[idx] Y_boot = Y_train[idx] # 拟合Lasso模型 boot_model = LogisticRegression(penalty='l1', solver='saga', C=best_C, max_iter=1000) boot_model.fit(X_boot, Y_boot.ravel()) # 统计非零系数 coef_counts += (boot_model.coef_[0] != 0).astype(int) # 计算每个特征的选中频率 feature_selection_freq = coef_counts / n_bootstrap print("特征选中频率:", feature_selection_freq)
3. 模型输出的最优解读
- 系数解读:
- 非零系数对应的特征是Lasso筛选出的、对二分类结果有预测价值的特征。
- 系数的正负表示特征对正类概率的影响方向:正系数意味着特征值越高,样本属于正类的概率越大;负系数则相反。
- 系数的大小反映特征的相对重要性(因数据已标准化,系数大小可直接比较)。
- 最优C值解读:
LogisticRegressionCV选出的best_C是在交叉验证中使neg_log_loss最优的参数,代表该正则化强度下模型的泛化能力最好。
- 模型性能解读:
- 用测试集的
neg_log_loss(对数损失)、ROC-AUC、准确率等指标评估模型的泛化能力,而不是仅看训练集表现。 - 若多个特征系数被压缩为0,说明这些特征对预测结果的贡献被正则化抵消,可从后续分析中剔除。
- 用测试集的
内容的提问来源于stack exchange,提问作者SeanC
相关产品推荐
相关产品推荐

