ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

机器学习期末复习:按题型拆解推导、手算与sklearn自检

机器学习期末复习:按题型拆解推导、手算与sklearn自检 简介《机器学习期末复习题及答案》面向高校机器学习课程备考学生与自学者围绕期末考点整理成一份可直接刷题的复习文档。内容涵盖单项选择题、多项选择题、名词解释、简答题与编程题等题型涉及数据集划分、欠拟合与过拟合、K近邻、朴素贝叶斯、决策树、支持向量机核函数、聚类算法、线性回归与均方误差等核心概念并附答案解析便于对照知识点回顾原理与判别依据。压缩包内共1个docx文档约20KB体量轻便适合打印或在平板上随时翻阅。目前已有1764人学习下载。读者可借此梳理课程知识框架通过题目与解析定位薄弱环节编程题部分给出线性回归建模步骤与K近邻分类的实现思路能帮助理解从导入库、建模、拟合到预测评估的完整流程适合考前集中突破与查漏补缺。1. 期末复习别从第一页翻起先按题型把考点切开机器学习期末卷面基本是三类题的组合概念辨析与简答、公式推导与手算迭代、代码或伪代码填空。按教材目录从头翻容易在定义堆里耗掉一半复习时间推导和手算还是空的。更划算的做法是先找近三年的卷子把每道题对应的知识点列成一张表再倒着回去补。这张表里线性回归、逻辑回归、SVM 稳定出推导题朴素贝叶斯和 K-means 出概率与迭代题混淆矩阵、P/R/F1、ROC-AUC 出计算题偏差方差与正则化几乎只出简答。后续几章按这个权重展开每段公式都配可运行的验证代码考场上手算的中间结果能直接和代码输出对答案错在哪一步一眼看得出来。2. 判别式模型复习线性回归、逻辑回归与 SVM 的手推与代码对照2.1 线性回归闭式解和梯度下降两条路都得会写卷面最常见的问法有两种给定样本求最优参数 w或者写出梯度下降的更新式并迭代两步。最小二乘目标写成 J(w) ½‖Xw − y‖²对 w 求偏导置零得到 Xᵀ(Xw − y) 0整理出正规方程 w (XᵀX)⁻¹Xᵀy。这个式子要背更要会判断 XᵀX 是否可逆特征之间存在强共线或者样本数少于特征数时矩阵奇异这时标准答案是加 L2 正则变成 w (XᵀX λI)⁻¹Xᵀy也就是岭回归的闭式解。梯度下降版本的更新式是 w ← w − η·Xᵀ(Xw − y)/mm 为样本数。考试一般给定初始 w、学习率和两三个样本让你写两轮迭代结果逐项代入比背公式更稳。import numpy as np # 设计矩阵第 0 列固定为 1用来吸收截距项 X np.array([[1.0, 1.0], [1.0, 2.0], [1.0, 3.0]]) y np.array([2.0, 3.1, 4.2]) # 路线一正规方程闭式解 w_closed np.linalg.inv(X.T X) X.T y # 路线二批量梯度下降 w_gd np.zeros(2) eta 0.05 # 学习率过大直接发散 for _ in range(500): grad X.T (X w_gd - y) / len(y) w_gd w_gd - eta * grad print(闭式解:, w_closed) # 约 [0.9, 1.1] print(梯度下降:, w_gd) # 500 步后贴近闭式解逻辑说明X.T X是 2×2 的格拉姆矩阵求逆在特征维度很高时开销大工程上常用np.linalg.lstsq代替。学习率 0.05 是针对这组数据试出来的换成 1.0 会震荡发散。考试手算时通常只要求两步按 w ← w − ηXᵀ(Xw − y)/m 逐项代进去保留两位小数就够了。另外要区分损失函数和评估指标训练用的是均方误差卷面问模型好坏时答的是 RMSE 或 R²两者不能混着写。2.2 逻辑回归从对数似然推到梯度就是 (h − y)x逻辑回归的假设是 h_w(x) σ(wᵀx)其中 σ(z) 1/(1 e^{−z})。对数似然写成 L(w) Σ[yᵢ log hᵢ (1 − yᵢ) log(1 − hᵢ)]对 w_j 求导中间用到 σ′(z) σ(z)(1 − σ(z))最后化简成 ∂L/∂w_j Σ(yᵢ − hᵢ)xᵢⱼ。梯度等于误差乘特征这个结论是高频考点建议自己推一遍再背推导过程本身就是一道大题。import numpy as np def sigmoid(z): return 1.0 / (1.0 np.exp(-z)) # 4 个样本2 个特征标签 0/1 X np.array([[1.0, -1.0], [1.0, 0.5], [1.0, 1.0], [1.0, 2.0]]) y np.array([0.0, 0.0, 1.0, 1.0]) w np.zeros(2) lr 0.5 for step in range(200): h sigmoid(X w) # 前向线性输出压到 (0,1) grad X.T (h - y) / len(y) # 梯度方向 w - lr * grad # 沿负梯度走 print(权重:, w) print(预测概率:, sigmoid(X w))参数说明学习率 0.5 比线性回归能放得更大因为 sigmoid 导数最大只有 0.25梯度天然被压缩过。判分点常常卡在梯度写成 (y − h)那是梯度上升的形式必须配 w lr·grad 才对符号和更新方向混用是扣分重灾区。np.exp(-z)在 z 绝对值很大时会溢出工程写法要按符号分支处理卷面写公式不受影响但代码题里出现这种写法要能反应过来。2.3 SVM间隔、对偶与 KKT 条件在卷面上怎么答完整SVM 的复习主线是三层结构原始问题、对偶问题、KKT 条件。原始问题是 min ½‖w‖²约束为 yᵢ(wᵀxᵢ b) ≥ 1。构造拉格朗日函数对 w 和 b 求偏导置零代回消去 w、b得到对偶问题 max Σαᵢ − ½ΣΣαᵢαⱼyᵢyⱼxᵢᵀxⱼ约束是 Σαᵢyᵢ 0、αᵢ ≥ 0。这一步是从原始问题推到对偶的完整链条考试常给一半让你补另一半。KKT 条件里最常被问的是互补松弛 αᵢ(yᵢ(wᵀxᵢ b) − 1) 0。它说明只有落在间隔边界上的样本 αᵢ 才非零其余样本对模型没有贡献这正是模型只依赖少数支持向量的来源。软间隔把约束放宽成 yᵢ(wᵀxᵢ b) ≥ 1 − ξᵢ对偶里 αᵢ 的上界变成 C核技巧就是把内积 xᵢᵀxⱼ 换成 K(xᵢ, xⱼ)RBF 核的 K(x, x′) exp(−γ‖x − x′‖²)γ 越大决策边界越贴合训练点。维度线性回归逻辑回归SVM输出连续实数(0,1) 概率决策函数符号损失均方误差对数似然Hinge 损失 L2闭式解有无无关键超参正则系数 λ学习率、正则系数C、核参数 γ卷面高频问法正规方程、梯度式梯度推导、概率解释对偶、KKT、核技巧from sklearn.linear_model import LinearRegression, LogisticRegression from sklearn.svm import SVC import numpy as np rng np.random.default_rng(0) X rng.normal(size(60, 2)) y (X[:, 0] X[:, 1] 0).astype(int) # 线性可分的二分类 lin LinearRegression().fit(X, y) # 回归硬套分类看分界方向 log LogisticRegression(C1.0).fit(X, y) svm SVC(kernellinear, C1.0).fit(X, y) print(线性回归系数:, lin.coef_) print(逻辑回归系数:, log.coef_) print(SVM 系数:, svm.coef_, 支持向量数:, len(svm.support_))逻辑说明LinearRegression对 0/1 标签做回归虽然给出一个分界方向但会被远离边界的样本拉动系数和 SVM 差得明显svm.support_的长度就是支持向量个数考试问哪些是支持向量可以用它核对答案。参数 C 控制误分类惩罚C 变大间隔变窄、容易过拟合在对偶里表现为 αᵢ 的上界抬升。3. 生成式与无监督朴素贝叶斯、K-means、EM 的推导套路与手算3.1 朴素贝叶斯拉普拉斯平滑的手算一步都不能省朴素贝叶斯的核心假设是特征条件独立决策规则为 argmax_c P(c)·ΠP(xⱼ | c)。卷面几乎必出一道表格题给一小份训练集算某个测试样本的后验概率。真正容易丢分的是零概率问题——某个特征取值在某个类别下从未出现连乘直接归零。拉普拉斯平滑写成 P(xⱼ a | c) (N_jc 1) / (N_c S_j)其中 N_jc 是该取值在该类别下的计数N_c 是该类的样本总数S_j 是第 j 个特征可能的取值个数。import numpy as np # 特征矩阵0/1 两个取值最后一列是类别 data np.array([[1, 0, 0], [1, 1, 0], [0, 1, 1], [0, 0, 1]]) X, y data[:, :-1], data[:, -1] n_feat, n_val X.shape[1], 2 def nb_predict(x, alpha1.0): scores {} for c in np.unique(y): mask (y c) prior (mask.sum() alpha) / (len(y) alpha * len(np.unique(y))) logp np.log(prior) for j in range(n_feat): cnt (X[mask, j] x[j]).sum() alpha denom mask.sum() alpha * n_val logp np.log(cnt / denom) # 取对数避免连乘下溢 scores[c] logp return max(scores, keyscores.get), scores print(nb_predict(np.array([1, 1])))参数说明alpha1.0就是标准拉普拉斯平滑。考试若追问 alpha 取 0 会怎样答案是训练集中未出现的特征取值概率为 0整个后验被一票否决。用对数相加代替概率连乘是工程写法卷面上写乘积形式即可但要补一句实际计算取对数防止下溢。3.2 K-means目标函数、迭代步骤与收敛性判断K-means 的目标是最小化簇内平方和 J Σ_k Σ_{x∈C_k} ‖x − μ_k‖²。迭代只有两步把每个样本分配到最近的质心把质心更新为所属样本的均值。考试常让手算两轮并比较 J 值变化或者问算法为什么一定收敛。标准答案是两步都在单调不增 J而样本的划分方案数量有限因此有限步内必然停止——但它收敛到的是局部最优不保证全局最优。import numpy as np X np.array([[1.0, 1.0], [1.5, 2.0], [3.0, 4.0], [5.0, 7.0], [3.5, 5.0], [4.5, 5.0], [3.5, 4.5]]) def kmeans(X, k2, iters10, seed0): rng np.random.default_rng(seed) centers X[rng.choice(len(X), k, replaceFalse)].copy() for _ in range(iters): d ((X[:, None, :] - centers[None, :, :]) ** 2).sum(-1) labels d.argmin(1) # 分配步 new_centers np.array([X[labels i].mean(0) if (labels i).any() else centers[i] for i in range(k)]) if np.allclose(new_centers, centers): # 质心不动即收敛 break centers new_centers return centers, labels centers, labels kmeans(X) print(质心:\n, centers) print(簇内平方和:, sum(((X[labels i] - centers[i]) ** 2).sum() for i in range(2)))参数说明随机初始化的种子影响最终结果。考试若问两次运行结果不同怎么解释答案就是目标函数非凸、初始点不同会落进不同的局部极小。工程上常用 k-means 初始化缓解sklearn.cluster.KMeans的initk-means是默认值。k 的选取常与肘部法一起考指标是不同 k 下的簇内平方和曲线拐点。3.3 EM 算法E 步与 M 步在 GMM 里各做什么EM 解决的是含隐变量的最大似然估计。E 步用当前参数算隐变量的后验 γ_ik π_k·N(xᵢ | μ_k, Σ_k) / Σ_j π_j·N(xᵢ | μ_j, Σ_j)M 步用 γ 做加权更新 μ_k Σᵢγ_ik·xᵢ / Σᵢγ_ikπ_k Σᵢγ_ik / N协方差同样按加权形式算。还需要能解释为什么 EM 每轮似然不降——它优化的是对数似然的下界ELBO每轮抬高下界真实似然随之单调不减。维度K-meansGMM隐变量硬分配 0/1软分配后验概率簇形状球形、等方差任意椭球优化方法交替最小化EM输出簇标签均值、协方差、混合系数初始敏感性高高可多次重启卷面考点收敛性证明、手算迭代E/M 步公式、ELBOfrom sklearn.mixture import GaussianMixture import numpy as np X np.array([[1.0, 1.0], [1.5, 2.0], [3.0, 4.0], [5.0, 7.0], [3.5, 5.0], [4.5, 5.0], [3.5, 4.5]]) gmm GaussianMixture(n_components2, covariance_typefull, random_state0).fit(X) print(均值:\n, gmm.means_) print(混合系数:, gmm.weights_) print(软分配前两行:\n, gmm.predict_proba(X)[:2])参数说明covariance_type决定协方差结构full让每个簇有独立的完整协方差diag只学对角。考试若问GMM 和 K-means 的关系答案是当各簇协方差趋于零且相等时GMM 的软分配退化成硬分配的 K-means。predict_proba给出的正是 E 步的 γ可以拿来和手算结果逐项对照。4. 模型评估与调参混淆矩阵、ROC-AUC、交叉验证的算式拆解4.1 混淆矩阵到 Precision/Recall/F1每一步都要写清分母评估题的失分大多不在概念而在分母写错。给定 TP、FP、FN、TN精确率 P TP/(TP FP)召回率 R TP/(TP FN)F1 2PR/(P R)。要记牢精确率的分母是预测为正召回率的分母是真实为正这两个方向弄反后面几问连锁全错。预测正预测负合计真实正TP 40FN 1050真实负FP 20TN 130150按上表算P 40/60 ≈ 0.667R 40/50 0.8F1 2 × 0.667 × 0.8 / (0.667 0.8) ≈ 0.727准确率 170/200 0.85。注意准确率高不代表模型可用正负样本 1:3 时全部预测为负也能拿到 0.75 的准确率所以卷面上经常要求同时给出 P、R、F1。from sklearn.metrics import precision_recall_fscore_support, confusion_matrix import numpy as np y_true np.array([1]*40 [1]*10 [0]*20 [0]*130) # 1 为正类 y_pred np.array([1]*40 [0]*10 [1]*20 [0]*130) cm confusion_matrix(y_true, y_pred) p, r, f1, _ precision_recall_fscore_support(y_true, y_pred, averagebinary) print(cm) print(fP{p:.3f} R{r:.3f} F1{f1:.3f})逻辑说明confusion_matrix默认把较大的标签当作正类标签是 0/1 时正类为 1输出矩阵按 [[TN, FP], [FN, TP]] 排列手算时务必先确认排列顺序顺序写错等于整题作废。averagebinary表示只统计正类指标多分类题要改成macro或weighted并在解答里说明选了哪个以及为什么。4.2 ROC 与 AUC手算排序法和它的概率解释ROC 曲线以 FPR FP/(FP TN) 为横轴、TPR TP/(TP FN) 为纵轴遍历所有阈值画出。AUC 有两条理解路径一是曲线下的面积二是随机抽一个正样本和一个负样本、正样本得分更高的概率。手算时排序法更快——把样本按预测分数降序排列AUC 正样本排在负样本前面的对数 / (P × N)遇到同分按 0.5 计入。from sklearn.metrics import roc_auc_score import numpy as np # 预测分数不是标签分数越高越倾向正类 scores np.array([0.9, 0.8, 0.7, 0.4, 0.35, 0.3]) y np.array([1, 1, 0, 1, 0, 0]) auc roc_auc_score(y, scores) print(fAUC{auc:.3f}) # 手算校验逐对比较正负样本 pos, neg scores[y 1], scores[y 0] wins sum((p n) 0.5 * (p n) for p in pos for n in neg) print(对数法:, wins / (len(pos) * len(neg)))参数说明roc_auc_score的第二个参数必须是连续分数或概率直接传 0/1 标签会退化成准确率的变体AUC 就失去意义。手算部分用(p n) 0.5 * (p n)处理同分只有和库函数结果一致才能说明排序法真学会了。当类别极不平衡时卷面常要求比较 PR 曲线与 ROC结论是 PR 曲线对少数类更敏感。4.3 偏差方差、交叉验证与正则化简答题的答题骨架偏差-方差分解写成 E[(y − f̂)²] 偏差² 方差 噪声。作答时按三段推进偏差描述模型假设与真实函数的偏离程度方差描述模型对训练集扰动的敏感度欠拟合对应高偏差过拟合对应高方差正则化通过限制参数范数降低方差、略微抬高偏差从而压低总误差。岭回归惩罚 λ‖w‖²Lasso 惩罚 λ‖w‖₁后者能产生稀疏解这一点常被追问。交叉验证的作用是让评估不依赖单次划分k 折把数据分成 k 份轮流做验证集再取平均。k 越大评估越稳但计算越贵工程常用 5 或 10。卷面会问留一法k N的偏差和方差标准答案是偏差小、方差大且计算代价最高。from sklearn.linear_model import Ridge, Lasso from sklearn.model_selection import cross_val_score from sklearn.preprocessing import StandardScaler from sklearn.pipeline import make_pipeline from sklearn.datasets import make_regression import numpy as np X, y make_regression(n_samples120, n_features20, noise8.0, random_state0) for alpha in [0.01, 0.1, 1.0, 10.0]: # 正则化前必须标准化否则惩罚强度被特征量纲带偏 pipe make_pipeline(StandardScaler(), Ridge(alphaalpha)) scores cross_val_score(pipe, X, y, cv5, scoringneg_mean_squared_error) print(falpha{alpha:5} CV MSE{-scores.mean():.2f}) lasso make_pipeline(StandardScaler(), Lasso(alpha0.1)).fit(X, y) print(Lasso 非零系数个数:, np.sum(lasso[-1].coef_ ! 0))参数说明alpha就是公式里的 λ越大正则越强、参数越被压向零。把StandardScaler放进管道是为了保证每一折内部只用训练部分算均值和方差避免数据泄漏手写交叉验证最容易在这里出错。neg_mean_squared_error取负号是因为 sklearn 统一按越大越好计分。看 Lasso 的非零系数个数是验证稀疏性的直接办法20 个特征下如果全部非零说明 alpha 取得太小。5. 用 sklearn 把答案跑成自检脚本错题复现与参数扰动复习阶段性价比最高的动作是把复习题里的数字塞进脚本跑一遍。手算和代码不一致的地方八成是公式记错或符号方向反了比反复看书有效得多。做法是每类题写一个函数输入题目给的数字、输出答案再和手算对照。from sklearn.metrics import accuracy_score, f1_score from sklearn.linear_model import LogisticRegression from sklearn.model_selection import StratifiedKFold, cross_val_score import numpy as np def check_metric(y_true, y_pred): 把手算的指标和库函数对齐 return {acc: accuracy_score(y_true, y_pred), f1: f1_score(y_true, y_pred)} # 同一份数据跑 10 次分层交叉验证看指标波动 X np.random.default_rng(1).normal(size(200, 5)) y (X[:, 0] X[:, 1] 0).astype(int) cv StratifiedKFold(n_splits10, shuffleTrue, random_state0) scores cross_val_score(LogisticRegression(max_iter1000), X, y, cvcv, scoringf1) print(fF1 均值 {scores.mean():.3f}标准差 {scores.std():.3f}) print(逐折:, np.round(scores, 3))StratifiedKFold保证每折的类别比例和整体一致类别不平衡时比普通 KFold 稳shuffleTrue配合random_state让结果可复现。逐折分数散得开说明模型对划分敏感这时候单看某一次划分的分数没有意义这个观察可以直接当作为什么需要交叉验证的论据。参数扰动是另一条自检路线把 C 从 0.01 扫到 100记录训练集和验证集分数训练分数高、验证分数低且差距大的区间就是过拟合区。判断标准很直接——验证分数随 C 增大先升后降峰值处就是这道题要的答案。自检对象扰动参数观察指标对应卷面结论逻辑回归正则C0.01→100训练/验证 F1过拟合与欠拟合的分界岭回归alpha0.01→10交叉验证 MSE偏差方差权衡GMMn_components2→5对数似然、BIC模型选择K-meansk2→8簇内平方和肘部法选 k扫参数时固定随机种子否则同一组参数两次跑出不同分数自检就失去参照。如果时间只够做一件事优先把混淆矩阵和 AUC 这两类计算题写成脚本——它们手算时最容易因分母写反而整题作废代码能在几秒内给出对照。把逐折分数和扰动曲线抄到复习笔记的边上比只记一个平均值更能解释清楚模型稳不稳。本文还有配套的精品资源点击获取
返回列表