ML-For-Beginners 分类课程实战:深入对比 scikit-learn 逻辑回归求解器(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 课程「Cuisine classifiers 1」(
4-Classification/2-Classifiers-1)中的课后作业「研究求解器」(Study the solvers)展开。作业要求从课程中出现的求解器中挑选两个进行对比:它们解决什么问题?如何适配不同的数据结构?为什么在特定场景下你会选择其中一个?本文以课程 README.md、notebook.ipynb 及 官方求解器答案 notebook 为事实依据,逐层拆解solver与multi_class两个核心参数,帮助你完成一份有深度、有依据的对比作业,并真正理解逻辑回归背后的优化原理。
作业背景:为什么课程要让你「研究求解器」
在4-Classification/2-Classifiers-1这一课中,你使用上一课保存的cleaned_cuisines.csv数据,尝试用多种分类器"根据一组食材预测菜系"。课程明确指出,在调用 scikit-learn 执行逻辑回归时,有两个必须指定的关键参数:
multi_class:决定多分类的方案(scheme),即ovr或multinomial;solver:决定优化问题所用的算法(algorithm),即求解器。
作业(见 英文原版 assignment.md,本仓库另有 希腊语翻译版)要求你:从课程列出的求解器中选两个,用自己的话比较它们的异同,并回答三个问题——它们解决什么类型的问题、如何与不同数据结构协作、为什么你会选择其中一个而不是另一个。评分标准(Rubric)要求提交一份包含两段对比文字的.doc文件,一段对应一个求解器。
要完成这份作业,先要搞清楚"求解器"到底是什么。
什么是求解器(Solver):逻辑回归背后的优化器
课程对求解器给出了精确定义:solver 是"优化问题中使用的算法"。逻辑回归虽然名字里带"回归",本质上是拟合一个决策边界——即找到一组权重,使得损失函数(交叉熵等)最小。这个"找权重"的过程就是数值优化,而不同的求解器就是不同的优化算法。
从源码结构看,scikit-learn 的LogisticRegression在拟合时会把solver参数分发给底层不同的实现路径:liblinear走的是独立于 scikit-learn 的 LIBLINEAR 库,而lbfgs、newton-cg、sag、saga走的是 scikit-learn 自带(或依赖 SciPy 优化器)的实现。这正是课程强调"并非所有 solver 都能与所有 multi_class 值配对"的根源——不同实现支持的目标函数形式不同。
课程引用的 scikit-learn 文档给出了多分类情况下的训练算法行为:
- 若
multi_class设为ovr,采用one-vs-rest(OvR)方案:为每个类别训练一个二分类器,判断"是不是这一类"; - 若
multi_class设为multinomial,采用交叉熵损失(softmax 多分类),直接对所有类别联合优化;当前multinomial仅被lbfgs、sag、saga、newton-cg支持。
课程用一个要点框解释了两者的本质区别:逻辑回归本身是为二分类设计的,这些方案让它能更好地处理多分类任务。OvR 把多分类拆成多个二分类;multinomial 则用 softmax 一次性输出各类别概率。
六个求解器速览:各自解决什么问题
scikit-learn 的LogisticRegression主要提供以下求解器(课程重点涉及liblinear与lbfgs,下表为课程与官方文档综合整理):
| 求解器 | 优化思想 | 擅长场景 | 主要限制 |
|---|---|---|---|
liblinear | 坐标下降法(LIBLINEAR 库) | 小数据集、L1 正则、稀疏数据 | 只支持 OvR,不支持multinomial;会惩罚截距 |
lbfgs | 拟牛顿法(Limited-memory BFGS) | 中小数据集,默认常被设为默认值 | 不支持 L1 正则 |
newton-cg | 牛顿法 + 共轭梯度 | 中小数据集 | 不支持 L1 正则;大数据集收敛慢 |
sag | 随机平均梯度下降(Stochastic Average Gradient) | 大数据集(速度快) | 对未缩放数据不鲁棒;不支持 L1 |
saga | SAG 的扩展,支持 L1/弹性网络 | 大数据集 + 需要稀疏正则 | 对未缩放数据不鲁棒 |
newton-cholesky(较新版本可选) | 牛顿法 + Cholesky 分解 | L2 正则场景 | 课程未涉及,可自行扩展阅读 |
课程在练习中还提示:可以尝试把solver='liblinear'换成lbfgs,后者"经常被设置为默认值"——在较新的 scikit-learn 版本中,lbfgs确实是solver的默认值,且搭配multi_class默认的auto行为时,对多分类任务表现稳定。
solver × 数据结构适配表:课程的核心对照依据
课程直接给出了 scikit-learn 官方文档中的求解器对比表格,用来解释"不同求解器如何处理不同数据结构带来的挑战"。这张表是完成作业的核心证据,务必逐行理解:
按表中内容可归纳为三个维度:
惩罚项(Penalties)兼容性:
Multinomial + L2:liblinear不支持,lbfgs/newton-cg/sag/saga支持;OvR + L2:所有求解器都支持;Multinomial + L1:仅saga支持;OvR + L1:仅liblinear与saga支持;Elastic-Net(L1+L2 组合):仅saga支持;- 无惩罚(
none):lbfgs/newton-cg/sag/saga支持,liblinear不支持。
行为特征(Behaviors):
- 惩罚截距(Penalize the intercept):仅
liblinear会这样做,通常这是不理想的; - 大数据集更快:
sag与saga具备优势; - 对未缩放数据鲁棒:
liblinear/lbfgs/newton-cg鲁棒,sag/saga不鲁棒(它们依赖梯度估计,特征尺度差异大会影响收敛)。
- 惩罚截距(Penalize the intercept):仅
数据结构的适配结论:
- 如果你的数据是大规模的(样本量很大),优先考虑
sag/saga; - 如果你的数据未经标准化且样本量不大,
liblinear/lbfgs/newton-cg更稳; - 如果你需要L1 稀疏解(特征很多、希望自动筛特征),
liblinear(OvR 下)或saga是选择; - 如果你想要联合多分类(multinomial)概率,则必须避开
liblinear。
- 如果你的数据是大规模的(样本量很大),优先考虑
实战验证:在菜系数据上比较liblinear与lbfgs
课程的核心练习就是用liblinear训练一个多分类逻辑回归模型。这里以课程 官方求解器答案 notebook 的实际输出为基准,完整还原流程,方便你对照着做对比实验。
步骤一:加载清洗后的菜系数据
import pandas as pd cuisines_df = pd.read_csv("../data/cleaned_cuisines.csv") cuisines_df.head()数据为 382 列(1 列索引 +cuisine标签 + 380 个食材特征列),每一行表示一道菜,特征列为 0/1 布尔值表示是否使用某种食材。
步骤二:划分特征与标签
cuisines_label_df = cuisines_df['cuisine'] # 标签:菜系 cuisines_feature_df = cuisines_df.drop(['Unnamed: 0', 'cuisine'], axis=1) # 特征:380 个食材列步骤三:训练集/测试集划分
from sklearn.model_selection import train_test_split X_train, X_test, y_train, y_test = train_test_split(cuisines_feature_df, cuisines_label_df, test_size=0.3)步骤四:用liblinear+ OvR 训练并评估
from sklearn.linear_model import LogisticRegression import numpy as np lr = LogisticRegression(multi_class='ovr', solver='liblinear') model = lr.fit(X_train, np.ravel(y_train)) accuracy = model.score(X_test, y_test) print("Accuracy is {}".format(accuracy))课程 notebook.ipynb 中的对应单元(lr = LogisticRegression(multi_class='ovr',solver='liblinear'))运行后,官方答案输出为:
Accuracy is 0.8181818181818182即准确率超过 80%。注意课程 README 中使用np.ravel(y_train)将标签 Series 展平为一维数组——这是fit时的常见要求。
对比实验:把上面代码中的solver='liblinear'换成solver='lbfgs'(保持multi_class='ovr'),再观察准确率变化。你会发现lbfgs在该数据集上同样可行,这正印证了表格中"OvR + L2 对所有求解器都支持"的结论;由于本数据集特征全部是 0/1 布尔值(尺度一致),sag/saga对未缩放数据不鲁棒的问题在此不构成障碍,也可以尝试。
步骤五:单样本预测与概率解释
# 测试第 50 行数据 print(f'ingredients: {X_test.iloc[50][X_test.iloc[50]!=0].keys()}') print(f'cuisine: {y_test.iloc[50]}')官方答案在这个随机划分下第 50 行的真实标签为korean,食材包含artemisia, black_pepper, mushroom, shiitake, soy_sauce, vegetable_oil。接着用predict_proba查看各类别概率:
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()输出示例(官方 notebook 实际结果):
| 0 | |
|---|---|
| korean | 0.392231 |
| chinese | 0.372872 |
| japanese | 0.218825 |
| thai | 0.013427 |
| indian | 0.002645 |
这里能看到 OvR 模式的一个特点:各类别概率由多个二分类器的得分构成,korean 与 chinese 的得分比较接近,说明这两个菜系在食材上确有重叠(都含酱油、香菇等)。课程 README 中展示的另一组随机划分结果(indian 0.715851)则显示,当食材特征(香菜、洋葱、豌豆、土豆、番茄、植物油)非常"印度"时,模型会给出高置信度判断。
步骤六:分类报告深挖
from sklearn.metrics import classification_report y_pred = model.predict(X_test) print(classification_report(y_test, y_pred))官方 notebook 在liblinear+ovr下的分类报告(完整结果):
| precision | recall | f1-score | support | |
|---|---|---|---|---|
| chinese | 0.75 | 0.73 | 0.74 | 223 |
| indian | 0.93 | 0.88 | 0.90 | 255 |
| japanese | 0.78 | 0.78 | 0.78 | 253 |
| korean | 0.87 | 0.86 | 0.86 | 236 |
| thai | 0.76 | 0.84 | 0.80 | 232 |
| accuracy | 0.82 | 1199 | ||
| macro avg | 0.82 | 0.82 | 0.82 | 1199 |
| weighted avg | 0.82 | 0.82 | 0.82 | 1199 |
从报告可以看出,indian类别的 precision/recall 最高,而chinese/japanese较低——这与"亚洲菜系食材重叠"的现实一致。这是你对比不同 solver 时的理想观测点:把 solver 换成lbfgs、sag、saga,对比各自的 accuracy、各类别 f1-score 与训练耗时,就能在作业中写出有数据支撑的对比结论。
如何撰写对比作业:一份结构建议
结合评分标准(「用两段文字、每段对应一个求解器、进行有思考深度的对比」),建议按以下骨架组织你的.doc文件:
第一段:
liblinear- 解决什么问题:小规模、稀疏(0/1 特征)数据的二分类与 OvR 多分类;支持 L1 得到稀疏解;
- 如何与数据结构协作:对未缩放数据鲁棒,但只支持 OvR,不能输出 multinomial 联合概率;会惩罚截距;
- 为什么选它:数据集小、特征为布尔值时,训练快且结果可解释(课程首选的合理性)。
第二段:
lbfgs- 解决什么问题:中小规模数据的稳健优化,默认 solver,支持
multinomial(softmax 交叉熵)多分类; - 如何与数据结构协作:对未缩放数据鲁棒;支持 L2 与无惩罚;但不能处理 L1;
- 为什么选它:想要联合多分类概率、又不想为数据标准化操心时,
lbfgs是稳妥选择;在菜系数据上准确率与liblinear相当,还避免了 OvR 概率割裂的问题。
- 解决什么问题:中小规模数据的稳健优化,默认 solver,支持
(可选加分)第三段:
saga- 唯一同时支持 L1、L2、Elastic-Net 且可配
multinomial的求解器,大数据集速度快——适合把作业推向"为什么saga是现代推荐的通用默认"。
- 唯一同时支持 L1、L2、Elastic-Net 且可配
课程在「🚀 挑战」中鼓励你继续深挖 solver 的幕后原理,并在「Review & Self Study」中建议进一步阅读逻辑回归背后的数学推导——对比作业正是检验你理解深度的最佳载体。
关联资源索引
- 课程正文:4-Classification/2-Classifiers-1/README.md(含 solver 表格、完整代码与分类报告)
- 作业原文:4-Classification/2-Classifiers-1/assignment.md
- 官方答案 notebook:4-Classification/2-Classifiers-1/solution/notebook.ipynb(含真实运行输出)
- 起始 notebook:4-Classification/2-Classifiers-1/notebook.ipynb
- 数据文件:4-Classification/data/cleaned_cuisines.csv
- 后续课程(对比更多分类器):4-Classification/3-Classifiers-2/README.md
完成本作业后,你将能自信地回答:什么样的数据结构对应什么样的求解器,以及为什么——这不仅是课程评分的要求,也是你在真实项目中为逻辑回归选型的基本功。
【免费下载链接】ML-For-Beginners12 weeks, 26 lessons, 52 quizzes, classic Machine Learning for all项目地址: https://gitcode.com/GitHub_Trending/ml/ML-For-Beginners
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考