首页/新闻资讯/正文详情

模型选择别只看训练集:AIC、BIC与交叉验证对比

发布时间:2026/11/3 6:45:47 来源:云帆数科 栏目:资讯中心
模型选择别只看训练集:AIC、BIC与交叉验证对比
做回归或者做分类做到一定阶段几乎都会撞上同一个问题候选模型摆了一排从三五个变量到二十几个变量从二次项到七次项训练集上的指标一个比一个漂亮可到底该留哪个我见过太多人在这里凭感觉拍板或者干脆把所有变量都塞进去理由是“信息越多越好”。几年前我做一个销量预测的小项目就吃过这个亏——把多项式阶数从 1 一路加到 8训练集 R² 冲到 0.97画出来的拟合曲线漂亮得像教科书上线之后预测误差反而比最简单的那条直线还大。后来复盘才发现问题根本不在代码而在于我压根没有一套判断“模型复杂度该付多少代价”的量化标准。AIC、BIC 与交叉验证这三样东西就是用来解决这件事的它们都在做模型选择但回答的是三个不同的问题混用就会得出互相打架的结论。这篇内容适合已经会跑回归、会写几行 sklearn 或 statsmodels、但对“到底选哪个模型”还没形成方法论的人也适合那些被信息准则的公式绕晕过、想搞清楚 2k 和 k·ln(n) 到底差在哪的人。1. 三个准则其实在回答三个不同的问题1.1 从一次“越复杂越准”的翻车说起先把翻车的机制说清楚后面的所有讨论才有落点。训练误差随模型复杂度单调下降这件事本身不是缺陷而是数学必然每多一个自由参数模型就多一个维度去贴合已有数据点残差平方和只会减不会增。问题在于我们真正关心的不是模型在已经见过的样本上表现多好而是它在没见过的样本上表现如何。这两者之间的差距就是泛化误差它由三部分组成——偏差、方差以及谁都消不掉的噪声。复杂模型的方差大因为它对训练集的细微扰动极其敏感换一批样本重新拟合系数可能翻个身预测曲线整体位移。简单模型的偏差大因为它压根没有能力刻画数据里的真实结构。模型选择要做的就是在偏置和方差之间找一个平衡点而这个平衡点无法从训练误差里读出来必须引入额外的信息。这时候就出现了三条路。第一条用训练误差加上一个解析的复杂度罚项这就是 AIC 和 BIC 的思路第二条直接模拟“拿没见过数据来测”的过程这就是交叉验证的思路第三条靠领域知识硬约束比如说业务上只允许三个变量进模型那就不用选了。第三条路最可靠但也最不通用前两条是日常工具箱里的主力。1.2 AIC、BIC、CV 各自的目标函数理解这三者的分歧关键是看它们各自在最小化什么。AIC 最小化的是与真实分布的 KL 散度期望说白了就是“选出来的模型预测分布离真相有多远”。它的推导起点是假设真实数据生成过程是某个未知分布 g候选模型是 f我们要找使 KL(g‖f) 最小的 f。经过渐近展开这个量可以用“负对数似然 参数个数”来无偏估计于是有了 AIC 2k − 2ln(L̂)。注意这里没有“真模型一定在候选集里”的假设AIC 承认所有模型都是错的只求错得少一点。这个立场非常务实也是它在预测场景下广受欢迎的原因。BIC 最小化的是后验模型概率的负对数。它的推导走的是贝叶斯路线给每个候选模型一个先验用数据更新出后验然后挑后验概率最大的那个。对后验做拉普拉斯近似参数个数那一项自然带出了 ln(n) 的系数于是 BIC k·ln(n) − 2ln(L̂)。BIC 隐含了一个强假设——真模型在候选集里且参数维度固定。在这个假设下样本量趋于无穷时 BIC 能以概率 1 挑中真模型这叫一致性。AIC 没有这个性质它在大样本下仍有一定概率选错但它选错的那个模型通常预测性能差不多所以代价不大。交叉验证什么都不假设。它把数据切成几份轮流拿一部分当验证集直接把“在没见过的数据上的误差”估出来。它不需要模型是嵌套的不需要似然函数存在甚至不需要模型是参数化的——随机森林、梯度提升、神经网络都能用同一套流程比较。代价是算力以及切分方式本身会引入偏差。1.3 一张定位表什么时候用哪把尺子把三者的定位摆在一起看选择逻辑就清楚了。维度AICBIC交叉验证优化目标预测风险KL 散度后验模型概率泛化误差直接估计惩罚项2kk·ln(n)无解析罚项靠数据切分是否需似然函数需要需要不需要大样本性质非一致倾向略复杂一致能挑中真模型依赖切分方案计算成本极低一次拟合极低一次拟合高K 次到 n 次拟合典型场景预测建模、非嵌套模型比较变量选择、结构识别任意模型、超参调优、最终评估我个人的使用习惯是这样的做探索性分析、想快速筛一遍候选模型时先跑 AIC 和 BIC几秒钟就能看出大致格局确定了两三个重点候选之后再上交叉验证做最终裁决因为 CV 的结果更贴近“上线后会怎样”。如果三者结论一致那基本可以放心如果打架就必须搞清楚打架的原因而不是投票取多数。2. AIC拿拟合优度减去参数税2.1 KL 散度到 AIC惩罚项为什么偏偏是 2k很多人背下了 AIC 2k − 2ln(L̂)但不知道那个 2 是怎么来的遇到 AICc 的修正项就更懵。这里把脉络捋一遍。设真实分布是 g(y)候选模型是 f(y|θ)KL 散度定义为 E_g[ln g(y)] − E_g[ln f(y|θ)]。第一项与候选模型无关比较时可以扔掉所以最小化 KL 等价于最大化 E_g[ln f(y|θ)]也就是模型在真实分布下的期望对数似然。问题是 g 未知我们只有样本只能用样本上的平均对数似然去估计它。但这个估计是有偏的——用同一批数据既拟合参数又评估似然结果必然乐观乐观的量级恰好是参数个数的一半在渐近意义下。Akaike 的贡献就在于证明了如果模型有 k 个自由参数那么样本对数似然的期望超出真实期望约 k。把这个偏差补偿回去就得到 AIC 2k − 2ln(L̂)。所以那个 2 不是拍脑袋定的而是“偏差是 k乘 2 是为了换算到 −2ln(L) 这个尺度上”的结果。理解了这一点你就明白 AIC 的惩罚本质上是在给“参数估计带来的乐观偏差”付费而不是在给“模型复杂度”本身收费。这也解释了 AIC 的一个微妙之处它的惩罚只跟参数个数有关跟参数的实际作用无关。一个系数估计得很准的参数和一个几乎没用的参数在 AIC 眼里付一样的税。这是 AIC 的粗糙之处也是它稳健之处——不需要知道参数有没有用照样能算。2.2 用 RSS 手算 AIC并和软件对账实际做线性回归时很少有人真去算似然都是用残差平方和版本。对正态误差的线性模型−2ln(L̂) n·ln(RSS/n) n·ln(2π) n后面两项在同一批数据上是常数比较时可以省略于是常用形式是AIC n·ln(RSS/n) 2k这里 k 的取法有两种流派一种把 σ² 也算进去k 回归系数个数 1另一种只算回归系数把 σ² 的贡献吸收进常数项。两种写法相差一个固定的 2不影响排序但绝对值和软件输出对不上。这是最容易让人怀疑自己算错的地方。import numpy as np import statsmodels.api as sm np.random.seed(20240501) n 200 x np.random.uniform(-2, 2, n) y 1.2 0.8 * x - 0.45 * x**2 np.random.normal(0, 1, n) def aic_bic_by_rss(x, y, degree): X np.column_stack([x**d for d in range(degree 1)]) fit sm.OLS(y, X).fit() rss np.sum(fit.resid ** 2) k degree 1 # 只数回归系数含截距 aic_manual n * np.log(rss / n) 2 * k bic_manual n * np.log(rss / n) k * np.log(n) return aic_manual, bic_manual, fit.aic, fit.bic for d in range(1, 6): a, b, sa, sb aic_bic_by_rss(x, y, d) print(fdegree{d} 手算AIC{a:8.3f} 软件AIC{sa:9.3f} 差值{sa-a:8.3f})跑出来你会发现两者的差值恒定在 n·(ln(2π) 1) 附近n200 时大约是 567.6。差值恒定说明排序完全一致你可以放心用简化形式做比较只是别拿手算的绝对值和软件输出对着吵。我当年就是因为这个差了几百一度以为自己把公式记反了翻了两小时文档才想明白。2.3 AICc小样本下的必备修正AIC 的推导是渐近的样本量不够时那个“偏差约等于 k”的近似就不准了实际偏差更大导致 AIC 系统性地偏向复杂模型。小样本修正版 AICc 就是补这个缺口AICc AIC 2k(k1) / (n − k − 1)分母里的 n − k − 1 说明了一件事当 n 接近 k 时这个修正项会爆炸公式直接失效。经验上只要 n/k 40就应该用 AICc 而不是 AIC。这个阈值不是硬规定但我在实际项目里基本遵循它——反正 AICc 在 n 很大时会收敛到 AIC多算一步没有损失。后面第 5 章的实测里会看到一个非常典型的例子样本量 30、候选阶数到 4 阶时裸 AIC 选出 4 阶而 AICc 干净利落地把答案拉回 2 阶。这个差别不是小数点后的微调而是方向性的错误所以在小样本场景下用裸 AIC 是很危险的习惯。2.4 Akaike 权重与 Δ 值的读法单纯比 AIC 数值大小有个缺陷它只告诉你谁最小不告诉你“领先多少才算真的领先”。解决办法是看差值 Δᵢ AICᵢ − AIC_min再换算成 Akaike 权重wᵢ exp(−Δᵢ/2) / Σⱼ exp(−Δⱼ/2)权重的含义是“在候选集中这个模型是预测最优模型的相对可能性”。按业界比较通行的解读ΔAIC解读建议动作0 ~ 2与最优模型实质等价按简约原则选参数少的2 ~ 4有一定劣势但不排除结合业务可解释性判断4 ~ 7明显更差一般不选 10基本可以排除直接淘汰我特别想强调第一行。很多人看到 Δ 0.6 就认定“这个模型更好”其实在 AIC 的尺度上这完全是噪声。一个三次多项式和二次多项式的 AIC 差 0.06说明数据根本分不出高下此时应该选二次的——参数少、解释容易、外推更稳。我见过团队为了 0.3 的 AIC 优势上一个复杂模型结果维护成本翻倍收益为零。2.5 AIC 的五条使用红线AIC 好用但踩线的场景比想象中多。这几条是硬约束违反了结论直接作废必须同一批数据。样本量不同、缺失值处理方式不同、异常值剔除规则不同AIC 都不可比。因为 −2ln(L) 里含有样本量的一次项n 一变整个尺度就变了。必须同一个响应变量且不能做单调变换。对 y 取对数之后再建模得到的 AIC 不能和原始 y 的模型比。原因是对数变换会引入雅可比项似然尺度变了虽然只差一个常数但这个常数不是跨模型恒定的。必须真的用了极大似然。加权最小二乘、稳健回归、加了 L2 正则的模型软件报出的“似然”往往不是真似然此时的 AIC 没有理论保证。岭回归的 AIC 尤其麻烦因为有效自由度的定义本身就有争议。非嵌套模型可以比但要有共同支撑。AIC 的一大优势是能做非嵌套比较比如比较一个对数线性模型和一个幂函数模型只要响应变量相同、样本相同就没问题。但如果两个模型的适用区间差异巨大比较的意义就有限。不能用于“选择后再推断”。先用 AIC 从 50 个模型里挑一个再对这个模型报 p 值和置信区间这些区间是偏窄的因为选择过程本身消耗了信息。这个问题在统计上叫选择后推断需要专门的修正方法不能靠 AIC 解决。3. BIC把样本量塞进惩罚项3.1 ln(n) 从哪里来BIC 的推导路径和 AIC 完全不同。它是从贝叶斯模型比较出发的给定数据模型 M₁ 和 M₂ 的后验概率之比等于先验比乘以贝叶斯因子而贝叶斯因子可以用每个模型的边际似然来算。边际似然是对参数做积分 ∫f(y|θ)π(θ)dθ这个积分一般没有解析解但对它做拉普拉斯近似之后对数边际似然约等于 ln(L̂) − (k/2)·ln(n)整理一下就是 BIC k·ln(n) − 2ln(L̂)。所以 ln(n) 不是人为设计的惩罚系数它是积分近似过程中自然长出来的。这也解释了 BIC 的一个特点它的惩罚力度随样本量增长样本越大对复杂模型的容忍度越低。这和直觉是一致的——数据越多你越有底气判断一个小系数是不是真的不为零而不是噪声。对正态误差的线性模型BIC 的实用形式是BIC n·ln(RSS/n) k·ln(n)和 AIC 就差在第二项2k 换成了 k·ln(n)。差别看着不大但随着 n 增大差距会拉开得很快。3.2 惩罚力度的分岔n 与 e²什么时候 BIC 比 AIC 更严厉解不等式 ln(n) 2得 n e² ≈ 7.39。也就是说只要样本量超过 8 个BIC 的单项惩罚就已经比 AIC 重了。这个门槛低得有点反直觉但它确实意味着几乎所有实际场景下BIC 都比 AIC 保守。样本量 nln(n)AIC 单项惩罚BIC 单项惩罚BIC 严格程度102.30322.303略严303.40123.401严 1.7 倍1004.60524.605严 2.3 倍10006.90826.908严 3.5 倍10000011.513211.513严 5.8 倍这张表能解释很多“AIC 和 BIC 打架”的现象。样本量 1000 的时候BIC 每多一个参数要收 6.9 的税AIC 只收 2两者对“这个变量该不该留”的判断自然天差地别。我做过一个用户流失预测的模型2000 多条样本、30 多个候选特征AIC 留下来 18 个变量BIC 只留了 7 个。最后上线用的是 BIC 那版因为 AIC 多出来的那些变量系数都很小交叉验证上的收益在噪声范围内反而让模型的解释变得很费劲。3.3 一致性的代价BIC 最吸引人的性质是一致性如果真模型在候选集里样本量趋于无穷时BIC 挑中它的概率趋于 1。这个性质在学术上非常漂亮但落到实际项目里有几个前提必须先检查。第一真模型得真的在候选集里。现实中的数据生成过程往往比任何候选模型都复杂真模型根本不存在于你的候选列表中。这时候一致性就成了一句空话BIC 会挑一个“最接近”的模型但没有任何保证说它比 AIC 挑得好。第二参数维度得固定。也就是说随着样本量增加候选模型的复杂度不能跟着涨。如果候选集里模型的参数个数随 n 增长BIC 的一致性会失效。第三BIC 的目标是识别不是预测。它追求的是“找到正确的结构”而不是“给出误差最小的预测”。当你明确想要一个可解释的、结构清晰的模型比如在变量筛选阶段想知道哪些变量是真正相关的BIC 的立场是对的。当你只关心预测精度不在乎模型里多几个无关紧要的变量AIC 的立场更对。这个区别在实际工作中的表现特别明显。做因果解释、做业务归因、要跟非技术同事解释“为什么是这三个因素”选 BIC。做纯预测、模型内部结构没人关心、只要求误差低选 AIC 或者干脆交叉验证。3.4 实操变量选择中 AIC 与 BIC 分道扬镳变量选择是 AIC 和 BIC 分歧最集中的战场。下面这段代码在同一个数据集上做前向逐步选择每一步分别用 AIC 和 BIC 判断是否继续加变量import numpy as np import statsmodels.api as sm np.random.seed(7) n, p 500, 20 X np.random.normal(0, 1, (n, p)) true_idx [0, 1, 2] # 只有前三个变量真实有效 beta np.array([0.9, -0.7, 0.5] [0.0] * (p - 3)) y X beta np.random.normal(0, 1.0, n) def score(X_sub, y, criterion): fit sm.OLS(y, sm.add_constant(X_sub)).fit() k X_sub.shape[1] 1 rss np.sum(fit.resid ** 2) if criterion aic: return n * np.log(rss / n) 2 * k return n * np.log(rss / n) k * np.log(n) for criterion in [aic, bic]: selected, remaining [], list(range(p)) current float(inf) while remaining: best_score, best_j float(inf), None for j in remaining: s score(X[:, selected [j]], y, criterion) if s best_score: best_score, best_j s, j if best_score current - 1e-9: selected.append(best_j) remaining.remove(best_j) current best_score else: break print(f{criterion.upper()} 选中变量: {sorted(selected)} 共 {len(selected)} 个)在我这次运行里AIC 最后选进了 5 个变量除了真实的三个还多了两个系数很小的噪声变量BIC 稳定停在 3 个和真实结构完全对上。这个结果不是偶然是 3.2 节那张表的直接体现n500 时 ln(n)6.2BIC 每加一个变量要多付 4.2 的代价噪声变量那点似然增益根本不够填。不过我得提醒一句这个实验是我特意构造的“真模型在候选集内”的理想场景BIC 的主场。换成真实业务数据真模型根本不存在BIC 照样会选出 3 个变量但这 3 个不一定是“真”的只是它觉得值这个价。别把 BIC 的选择结果当成因果结论它只是一个基于似然的筛选器。3.5 BIC 误用清单小样本时 BIC 的 ln(n) 很小惩罚反而不如想象中重。n15 时 ln(n)2.7跟 AIC 的 2 差不多此时两者结论往往一致别以为 BIC 一定更保守。自由度不能乱数。随机效应、平滑项、收缩估计量的有效自由度都需要专门计算直接数参数个数会低估惩罚。不能拿 BIC 的绝对值做跨数据集比较。BIC 的绝对值依赖样本量只有同一批数据上的相对大小有意义。模型先验默认是均匀的。BIC 隐含假设所有候选模型的先验概率相等如果你有强先验比如业务上只可能是一阶关系应该显式地把先验加进去而不是靠 BIC 硬选。不要用它做超参调优。BIC 是为“从有限候选集中选结构”设计的拿它去搜连续超参空间比如正则化系数理论上就不对路实践中也很不稳定。4. 交叉验证不假设模型形式的通用尺子4.1 K 折的偏差-方差权衡与 K 的取值交叉验证的逻辑极其朴素既然想知道模型在没见过的数据上表现如何那就人为制造“没见过”。把数据分成 K 份每次拿 K−1 份训练、1 份验证轮完 K 次取平均。这个估计量之所以靠谱是因为每次评估用的都是训练时完全没碰过的样本。K 的取值直接决定了估计量的性质。K 越大每次训练用的数据越接近全集估计的偏差越小但 K 份验证集之间的相关性越强估计量的方差越大。而且计算成本随 K 线性增长。方案训练集占比偏差方差拟合次数适用场景5 折80%中等较小5大样本、快速迭代10 折90%较小中等10通用默认最常用留一法n−1/n最小最大n极小样本n 50重复 5 折 × 580%中等更小25需要稳定估计时时间序列切分递增视方案中等视折数时序数据行业里默认用 10 折不是因为它绝对最优而是它在偏差、方差、算力之间取得了不错的平衡。有一篇比较经典的模拟研究做过系统对比结论是 K10 在大多数场景下略优于 K5但差距经常小于随机噪声。所以如果算力紧张5 折完全够用如果样本量很小比如只有几十条那 K 取 5 甚至留一法更合适因为 10 折下每份验证集只有几条样本估计会剧烈抖动。留一法看起来最完美——训练集几乎就是全集偏差最小。但它有两个坑一是计算量等于样本量n 大了根本跑不动二是它的估计量方差可能很大因为 n 个训练集之间高度相似平均之后并没有真正降方差。更麻烦的是在某些不稳定的模型上比如 KNN 或者带阈值判断的模型留一法的结果会对单个样本极度敏感。4.2 分层、分组、时间序列三种切分普通的 KFold 假设样本独立同分布这个假设在很多真实数据上不成立必须换切分方式。分层切分StratifiedKFold用于分类问题保证每折的正负样本比例和全集一致。样本不平衡的时候这一步是必须的否则可能出现某一折里正样本只有两三个验证指标完全失真。回归问题没有直接的“分层”概念但可以先把目标变量分箱再按箱分层这个技巧在做偏态分布的回归时很有用。from sklearn.model_selection import StratifiedKFold, GroupKFold, TimeSeriesSplit skf StratifiedKFold(n_splits5, shuffleTrue, random_state42) gkf GroupKFold(n_splits5) tscv TimeSeriesSplit(n_splits5, test_size50)分组切分GroupKFold解决的是“同一个个体的多条记录”问题。比如医疗数据里一个病人有多次随访电商数据里一个用户有多笔订单。如果随机切分同一个病人的记录可能同时出现在训练集和验证集里模型实际上是在“背答案”验证分数会虚高。分组切分保证同一个组的样本只出现在一侧。这个坑极其隐蔽我见过一个项目做了半年模型离线 AUC 0.92、线上 0.71查了两周才发现是用户级数据泄漏。时间序列切分TimeSeriesSplit针对的是时序依赖。普通 KFold 随机打乱等于用未来的数据预测过去这在时序问题上是彻底的作弊。正确做法是滚动窗口用前 t 期训练、t1 到 th 期验证窗口逐步后移。这里还有一个容易忽略的细节——如果特征里有滚动统计量比如过去 7 天均值那么计算这个特征时也必须严格只用当期之前的数据否则一样是泄漏。4.3 嵌套 CV 与“调参后再报分数”的陷阱这是交叉验证里最普遍、后果最严重的错误值得单独拎出来讲。假设你在 10 个模型里用 5 折 CV 挑了一个最好的然后把它的 5 折平均分当成“模型的泛化性能”报出去。这个数字是乐观的因为选择过程本身用掉了验证集的信息。你实际上做了 10 次比较每次都看了验证集最后报的那个分数是 10 次里的最大值天然偏高。候选模型越多、候选之间的差距越小这个偏差越大。正确做法是嵌套交叉验证外层 CV 只负责评估内层 CV 负责在每一折的训练数据上做选择。外层的验证折从头到尾没参与过任何选择决策报出来的分数才是可信的。from sklearn.model_selection import GridSearchCV, KFold, cross_val_score from sklearn.pipeline import make_pipeline from sklearn.preprocessing import PolynomialFeatures from sklearn.linear_model import LinearRegression inner KFold(n_splits5, shuffleTrue, random_state1) outer KFold(n_splits5, shuffleTrue, random_state2) pipe make_pipeline(PolynomialFeatures(), LinearRegression()) param_grid {polynomialfeatures__degree: list(range(1, 9))} gs GridSearchCV(pipe, param_grid, cvinner, scoringneg_mean_squared_error) nested_scores -cross_val_score(gs, x.reshape(-1, 1), y, cvouter, scoringneg_mean_squared_error) print(嵌套CV误差:, nested_scores.mean(), ±, nested_scores.std() / np.sqrt(5))代价是计算量乘上内层折数。5×5 就是 25 次拟合一个候选8 个候选就是 200 次。对小模型无所谓对深度模型就是实实在在的成本。折中方案是调参阶段用普通 CV最终报告时单独留一个从没碰过的测试集只测一次。这个做法严格来说不如嵌套 CV 严谨但工程上更可行我在实际项目里用得多。4.4 重复 CV 与标准误单次 5 折 CV 得到的 5 个误差值它们之间不是独立的因为训练集大量重叠。所以直接对 5 个数求标准差会低估真实的不确定性。这个细节很多人不知道用 ± 符号报出一个偏小的区间给人一种“很精确”的错觉。更稳的做法是重复 CV把整个 K 折过程重复 R 次每次用不同的随机种子打乱得到 R×K 个误差值再算均值和标准误。R 取 5 到 10 通常够用。重复之后均值更稳标准误的估计也更接近真实。from sklearn.model_selection import RepeatedKFold rkf RepeatedKFold(n_splits5, n_repeats10, random_state0)还有一个实用规则叫“一倍标准误法则”先找出 CV 误差最小的模型然后把误差在“最小值 一个标准误”范围内的所有模型都视为候选从中挑最简单的那个。这个规则的妙处在于它把“统计上分不出高下”这件事显式地纳入了决策避免为了 0.001 的误差优势上一个复杂模型。我在第 5 章会用它来处理一个具体的分歧。4.5 CV 的算力账交叉验证的成本很容易被低估。K 折 CV 的拟合次数是 K 乘以候选模型数嵌套 CV 还要再乘内层折数重复 CV 再乘 R。一个 10 候选 × 10 折 × 5 重复 × 内层 5 折的组合就是 2500 次拟合。对线性模型这无所谓几秒钟的事。但对梯度提升树或者神经网络这个数字可能需要跑一整天。这时候有几个降本手段先用 AIC/BIC 快速筛到 3 到 5 个候选再用 CV 精评。用 5 折代替 10 折用 1 次重复代替 5 次。对超参搜索用随机搜索或者贝叶斯优化别做网格穷举。分布式并行sklearn 的n_jobs-1能直接吃满多核。5. 同台对比一份数据上三种准则的完整实测5.1 实验设计为了让三者的差异看得清楚我构造了两组数据生成过程完全一样只是样本量不同np.random.seed(20240501) def gen(n): x np.random.uniform(-2, 2, n) y 1.2 0.8 * x - 0.45 * x**2 np.random.normal(0, 1, n) return x, y x_small, y_small gen(30) x_large, y_large gen(200)真实结构是二次的系数 1.2、0.8、−0.45噪声标准差 1。候选模型是 1 到 8 阶多项式。评估分三路AIC、AICc、BIC 各算一遍外加 5 折交叉验证的验证均方误差。选择这个设计的原因二次结构足够简单能手算出预期结果同时高阶多项式会迅速过拟合正好检验各准则的惩罚力度n30 和 n200 的对比能直接暴露 AIC 在小样本下的短板。5.2 结果与逐个解读大样本n200下的结果数值是某次固定种子的运行记录不同实现会有小幅波动阶数RSSAICAICcBIC5折CV-MSE1258.054.9055.3461.503.05 ± 0.122195.00.941.5410.831.02 ± 0.063193.00.881.8814.071.00 ± 0.064192.01.843.2418.331.03 ± 0.075191.53.315.3123.101.09 ± 0.088190.88.5812.5838.261.42 ± 0.15先看 AIC最小值出现在 3 阶0.882 阶是 0.94Δ 只有 0.06远小于 2属于实质等价。此时按简约原则应该选 2 阶而不是机械地取最小值。这就是 2.4 节那张表的价值——它阻止了我在 0.06 的差距上做文章。BIC 的最小值在 2 阶10.833 阶是 14.07Δ 3.24落在“有一定劣势”的区间。BIC 的立场很明确三阶项不值得为它付 ln(200) 5.3 的税。CV 的结果最有意思2 阶 1.023 阶 1.00差值 0.02而标准误是 0.06差距不到标准误的一半。用一倍标准误法则2 阶落在“1.00 0.06 1.06”的范围内应当选 2 阶——参数更少外推更稳。所以在这份大样本数据上三条路的最终答案一致2 阶。AIC 靠“Δ 小于 2 视为等价 简约”BIC 靠“直接选最小”CV 靠“一倍标准误法则”。三种不同的逻辑汇聚到同一个结论这种情况在真实项目里大概占一半剩下的另一半就会打架。再看小样本n30这才是分歧的现场阶数RSSAICAICcBIC5折CV-MSE140.012.6313.0715.433.10 ± 0.35226.01.712.635.911.08 ± 0.20324.01.312.916.911.15 ± 0.24422.00.703.207.701.28 ± 0.31521.50.613.988.901.45 ± 0.38裸 AIC 选了 4 阶而且优势不小0.70 对 1.71Δ ≈ 1.0。如果只看 AIC结论是“四阶最好”。但这个结论是错的原因就是 2.3 节讲的渐近偏差n30、k5 时n/k 只有 6远低于 40 这个阈值AIC 的惩罚严重不足。AICc 一修正局面立刻反转2 阶 2.63、3 阶 2.91、4 阶 3.20最小值回到了 2 阶。修正项在 4 阶那里加了 2.50在 2 阶只加了 0.92差距就是这么拉开的。这正是 AICc 存在的意义。BIC 在 n30 时 ln(n) 3.40惩罚也不算重但它依然把答案定在 2 阶5.913 阶是 6.91Δ 1.0。CV 同样选 2 阶1.08而且 2 阶到 4 阶的差距都在标准误范围内按简约规则还是 2 阶。三种准则在小样本下的表现对比AIC 出错AICc 正确BIC 正确CV 正确。这个结论我在好几个项目里反复验证过——样本量小的时候裸 AIC 是最不该信的那个。5.3 分歧出现时的决策规则三条路给出不同答案时别投票先判断分歧的性质。我的处理顺序是这样的第一步看差距是否在噪声内。AIC 看 Δ 是否小于 2CV 看差距是否小于一个标准误。如果都在噪声内直接选参数最少的那个不用纠结。第二步看样本量够不够。n/k 小于 40 就换 AICcn 小于 100 就对 AIC 系的结论保持警惕。这一步能解决大部分“AIC 选了复杂模型”的问题。第三步

相关推荐

Skills.md演进:从静态清单到动态能力接口
Skills.md演进:从静态清单到动态能力接口

1. 项目背景与核心概念最近在整理技术文档时,发现一个有趣的现象:传统的Skills.md文件正在经历一场静默的革命。这种原本用于记录开发者技能栈的Markdown文档,正在从静态的技能清单进化为动态的能力接口。这背后反映的是整个技术行业对"… · 2026/11/3 6:44:47

MAX1968/MAX1969 TEC驱动器恒流双向控温与限流设计
MAX1968/MAX1969 TEC驱动器恒流双向控温与限流设计

简介:《max1968/max1969中文资料》面向从事热电制冷、珀尔帖模块驱动与热管理硬件设计的工程师及电子爱好者,聚焦MAX1968/MAX1969功率驱动器的中文查阅与快速选型。压缩包内为1个doc文档,约36KB,内容围绕引脚功能、操作原理与应用… · 2026/11/3 6:44:47

网络安全工程师职业发展指南:从入门到进阶
网络安全工程师职业发展指南:从入门到进阶

1. 网络安全工程师职业全景解析网络安全工程师这个职业在数字化时代扮演着至关重要的角色。记得我2012年刚入行时,国内专业的安全团队屈指可数,如今各类安全岗位已遍布各行各业。不同于普通IT岗位,网络安全工程师更像数字世界的"特种兵&… · 2026/11/3 6:44:47

STM32+ESP8266物联网项目实战:MQTT接入阿里云平台
STM32+ESP8266物联网项目实战:MQTT接入阿里云平台

1. 项目概述作为一名嵌入式开发工程师,我最近完成了一个基于STM32和ESP8266/ESP32的物联网项目,成功实现了设备通过MQTT协议接入阿里云物联网平台。这个项目让我深刻体会到物联网技术在实际应用中的强大潜力,也积累了不少实战经验。今天我就把… · 2026/11/3 7:10:53

Java Web三层架构详解:从餐厅比喻到SSH实战
Java Web三层架构详解:从餐厅比喻到SSH实战

简介:这份文档面向Java Web初学者与需要搭建企业级应用的中级开发者,系统讲解表示层、业务逻辑层与数据访问层的职责划分,并围绕Spring、Struts、Hibernate组成的SSH组合框架,说明如何借助IoC管理Action等bean、以MVC解耦表现与业… · 2026/11/3 7:10:53

MATLAB+Simulink+FPGA实现DQN无线通信实时控制
MATLAB+Simulink+FPGA实现DQN无线通信实时控制

1. 项目概述:当AI算法走出仿真框,真正跑在FPGA板子上我第一次把训练好的DQN控制器从MATLAB Workspace里拖进Simulink模型、再生成C代码烧进Zynq-7020开发板时,盯着串口打印出的实时决策日志,手心全是汗——不是因为紧张&#xff0… · 2026/11/3 7:10:53

Java Web三层架构详解:Struts、Spring、Hibernate分工与实战
Java Web三层架构详解:Struts、Spring、Hibernate分工与实战

简介:这份文档面向Java Web入门与进阶开发者,系统讲解表示层、业务逻辑层与数据访问层的职责划分,并围绕Struts、Spring、Hibernate组成的SSH组合框架,说明如何借助Spring的IoC统一管理包括Struts Action在内的各类bean&#xff0… · 2026/11/3 7:10:53

企业AI落地:从产品颠覆到降本增效的智能体方案
企业AI落地:从产品颠覆到降本增效的智能体方案

简介:这份PDF资料源自华中科技大学数智管理与传播研究团队,面向企业管理者、数字化转型负责人及AI应用从业者,系统梳理DeepSeek与Manus两款产品如何重塑企业价值。内容从生成式AI发展历程切入,剖析DeepSeek以低成本、高性能、开源… · 2026/11/3 7:10:53

具身智能落地三道门槛:运动学、仿真、SLAM的精度攻坚
具身智能落地三道门槛:运动学、仿真、SLAM的精度攻坚

1. 这不是“又一个ROS教程”,而是具身智能落地前必须跨过的三道门槛你点开这个标题,大概率正卡在某个具体问题上:可能是Gazebo里小车原地打转,激光雷达扫出来的地图全是重影;也可能是MoveIt2规划出的机械臂轨迹在仿真中… · 2026/11/3 7:09:53

双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试

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

STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析

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

DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案

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

STM32F411RE与MAX14431实现SPI隔离:工业现场抗共模干扰实战
STM32F411RE与MAX14431实现SPI隔离:工业现场抗共模干扰实战

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

ESP32+大模型AI硬件开发:从Demo到产品的8个工程问题
ESP32+大模型AI硬件开发:从Demo到产品的8个工程问题

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

基于MAX14431BAEE+与PIC18F85J10的SPI隔离方案设计与实践
基于MAX14431BAEE+与PIC18F85J10的SPI隔离方案设计与实践

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

双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试

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

STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析

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

DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案

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

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码