ML-For-Beginners 分类实践:深入剖析 scikit-learn LogisticRegression 的 Solver 选择与对比
【免费下载链接】ML-For-Beginners12 weeks, 26 lessons, 52 quizzes, classic Machine Learning for all项目地址: https://gitcode.com/GitHub_Trending/ml/ML-For-Beginners
本篇技术指南基于 ML-For-Beginners 项目第 11 课《Cuisine Classifiers 1》(课程正文)及其配套作业《Study the solvers》(英文原版作业),围绕"在多重分类任务中如何理解并选择 LogisticRegression 的 solver"这一核心主题展开。你将掌握liblinear、lbfgs、newton-cg、sag、saga五个 solver 的底层原理、适用数据规模与正则化支持差异,并学会按照作业要求,用对比论证的方式完成一份结构化的 solver 研究报告。
作业背景:从"预测菜系"到"研究求解器"
本课的任务是基于上一课清洗出的平衡数据集cleaned_cuisines.csv,构建一个"根据一组食材预测国家菜系"的多分类模型(数据文件)。在建模过程中,课程引入了一个关键概念:solver,即"优化问题中使用的算法"。作业要求学习者在课程所列出的 solver 中任选两个,用自己的话完成对比分析,回答三个核心问题:
- 它们解决什么类型的问题?
- 它们如何处理不同的数据结构?
- 为什么你会选择其中一个而不是另一个?
要高质量完成这份作业,首先需要理解 solver 在 scikit-learn 逻辑回归中的确切角色。
先厘清两个参数:multi_class与solver
在课程中,当使用LogisticRegression处理多分类数据时,需要显式指定两个关键参数(课程正文):
multi_class:决定多分类展开方案。设为ovr(one-vs-rest,一对剩余)时,模型为每个类别训练一个二分类器,将其余所有类别视为负类;设为multinomial时,模型直接使用交叉熵损失(cross-entropy loss)训练一个多分类模型。solver:决定优化算法,即"用什么算法求解优化问题"。
值得注意的是,并非所有 solver 都能与所有multi_class方案自由组合。例如课程文档明确说明:multinomial选项目前仅由lbfgs、sag、saga和newton-cg支持,而liblinear只能配合ovr使用。
五个 solver 逐一拆解
liblinear:小规模数据的坐标下降法
liblinear源自 LIBLINEAR 库,采用坐标下降(coordinate descent)优化策略,专为线性分类器设计。它的优势在于:
- 原生支持 L1 正则化,可用于特征选择;
- 对未标准化的数据鲁棒性较好;
- 适合中小规模数据集。
代价是它不支持multinomial方案,也无法使用none(无惩罚项)选项,且会惩罚截距项(这一行为通常不被推荐)。
lbfgs:拟牛顿法的默认之选
lbfgs(Limited-memory Broyden–Fletcher–Goldfarb–Shanno)是一种拟牛顿法,通过近似海森矩阵(Hessian)的逆来加速收敛,内存占用远小于完整牛顿法。它:
- 同时支持
ovr与multinomial两种方案; - 支持 L2 正则化与无惩罚项;
- 对未标准化的数据鲁棒;
- 是课程中指出的"通常作为默认值"的 solver。
newton-cg:牛顿共轭梯度法
newton-cg使用牛顿法配合共轭梯度(conjugate gradient)求解,计算成本较高,适合中小规模数据。它支持ovr与multinomial、L2 惩罚与无惩罚项,同样对未标准化数据鲁棒。
sag:随机平均梯度法
sag(Stochastic Average Gradient)是一种随机平均梯度方法,通过维护所有样本梯度的平均值来平滑更新,特别适合大规模数据集(收敛速度快于传统梯度下降)。但它的前提条件是特征需经过标准化,否则容易不收敛。
saga:弹性网正则化的唯一选择
saga是sag的改进版,增加了对 L1 和弹性网(Elastic-Net,L1+L2 混合)正则化的支持。在课程列举的五个 solver 中,只有saga同时支持multinomial+ L1、OVR + L1 以及 Elastic-Net,且同样适合大规模数据集,但同样要求特征标准化。
Solver 支持能力速查表
课程正文中的solvers.png表格(图片原件)系统总结了五个 solver 在不同惩罚项和数据行为下的支持情况,这也是完成作业对比时最直接的依据:
| 场景 | liblinear | lbfgs | newton-cg | sag | saga |
|---|---|---|---|---|---|
| Multinomial + L2 | 否 | 是 | 是 | 是 | 是 |
| OVR + L2 | 是 | 是 | 是 | 是 | 是 |
| Multinomial + L1 | 否 | 否 | 否 | 否 | 是 |
| OVR + L1 | 是 | 否 | 否 | 否 | 是 |
| Elastic-Net | 否 | 否 | 否 | 否 | 是 |
| 无惩罚项(none) | 否 | 是 | 是 | 是 | 是 |
| 惩罚截距(不推荐) | 是 | 否 | 否 | 否 | 否 |
| 大规模数据更快 | 否 | 否 | 否 | 是 | 是 |
| 对未标准化数据鲁棒 | 是 | 是 | 是 | 否 | 否 |
从表中可以提炼出三条核心结论,直接服务于作业的对比论证:
- 追求 L1 正则化/特征选择时,
liblinear(仅限 OVR)与saga(OVR 与 multinomial 均可)是仅有的两个选项; - 数据量大时,优先考虑
sag或saga,但必须先做特征标准化; - 需要
multinomial交叉熵方案且数据未标准化时,lbfgs是最稳妥的默认选择——这也是课程建议"尝试lbfgs作为默认值"的原因。
在真实数据集上跑通作业所需的对比实验
作业要求"用自己的话"对比两个 solver,而课程 notebook 提供了完整的对比实验模板(官方解答 notebook)。以liblinear为例,训练与评估代码如下:
from sklearn.linear_model import LogisticRegression from sklearn.model_selection import train_test_split from sklearn.metrics import classification_report import numpy as np import pandas as pd cuisines_df = pd.read_csv("../data/cleaned_cuisines.csv") cuisines_label_df = cuisines_df['cuisine'] cuisines_feature_df = cuisines_df.drop(['Unnamed: 0', 'cuisine'], axis=1) X_train, X_test, y_train, y_test = train_test_split( cuisines_feature_df, cuisines_label_df, test_size=0.3) # 方案一:ovr + liblinear lr = LogisticRegression(multi_class='ovr', solver='liblinear') model = lr.fit(X_train, np.ravel(y_train)) print("Accuracy is {}".format(model.score(X_test, y_test))) # 方案二:multinomial + lbfgs(作业对比的另一个候选) lr2 = LogisticRegression(multi_class='multinomial', solver='lbfgs') model2 = lr2.fit(X_train, np.ravel(y_train)) print("Accuracy is {}".format(model2.score(X_test, y_test))) y_pred = model.predict(X_test) print(classification_report(y_test, y_pred))在实际运行中,ovr + liblinear方案在测试集上获得了81.8% 的准确率,分类报告显示各菜系的 F1 分数大致在 0.74~0.90 之间(来源:solution/notebook.ipynb)。这组数据为作业对比提供了可引用的事实依据。
此外,还可以像课程那样用predict_proba观察单个样本的概率分布,理解 solver 优化出的模型如何"犹豫":
test = X_test.iloc[50].values.reshape(-1, 1).T proba = model.predict_proba(test) classes = model.classes_ resultdf = pd.DataFrame(data=proba, columns=classes) topPrediction = resultdf.T.sort_values(by=[0], ascending=[False]) topPrediction.head()对比实验时建议控制变量:固定multi_class与数据集切分(例如固定random_state),只切换solver,从而将准确率、收敛时间与正则化能力差异归因于 solver 本身。你也可以参考本课 R 语言解法(lesson_11-R.ipynb)中通过multinom_reg(penalty = ...)调参的思路,理解惩罚参数对多分类模型的同等重要性。
作业的评分标准与交付要求
原作业以 Rubric 形式明确了评分维度(见 assignment.md):
| 标准 | 优秀 | 合格 | 待改进 |
|---|---|---|---|
| 内容 | 提交一份 .doc 文件,包含两个段落,每段对一个 solver 进行深思熟虑的对比 | 只提交了一个段落 | 作业不完整 |
对照"优秀"标准,一份高质量作业应当:为每个选中的 solver 各写一段,段落内至少覆盖"解决的问题类型""与数据结构的适配关系""选择理由"三个维度,并结合上文的支持矩阵与实验结果给出可验证的论据。例如,比较liblinear与saga时,可以论证:两者都支持 L1 正则化(前者限 OVR、后者同时支持 multinomial),但saga在大规模数据上更快且需要标准化,而liblinear对未标准化数据更稳健、实现更轻量。
从作业出发的延伸思考
课程结尾的挑战环节建议深入阅读 scikit-learn 提供的分类算法选项,进一步探究 solver 背后的数学机制(课程正文)。solver 的选择本质上是"优化算法特性 × 数据形态 × 正则化需求"三者之间的权衡:没有放之四海而皆准的最优解,只有与当前数据规模、特征分布和建模目标最匹配的组合。完成本次作业后,建议继续阅读本系列后续课程,观察同一数据集在 SVM 等其他分类器下的表现差异(下一课 Classifiers-2),从而建立更完整的分类算法选型视野。
【免费下载链接】ML-For-Beginners12 weeks, 26 lessons, 52 quizzes, classic Machine Learning for all项目地址: https://gitcode.com/GitHub_Trending/ml/ML-For-Beginners
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考