简介:这份数理统计课程大作业以鸢尾花数据集为分析对象,面向正在学习多元统计、模式识别或准备课程报告的高校学生,围绕花萼与花瓣四项属性完成分类、聚类与降维的完整实践。文档系统梳理马氏距离、高斯混合模型、主成分分析、线性判别分析及刀切法的原理,并给出数据预处理、算法比对与结果讨论,其中重点展示PCA与LDA降维后在极大似然估计下拟合混合高斯模型、再用留一法评估降维程度与模型差异的思路。资源包仅含1个docx文件,大小约511KB,结构包含摘要、引言、符号说明、算法原理、数据处理分析和结论等章节,便于按目录查阅与引用。目前已有1429人学习,适合作为课程作业参考、统计方法复习或机器学习入门的案例材料。
1. 从一份"看起来很水"的数据集作业说起
数理统计大作业挑鸢尾花数据集,十个里有八个觉得这题被做烂了:150 行、4 列、3 个类别,随便调个库就能出结果。真动手才发现难点根本不在分类准确率,而在于怎么把马氏距离、混合高斯模型、主成分分析、线性判别分析、刀切法这五个知识点串成一条自洽的链路——降维降几维、GMM 用几个成分、刀切法怎么比对两种降维方法的差异,每一步都要有理由。这套方案就是围绕这条链路展开的:从 4 维原始特征出发,用 PCA 和 LDA 分别降到低维空间,用高斯混合模型在极大似然意义下拟合分布,用马氏距离判类,最后用留一法给出可信的错误率对比。适合正在写数理统计大作业、统计学习课程设计的人直接照着改。
2. 数据与符号:150 个样本、4 个属性、3 个类别的落表方式
鸢尾花数据集的结构已经被反复讲过,但真到写报告那一章,多数人卡在"符号怎么定义、表怎么列、预处理做到哪一步算够"。这一章把这个地基打牢,后面三章的推导和代码都建立在这套符号上。
2.1 数据集结构与符号约定
数据集包含 150 个观测样本,分属 3 个类别,每类 50 个,每个样本有 4 个数值型属性,单位统一为厘米。原始数据在公开的机器学习数据仓库里可以拿到,字段顺序常见的是花萼长度、花萼宽度、花瓣长度、花瓣宽度,但不同来源的列顺序并不一致,导入后第一件事是对着前几行核对列名,别默认列序。
符号体系建议在报告开头一次性定死,后面全部沿用,否则写到第四章会出现同一个量两个名字的尴尬。我一般用下面这张表:
| 符号 | 含义 | 说明 |
|---|---|---|
| n | 样本个数 | 取 150 |
| x₁ | 花萼长度 | 连续型,单位 cm |
| x₂ | 花萼宽度 | 连续型,单位 cm |
| x₃ | 花瓣长度 | 连续型,单位 cm |
| x₄ | 花瓣宽度 | 连续型,单位 cm |
| y | 类别标签 | 0 / 1 / 2,仅作标识 |
| D | 样本矩阵 | n × 4 |
| μ | 均值向量 | 4 维 |
| Σ | 协方差矩阵 | 4 × 4 |
| R | 相关矩阵 | 4 × 4,标准化后等价于协方差阵 |
| u | 线性变换方向 | 4 × 1 或 4 × k |
| K | 高斯成分个数 | 每类内独立设定 |
标签编码有一个容易忽略的点:0、1、2 只是类别代号,不构成大小关系。后面所有涉及标签的运算只有"同类/异类"判断,绝不能把标签当数值参与回归或者求均值,否则会在 LDA 的类间散度计算里引入完全不存在的序关系。
四个属性的取值范围差异不小。花瓣长度大致落在 1 到 7 厘米,花瓣宽度只有 0.1 到 2.5 厘米,花萼宽度的波动更窄。这种量级差异对欧氏距离和基于协方差矩阵的 PCA 都是干扰项,后面会专门处理。
2.2 数据清洗与标准化:为什么先换成相关矩阵
先做三件最基础的检查:缺失值、重复行、类别计数。这组数据通常是干净的,150 行无缺失,但重复行值得看一眼——如果发现有两条四个属性完全相同的记录却标了不同类别,那就是天然的噪声样本,留一法里必然被判错一次,报告里要能解释。类别计数确认 50/50/50,后面按类分层抽样才有依据。
真正需要设计的是标准化策略。PCA 的目标是找方差最大的方向,如果直接对原始协方差矩阵做特征分解,方差绝对值最大的花瓣长度会独占第一主成分,另外三个属性几乎没有话语权,降维结果就变成了"只看花瓣长度"。消除这种影响的常规做法是对每个属性做 z 分数标准化,等价地,用相关矩阵 R 代替协方差矩阵 Σ 做特征分解:
import numpy as np def corr_matrix(X): """按列标准化后求相关矩阵,等价于对 X 做 z-score 再求协方差""" mu = X.mean(axis=0) sd = X.std(axis=0, ddof=1) # 样本标准差用 n-1 Z = (X - mu) / sd # 每列均值 0、方差 1 R = np.corrcoef(Z, rowvar=False) # 4 x 4 相关矩阵 return mu, sd, Rddof=1是无偏估计的常规选择,样本量 150 时和ddof=0差别很小,但报告里写清楚更稳妥。rowvar=False表示每一列是一个变量,这一行写错会让相关矩阵变成 150 × 150,后面特征分解直接炸掉,是新手最常见的翻车点之一。
标准化之后还有一个判断要做:四个属性之间到底存不存在值得降维的相关性。把 R 打印出来看非对角元素,如果花瓣长度和花瓣宽度的相关系数在 0.9 附近,花萼长度和花瓣长度也在 0.8 以上,说明信息确实重叠,PCA 有存在价值;如果全是 0.1 以下,那降维就是纯粹丢信息,这时候应该老实报告"该数据在相关意义下近似正交",而不是硬降。这组数据的实际相关结构属于前者,花瓣两个属性高度相关,这也是二维降维后仍能保留大部分信息的原因。
2.3 训练/验证的划分方式与样本组织
这份作业的评估方式不能用简单的训练集/测试集对半切。样本只有 150 条,切一半出去,每类只剩 25 条训练样本,GMM 的协方差矩阵在 2 维空间还算稳,4 维空间下每类 25 条估计 4 × 4 协方差阵就有点勉强,误差估计的抖动会非常大。
刀切法(留一法)在这里是更合适的选择:每次留出 1 条做测试,其余 149 条训练,重复 150 次。好处是几乎用上了全部数据,偏差小;代价是要训练 150 次模型,PCA、LDA、GMM 各跑一遍,Python 里循环 150 次完全在可接受范围内,单次实验通常几十秒到几分钟。如果打算做多组参数对比(比如 PCA 降到 1、2、3 维,LDA 降到 1、2 维),总训练次数会乘上组数,这时候建议把降维部分预先算好——PCA 和 LDA 的变换方向只依赖训练集,但严格来说每次留一都要重新拟合,偷懒复用会引入轻微的信息泄漏,报告里要如实说明是哪种做法。
样本组织上还有个细节:留一法循环里要保证每类的样本都被均匀留出。直接按行号 0 到 149 顺序循环是没问题的,因为原始数据通常是按类别排好序的,前 50 条全是第一类。如果做过 shuffle,记得固定随机种子,让结果可复现。
3. 算法原理与选型:五个模块各自解决什么问题
五个算法不是并列关系,而是一条流水线上的五个工位:两个降维工位(PCA、LDA)、一个建模工位(GMM)、一个判类工位(马氏距离)、一个质检工位(刀切法)。搞清楚每个工位的输入输出,报告的逻辑链条才不会散。
3.1 马氏距离:把协方差结构带进"距离"里
欧氏距离的问题在于它假设各维度独立且等方差,四个属性量纲虽然都是厘米,但方差差了一个量级,直接用欧氏距离等于默认花瓣宽度的 1 厘米和花瓣长度的 1 厘米等价,显然不合理。马氏距离的定义是:
d²(x, μ) = (x − μ)ᵀ Σ⁻¹ (x − μ)
其中 μ 是均值向量,Σ 是协方差矩阵。三个性质值得在报告里点出来:当 Σ 取单位阵时退化为欧氏距离;它等价于先做标准化再做欧氏距离;它是无量纲的,不受量纲变化影响。第三点在跨数据集比较时特别有用。
实际计算里 Σ 可能接近奇异,尤其是在留一法某次训练中某类样本数偏少、或者降维后的维度接近样本数时。稳妥写法是用伪逆np.linalg.pinv或者给对角线加一个极小的正则项(如 1e-6),避免求逆时报错或者数值爆炸。这一步不做,程序会在某次留一循环里突然抛LinAlgError,排查起来很费时间。
在这套方案里,马氏距离承担的是判类职责:GMM 拟合完之后,每个高斯成分有自己的一组 (μₖ, Σₖ),新样本对每个成分算一次马氏距离,取距离最小的成分所属类别作为预测结果。这个做法在高斯假设成立、各类先验相近时,和最大后验判别是等价的。
3.2 混合高斯模型:用 EM 求极大似然
单个高斯分布只能描述一个"钟形"的簇,而一个类别内部的样本分布未必这么规整。高斯混合模型把若干个高斯成分按权重加起来:
p(x) = Σₖ πₖ · N(x | μₖ, Σₖ)
其中 πₖ 是混合权重,满足求和为 1。对 n 个样本写对数似然,直接对 π、μ、Σ 求导会得到一组互相耦合的方程,没有闭式解,所以走 EM 迭代:E 步用当前参数算每个样本属于每个成分的后验概率(责任度),M 步用责任度加权更新 π、μ、Σ,交替直到对数似然增量小于阈值。
有几个设计决策要在报告里交代清楚。第一是成分数 K 怎么定:每类内部用一个成分(K=1,退化为单高斯)是最简方案,也可以用 BIC 在 K=1 到 3 之间选,BIC 会惩罚参数过多。第二是协方差类型:full 最灵活但参数最多(d 维下 d(d+1)/2 个),diag 只估方差不管相关性,tied 让所有成分共享一个协方差阵。这组数据每类 50 个样本,2 维下 full 只有 5 个参数,完全撑得住;4 维下 10 个参数也还行,但留一法里每类只剩 49 条,稳定性要盯一下。第三是初始化:EM 对初值敏感,常规做法是用 k-means 先粗分一次拿均值,或者跑 10 次不同随机初值取对数似然最大的那组,后者贵但省心。
3.3 主成分分析:无监督降维的上限在哪
PCA 的思路是把 p 个相关变量线性变换成 p 个互不相关的新变量,新变量的方差依次递减。方差大意味着信息量大,所以保留前 k 个就完成了降维。数学上,变换方向就是相关矩阵(或协方差矩阵)的前 k 个最大特征值对应的单位特征向量。
维数怎么选,看累积贡献率:把特征值归一化后累加,通常取到 85% 或 90% 就够。这组数据前两个主成分的累积贡献率一般在 95% 以上,所以降到 2 维是很自然的选择,降到 1 维会损失较多信息,降到 3 维则收益很小、降维的意义被削弱。
PCA 的局限必须点明:它完全无视标签,找的是"数据整体最分散的方向",而这个方向未必是"最能把三个类别分开的方向"。极端情况下,方差最大的方向恰好是类内波动最大的方向,降维之后三类样本反而糊在一起。这不是实现 bug,是方法本身的属性,也是后面引入 LDA 的直接动机。
3.4 线性判别分析:用上标签后的降维差异
LDA 的目标和 PCA 相反:不是让总体方差最大,而是让投影之后同类样本尽量聚拢、异类样本尽量远离。定义类内散度矩阵 S_w 和类间散度矩阵 S_b,投影方向 u 的目标函数是
J(u) = uᵀ S_b u / uᵀ S_w u
最大化这个比值,解归到广义特征值问题 S_w⁻¹ S_b u = λu,取最大若干特征值对应的特征向量组成变换矩阵。因为 S_b 的秩最多是 c − 1(c 为类别数),LDA 最多只能给出 c − 1 个有效判别方向,3 类数据最多降到 2 维——这个硬上限是 PCA 没有的,报告里要专门说明,否则读者会问"为什么 LDA 不降到 3 维"。
S_w 在样本数少于维度时容易奇异,伪逆是常规兜底。另外 LDA 是监督方法,留一法循环里每次只能用 149 条训练样本的标签重新拟合变换矩阵,如果把全量数据的标签信息带进降维步骤,错误率会被系统性地低估,这是整个方案里最隐蔽的一处泄漏。
3.5 刀切法:留一法怎么给出可信的错误率
刀切法的步骤可以拆成五步:从某一类的 n₁ 个训练样本中剔除一个,用剩余样本建立判别规则;用这个规则判别被剔除的那个样本;重复直到该类每个样本都被判别过一次,记判错数 k₁;对每个类别重复上述过程,得到 kᵢ;最后算总判错率。
它比回报法(用训练集自己测自己)靠谱得多,回报法在样本少的时候会给出虚高的准确率;也比留出法稳定,因为没有随机切分带来的方差。代价是训练次数等于样本数,计算量线性增长。150 条样本、单次训练几十毫秒的量级,总耗时完全可控。
真正需要注意的是错误率估计本身的方差。150 个样本,判错 3 个是 2%,判错 4 个是 2.67%,两个方法差 1 个样本就会让排名翻转。所以报告里不能只写"LDA 比 PCA 好",要写清楚差了几个样本、这个差异在 150 的样本量下是否站得住。保守的做法是除了错误率再报一个混淆矩阵,看错分集中在哪两类之间——这组数据里第一类通常完全可分,错分基本都发生在后两类的交界带。
4. 代码实现:PCA/LDA 类、GMM 的 EM 与刀切法主循环
算法原理写清楚之后,实现部分的核心是把每个模块封装成职责单一的类或函数,让刀切法主循环只负责调度,不掺和具体计算。这样调试时能单独验证每个环节,报告里的 UML 图也有实际内容可画。
4.1 PCA 类:fit 与 transform 的职责边界
PCA 用类实现,fit只学参数(均值、标准差、投影矩阵),transform只做映射。这个边界划清楚,留一法循环里才不会写错:
import numpy as np class PCA: def __init__(self, n_components=2): self.n_components = n_components def fit(self, X): # 1) 记录训练集均值与标准差,供 transform 复用 self.mu_ = X.mean(axis=0) self.sd_ = X.std(axis=0, ddof=1) Z = (X - self.mu_) / self.sd_ # 标准化,消除量纲 # 2) 相关矩阵做特征分解(对称矩阵用 eigh,结果按升序) R = np.corrcoef(Z, rowvar=False) eigval, eigvec = np.linalg.eigh(R) order = np.argsort(eigval)[::-1] # 改成降序 self.eigval_ = eigval[order] self.eigvec_ = eigvec[:, order] # 3) 取前 k 个方向,记录累积贡献率 self.components_ = self.eigvec_[:, :self.n_components] self.explained_ratio_ = self.eigval_ / self.eigval_.sum() return self def transform(self, X): # 必须用训练集的 mu_ 和 sd_,不能用测试集自己的统计量 Z = (X - self.mu_) / self.sd_ return Z @ self.components_三个参数的含义:n_components是保留的主成分个数,做降维程度对比时依次取 1、2、3;explained_ratio_是各主成分的方差贡献率,报告里那张"降维到 k 维保留多少信息"的表直接从这取;components_是 4 × k 的投影矩阵,每一列是一个方向。
transform里用训练集的mu_和sd_是关键。如果偷懒用X自己的均值方差,训练集和测试集的标准化基准就不一致,留一法每一折都引入一次系统性偏差,最后错误率会莫名其妙地好看。这个坑我在第一次写的时候踩过,当时怎么调参都解释不了为什么测试准确率比训练准确率还高。
4.2 LDA 类:广义特征值问题的数值稳定写法
LDA 的实现在散度矩阵累加和广义特征值求解两步:
class LDA: def __init__(self, n_components=2): self.n_components = n_components def fit(self, X, y): d = X.shape[1] classes = np.unique(y) mu_all = X.mean(axis=0) S_w = np.zeros((d, d)) S_b = np.zeros((d, d)) for c in classes: Xc = X[y == c] mu_c = Xc.mean(axis=0) diff = Xc - mu_c S_w += diff.T @ diff # 类内散度 m = (mu_c - mu_all).reshape(-1, 1) S_b += len(Xc) * (m @ m.T) # 类间散度,按类样本数加权 # 广义特征值问题:pinv(S_w) @ S_b 的特征分解 A = np.linalg.pinv(S_w) @ S_b eigval, eigvec = np.linalg.eig(A) order = np.argsort(eigval.real)[::-1] # 有效方向数上限为 类别数 - 1 k = min(self.n_components, len(classes) - 1) self.components_ = eigvec[:, order][:, :k].real return self def transform(self, X): return X @ self.components_np.linalg.eig处理的是非对称矩阵,返回值可能是复数,取.real是必要的,否则后面算距离会报类型错误。pinv代替inv是为了应对 S_w 奇异,3 类数据在 2 维空间下 S_w 通常是满秩的,但留一法某次训练里如果某类样本数掉到 2 条以下,秩就掉了,稳一点没坏处。
len(classes) - 1这个截断不能省。如果不截断直接取前n_components个特征向量,当n_components=3时第三个方向的对应特征值接近 0,投影结果是纯噪声,还会让后续 GMM 的协方差估计出现数值问题。
4.3 GMM:E 步、M 步与参数初始化
GMM 的核心是两个函数交替调用。为了代码短一些,这里给 E 步和 M 步的骨架,高斯密度用 SciPy 的实现:
from scipy.stats import multivariate_normal def e_step(X, weights, means, covs): n, k = X.shape[0], len(weights) resp = np.zeros((n, k)) for j in range(k): # 每个成分的加权密度 resp[:, j] = weights[j] * multivariate_normal.pdf( X, mean=means[j], cov=covs[j], allow_singular=True) resp /= resp.sum(axis=1, keepdims=True) # 归一化成责任度 return resp def m_step(X, resp): n, k = resp.shape nk = resp.sum(axis=0) # 各成分的有效样本数 weights = nk / n means = (resp.T @ X) / nk[:, None] covs = [] for j in range(k): diff = X - means[j] covs.append((resp[:, j][:, None] * diff).T @ diff / nk[j]) return weights, means, covsallow_singular=True是给留一法兜底的,某次训练里成分的有效样本数nk[j]可能极小,协方差阵接近奇异,不加这个参数会直接抛异常。代价是密度值可能异常大,所以初始化阶段要尽量避免产生"空成分"——用 k-means 初始化均值,再把权重平均分,比纯随机初始化稳得多。
收敛判据用对数似然增量,阈值设 1e-6 就够,通常 20 到 50 轮内收敛。迭代次数上限设 200 轮,防止数值问题导致死循环。
每个类别单独拟合一个 GMM,预测时对测试样本算它到每个成分的马氏距离,取最小者所属类别。如果每类只用一个成分(K=1),那就退化成"最近高斯中心 + 协方差加权",实现更简单,报告里也能和 K>1 的结果做个对比。
4.4 刀切法主循环:把降维与分类串起来
主循环负责调度,把降维、拟合、预测三步串起来,并且统计每类的判错数:
def loo_evaluate(X, y, reducer_cls, reducer_kwargs, gmm_k=1): n = len(y) wrong = 0 conf = np.zeros((3, 3), dtype=int) # 混淆矩阵 for i in range(n): idx = np.arange(n) != i X_tr, y_tr = X[idx], y[idx] X_te = X[i:i+1] # 1) 只用训练折拟合降维器,避免标签泄漏 reducer = reducer_cls(**reducer_kwargs).fit(X_tr, y_tr) \ if reducer_cls is LDA else reducer_cls(**reducer_kwargs).fit(X_tr) Z_tr, Z_te = reducer.transform(X_tr), reducer.transform(X_te) # 2) 每类单独建 GMM,返回该类的成分参数列表 models = {c: fit_gmm(Z_tr[y_tr == c], gmm_k) for c in np.unique(y_tr)} # 3) 马氏距离判类 pred = predict_by_mahalanobis(Z_te[0], models) conf[y[i], pred] += 1 wrong += int(pred != y[i]) return 1 - wrong / n, confreducer_cls is LDA那个三元表达式是为了兼容两种fit签名,实际写的时候拆成两个函数更清楚。核心约束只有一条:fit只看训练折,transform才能碰测试样本。混淆矩阵conf的行是真实类别、列是预测类别,答辩时这张表比一个准确率数字有说服力得多——它能直接告诉你错分发生在哪两类之间。
跑对比实验时,把reducer_cls换成 PCA 或 LDA,reducer_kwargs里的n_components依次取 1、2、3(LDA 会自动截断到 2),gmm_k取 1 和 2,就能得到一张完整的对比矩阵。每组配置跑 150 次留一,一共十几组,总耗时通常在几分钟量级。
5. 避坑与排查:五个最容易翻车的细节
这套流程跑通不难,跑出可信的结果难。下面五条是我在复现和改这份作业时踩过或者见别人踩过的,按"现象 → 原因 → 解决"写,对照着自查能省不少时间。
5.1 降维环节的三个翻车点
降维用了全量数据,错误率虚低。现象是留一法跑出来的准确率比预期高出一大截,比如 98% 以上,换个随机种子结果也没变化。原因是 PCA 或 LDA 的变换矩阵在循环外一次性拟合了全部 150 条样本,测试样本的标签信息已经提前渗进降维方向,等于开卷考试。解决方式是把fit挪进循环体,每折重新拟合;如果为了提速确实要预计算,报告里必须明确写"降维方向在全体样本上估计,存在轻微信息泄漏",别装作没这回事。
PCA 用了协方差矩阵而不是相关矩阵。现象是第一主成分的载荷几乎全部集中在花瓣长度上,降维之后另外三个属性形同虚设。原因是四个属性方差差异大,未标准化时方差绝对值主导了特征分解。解决办法是先 z-score 标准化再求协方差,或者直接用相关矩阵——两者在数学上等价,代码里选一种写清楚即可。
LDA 降维维数超过类别数减一。现象是n_components=3时程序不报错,但第三个方向投影出来的数值极小,GMM 拟合时协方差阵接近奇异,偶尔抛LinAlgError。原因是 S_b 的秩最多为 c − 1 = 2。解决办法是在fit里显式截断k = min(n_components, len(classes) - 1),并在报告里说明这个理论上限,这本身就是个能加分的知识点。
5.2 模型与评估环节的两个翻车点
EM 初始化不当,结果每次跑都不一样。现象是同样的数据、同样的 K,两次运行的对数似然差一大截,错误率上下浮动好几个百分点。原因是随机初始化落到了局部极值,或者某个成分一开始就没有样本认领,变成了空成分。解决办法是用 k-means 的聚类中心初始化均值、权重设为均分,或者跑 10 次随机初值取对数似然最大的那组,把随机种子固定下来写进代码。
只报准确率,不看混淆矩阵。现象是报告里写"某方法准确率 96%",答辩时被问"错的那 6 个样本错在哪"就答不上来。原因是单一指标掩盖了错误分布,而这组数据的三类难度差异极大——第一类几乎线性可分,后两类在边界上有重叠。解决办法是把混淆矩阵一并输出,指出错分集中在哪两类之间,再解释这是因为这两个类别的花瓣尺寸分布本身就存在交叠,属于数据固有难度而非方法失效。这一句话往往比多跑十组实验更能体现你理解了这个模型。
6. 验收与答辩:用一张比对表证明方法差异是真的
这套作业最后要交的不是代码,是一个能自圆其说的结论。验收的核心动作只有一件:把所有配置的结果压到一张表里,让差异自己说话。
我一般会做这样一张对比表,行是降维方法加维数,列是 GMM 成分数和两个指标:
| 降维方法 | 维数 | 成分数 K | 留一错误率 | 主要错分区间 |
|---|---|---|---|---|
| 不降维 | 4 | 1 | 待测 | 后两类 |
| PCA | 1 | 1 | 待测 | 后两类明显增多 |
| PCA | 2 | 1 | 待测 | 后两类 |
| PCA | 2 | 2 | 待测 | 后两类 |
| PCA | 3 | 1 | 待测 | 后两类 |
| LDA | 1 | 1 | 待测 | 后两类 |
| LDA | 2 | 1 | 待测 | 后两类 |
| LDA | 2 | 2 | 待测 | 后两类 |
表里的"待测"要你自己跑出来填,我不给具体数字,因为随机种子、初始化方式、是否分层都会影响小数点后那一位。填完之后按三条线读:第一,LDA 在同等维数下通常优于 PCA,原因是它用上了标签信息,这正是理论预期,如果实测反了,先查泄漏和实现 bug,别急着写"与理论不符";第二,维数从 1 涨到 2 收益明显,从 2 涨到 3 收益很小,说明二维已经抓住了主要判别信息;第三,K 从 1 涨到 2 未必带来提升,样本量小时参数增多反而过拟合,这个结论本身就可以写进报告。
答辩被问到的概率最高的三个问题,提前准备好答案。一是"为什么 LDA 最多降到 2 维",答 S_b 的秩上限是 c − 1。二是"刀切法和交叉验证有什么区别",答留一法是 k 折交叉验证在 k = n 时的特例,偏差最小但方差较大,样本量小时更适用。三是"错误率差一个样本算不算有差异",这个问题最考验功底,老实回答"150 个样本下 2% 和 2.67% 的差距只有 1 个样本,不足以支撑强结论,只能说方向一致"比硬吹方法优劣得分更高。
有个习惯我从做这份作业之后一直保留:任何涉及"方法 A 比方法 B 好"的结论,都要先跑三遍不同随机种子,看排名稳不稳,再决定这句话能不能写进报告。数理统计这门课考的从来不是调包能力,是你能不能在噪声里区分出信号。这套鸢尾花分析方案的完整推导、代码和对比表我整理成了一份文档,需要照着改的话可以直接拿去对照。希望帮到你。
本文还有配套的精品资源,点击获取