news 2026/9/17 17:40:48

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

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
机器学习期末复习:按题型拆解推导、手算与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)/m,m 为样本数。考试一般给定初始 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(C=1.0).fit(X, y) svm = SVC(kernel="linear", C=1.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, alpha=1.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, key=scores.get), scores print(nb_predict(np.array([1, 1])))

参数说明:alpha=1.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, k=2, iters=10, seed=0): rng = np.random.default_rng(seed) centers = X[rng.choice(len(X), k, replace=False)].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.KMeansinit="k-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 步公式、ELBO
from 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_components=2, covariance_type="full", random_state=0).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.667,R = 40/50 = 0.8,F1 = 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, average="binary") print(cm) print(f"P={p:.3f} R={r:.3f} F1={f1:.3f}")

逻辑说明:confusion_matrix默认把较大的标签当作正类,标签是 0/1 时正类为 1,输出矩阵按 [[TN, FP], [FN, TP]] 排列,手算时务必先确认排列顺序,顺序写错等于整题作废。average="binary"表示只统计正类指标,多分类题要改成macroweighted,并在解答里说明选了哪个以及为什么。

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(f"AUC={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_samples=120, n_features=20, noise=8.0, random_state=0) for alpha in [0.01, 0.1, 1.0, 10.0]: # 正则化前必须标准化,否则惩罚强度被特征量纲带偏 pipe = make_pipeline(StandardScaler(), Ridge(alpha=alpha)) scores = cross_val_score(pipe, X, y, cv=5, scoring="neg_mean_squared_error") print(f"alpha={alpha:<5} CV MSE={-scores.mean():.2f}") lasso = make_pipeline(StandardScaler(), Lasso(alpha=0.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_splits=10, shuffle=True, random_state=0) scores = cross_val_score(LogisticRegression(max_iter=1000), X, y, cv=cv, scoring="f1") print(f"F1 均值 {scores.mean():.3f},标准差 {scores.std():.3f}") print("逐折:", np.round(scores, 3))

StratifiedKFold保证每折的类别比例和整体一致,类别不平衡时比普通 KFold 稳;shuffle=True配合random_state让结果可复现。逐折分数散得开,说明模型对划分敏感,这时候单看某一次划分的分数没有意义,这个观察可以直接当作"为什么需要交叉验证"的论据。

参数扰动是另一条自检路线:把 C 从 0.01 扫到 100,记录训练集和验证集分数,训练分数高、验证分数低且差距大的区间就是过拟合区。判断标准很直接——验证分数随 C 增大先升后降,峰值处就是这道题要的答案。

自检对象扰动参数观察指标对应卷面结论
逻辑回归正则C(0.01→100)训练/验证 F1过拟合与欠拟合的分界
岭回归alpha(0.01→10)交叉验证 MSE偏差方差权衡
GMMn_components(2→5)对数似然、BIC模型选择
K-meansk(2→8)簇内平方和肘部法选 k

扫参数时固定随机种子,否则同一组参数两次跑出不同分数,自检就失去参照。如果时间只够做一件事,优先把混淆矩阵和 AUC 这两类计算题写成脚本——它们手算时最容易因分母写反而整题作废,代码能在几秒内给出对照。把逐折分数和扰动曲线抄到复习笔记的边上,比只记一个平均值更能解释清楚模型稳不稳。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/17 17:36:18

轻量化模型融合:ShuffleNetV2+MobileNetV3实现农业病虫害嵌入式识别

简介&#xff1a;这份PDF聚焦轻量化ShuffleNetV2与MobileNet-V3融合模型&#xff0c;面向农业病虫害识别与嵌入式部署方向的研究者、算法工程师及PyTorch学习者。文档完整覆盖融合模型设计动机、特征融合策略、剪枝量化优化、数据集构建、训练评估以及嵌入式平台部署全流程&…

作者头像 李华
网站建设 2026/9/17 17:34:00

CFRP/钛叠层钻削温度场仿真:显式有限差分与热源模型详解

简介&#xff1a;CFRP/钛叠层钻削温度场仿真与切屑效应解析资料提供了一套以C实现的温度场建模方案&#xff0c;面向机械工程研究人员、制造业从业者及高校师生&#xff0c;旨在通过数值仿真理解钻削过程中钛合金切屑形态对温度分布的影响&#xff0c;解决局部高温导致的刃部烧…

作者头像 李华
网站建设 2026/9/17 17:32:53

LabVIEW CAN UDS诊断入门:TOOMOSS_OpenDev(CAN).vi核心解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/17 17:30:02

PROFINET IRT同步性能不达标?等时模式配置误区与实操排查指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/17 17:29:50

PyCharm安装与使用指南:从环境配置到项目调试全攻略

做Python开发这些年&#xff0c;我自己都数不清打开过多少次PyCharm了。不管是刚入门写爬虫&#xff0c;还是后来做数据分析、维护项目&#xff0c;PyCharm几乎全程都陪着我。身边经常有朋友问&#xff1a;听说Python要先装解释器&#xff0c;还要配个IDE&#xff0c;到底怎么搞…

作者头像 李华