qinghuan
← 机器学习与统计推断 / 全部笔记

单元 11 / 机器学习与统计推断

P1 · 重点提升L1 · 基础

置信区间、Bootstrap 与假设检验

从已有样本中重复抽样,观察估计怎样变化;手写均值 bootstrap,再分清置信区间、p 值、效果大小和同题配对比较。

本篇目录 · 按需要跳转

这篇重点学什么

本篇重点:先说明想研究哪些对象、样本怎样抽取,再区分抽样与重复运行;用 bootstrap 和置信区间描述估计的不确定性,并检查样本是否可视为独立。

开始读正文 ↓
学过相近内容?查看哪些可以跳过

两条路线有些基础相同。已经学会的部分可以跳过,另一条路线只用来补你当前需要的内容。

回归与统计评估

共同基础先约定实验方法,再用独立样本得到可以比较的结果。

另一条路线补充什么?

先列出发布必须通过的检查,校准评分器,再比较新旧版本有没有退步,决定能否发布。

读完这篇,你能做什么

能实现可重复的百分位 bootstrap,说明独立性假设和区间含义,并为模型比较选对需要一起抽样的单位。

学习理由、准备要求与知识点

为什么学它

分数只差一点,可能是抽到的样本不同。先弄清统计推断的条件,才不会把偶然变化当成稳定提升。

先读这些内容

知识点清单

  • 统计量与抽样分布
  • 频率学派置信区间
  • 有放回 bootstrap
  • 百分位插值
  • 配对与分组重采样
  • 原假设与 p 值
  • 效果大小与多重比较
  • 蒙特卡洛误差

运行前先确认Java 17;Python 3.14 标准库 CPU 实验;源码参考 SciPy v1.16.2,不要求安装 SciPy。百分位区间是教学估计,未验证其对任意总体的覆盖率。

01先弄懂它是什么

同一个模型换一批测试题,分数往往会变,所以一次得分也有不确定性。平均误差这类由样本算出的数叫统计量。假想按同样规则从同一总体反复取数据,每次都算一次平均误差,这些结果的波动就是它的抽样分布。手头只有一份数据时,要区分“各道题误差有多大”和“换一套题后平均误差会怎样变”,它们不是同一个分布。

置信区间用一个范围表达估计的不确定性。例如采用覆盖率为百分之九十五的方法,意思是:在相应假设成立时,反复抽样并按同样步骤构造区间,长期约有百分之九十五的区间能包含固定的总体参数。这个说法评价的是构造区间的方法。拿到眼前这个区间后,不能直接改说“参数有百分之九十五的概率在里面”;那类后验概率需要另一套建模方式。

Bootstrap 用经验分布近似未知总体:从当前 n 个观测中有放回抽 n 次,计算一次统计量,重复 B 次。每次抽取后放回,所以同一观测可能重复出现,也可能未被抽到。B 增加主要减小重采样模拟误差,并没有凭空增加原始数据的信息量;错误抽样单位也不会因 B 很大而被修正。

文中这几个词,先认一认

统计量
从一份样本算出来的数,例如这份样本的平均误差。
覆盖率
反复抽样并构造区间时,有多少比例的区间能够包含要估计的固定参数。
百分位区间
先反复重抽样并计算统计量,再取这些结果的两个分位点作为区间左右端点。
p 值
假定原假设和所用模型成立,出现当前这么极端、或更极端的检验统计量的概率。它不是原假设为真的概率。

还有陌生词?到术语小抄里看一个具体例子 ↗

02看看它怎么工作

本篇估计总体均值,使用双侧百分位区间。设置信水平为 c,左尾概率 q=(1-c)/2;把 B 个 bootstrap 均值排序后,取 q 与 1-q 的分位数。代码明确采用位置 q*(B-1) 的线性插值,因此不同软件采用不同分位数约定时,有限 B 的端点可能略有差别。

最简单的逐行 bootstrap,把各行近似看成来自同一种抽样机制、彼此独立的观测,这就是这里需要的独立同分布条件。同一用户的多条记录、相邻时刻的数据可能互相关联,不能自动当成彼此独立的行。

比较两个模型时,还要把同一道题的两个成绩绑在一起:先算这道题上两者的误差差值,再按符合数据结构的单位重抽样。若把两边各自乱抽,同题难度带来的共同影响就被拆散了;需要按用户或其他组一起抽时,也不能只保留题目配对就算完成。

区间跨过零只说明在当前方法与信息下,差异方向还不够明确;它不证明两个模型相等。反过来,区间很窄且排除零,也不自动说明改进对业务有意义。应同时报告原始单位中的效果大小、区间、样本量与抽样设计,让读者判断变化是否超过实际关心的阈值。

p 值不等于原假设为真的概率,也不是效果大小。它依赖检验统计量、原假设、单双侧方向和数据生成假设。若试了很多模型只报告最小 p 值,或者不停看结果一显著就停止,原来的错误率解释可能不再成立;应预先定义比较计划,或使用适合多重比较和序贯分析的方法。

百分位 bootstrap 容易实现,但算出来的区间不一定有预期覆盖率。样本太少、统计量变化不平滑、极端值较多、参数靠近边界,或样本几乎没有变化,都可能造成问题。例如手里的数全是七,怎样重抽都还是七,区间宽度就为零;这只说明现有样本没有变化,不能证明真实总体也没有波动。BCa、学生化区间和参数模型各有条件,也不能不加检查地替换使用。

先跑通一个最小例子

仅需 Python 3.14 标准库。保存为 experiment.py,执行 python experiment.py;固定种子检查可重复性和退化样本,不以这些断言声称已经证明覆盖率。

experiment.py · python
import math,random
def interval(values,seed=2026,B=2000,c=.95):
    if len(values)<2 or B<2 or not 0<c<1 or not all(math.isfinite(x) for x in values):
        raise ValueError("input")
    rng=random.Random(seed)
    means=sorted(math.fsum(rng.choice(values) for _ in values)/len(values) for _ in range(B))
    def quantile(q):
        pos=q*(B-1); lo=math.floor(pos); hi=math.ceil(pos)
        return means[lo]*(hi-pos)+means[hi]*(pos-lo) if lo!=hi else means[lo]
    return quantile((1-c)/2),quantile((1+c)/2)
a=interval([1.,2.,3.,4.])
assert a==interval([1.,2.,3.,4.])  # 同一种子与同一程序版本可重复。
assert a[0]<=a[1]
assert 1<=a[0]<=4 and 1<=a[1]<=4
assert interval([7.,7.,7.])==(7.,7.)  # 零宽度只反映这份经验样本。
assert interval([0.,1.])==(0.,1.)
try:
    interval([1.])
except ValueError:
    rejected=True
else:
    rejected=False
assert rejected
print("PASS 6; percentile interval =",a)

核对运行结果打印 PASS 6 和均值区间;常量样本得到 [7,7],程序不会把它解释为总体完全确定。

正在加载流程图…

重采样重复的是估计程序;增加 B 不会替代增加独立观测。
查看流程图源码(Mermaid)
flowchart LR
 A["明确总体和抽样单位"] --> B["原始 n 个观测"]
 B --> C["有放回抽 n 个"]
 C --> D["计算一次统计量"]
 D --> E["重复 B 次并排序"]
 E --> F["取两端分位点"]
 F --> G["说明假设与效果大小"]

按顺序看,每一步做了什么

  1. 明确目标参数和独立抽样单位。
  2. 固定区间方法、置信水平和种子。
  3. 重复有放回抽样并计算均值。
  4. 排序后按明确插值规则取分位点。
  5. 报告端点、样本规模和失效条件。

03对照实现代码

SciPy v1.16.2:bootstrap 的有放回索引抽样 (新标签页)↗

SciPy v1.16.2;scipy/stats/_resampling.py · _bootstrap_resample

以下为原创精简教学实现,不是原样库源码;只演示本文说明的机制,省略真实实现的优化、调度和完整兼容边界。

核心机制代码 · python
def resample_once(values,rng):
    # 原创列表模型:抽取下标后保留重复观测。
    n=len(values)
    if n==0:
        raise ValueError("empty")
    return [values[rng.randrange(n)] for _ in range(n)]
    # 未实现 SciPy 的多轴向量化、批处理或区间校正。

固定版本的 _bootstrap_resample 从 sample.shape[-1] 取得样本数,生成形状为 (n_resamples,n) 的整数索引,再用 sample[...,i] 收集观测。整数索引可以重复,这正是有放回抽样的机制;它不是打乱后无放回遍历所有观测。

函数本身只负责构造重采样数据,不计算用户统计量,也不决定置信区间端点。统计量求值、分批处理、区间方法与输入检查在外层流程负责;把这个小函数读懂,不等于已经实现完整 bootstrap 接口。

样本轴位于最后一维,其余维度可能携带批次或变量信息。原创模型只支持一维列表,通过逐次选下标表达同一抽样思想,未复制真实多维数组索引规则。配对数据的共享索引必须由上层明确保证,不能指望两次独立随机调用自然保持配对。

SciPy 的完整 bootstrap 支持包括 BCa 在内的多种区间方法,而本篇只实现百分位均值区间。阅读文档时要显式对应 method、paired 和 axis 等设置;库默认值与教学例子的选择不同,不应只比较函数名称就认为计算完全一致。

代码先调用谁,再调用谁

  1. 外层 bootstrap 验证数据与统计量
  2. _bootstrap_resample 生成重复下标
  3. 按下标形成各次样本
  4. 外层计算统计量与区间

04动手写一个例子

可重复的百分位均值 Bootstrap

输入至少两个有限 double 观测、2–10000 次重采样、开区间 (0,1) 内置信水平与随机种子,返回均值百分位区间;本算法不保证任意数据分布的覆盖率。

输入 1
[7,7,7], B=2000, c=.95
输出 1
[7,7]
输入 2
[0,1], B=2000, seed=2026
输出 2
[0,1]

为每次重采样创建一个均值累加器,独立抽 n 个下标。均值按每项先除 n 再相加,减少直接总和溢出的机会,并在结果后检查有限性;它仍然是普通浮点实现,不提供任意极端数据的精确统计。

保存 B 个均值后排序,用端点分位规则进行线性插值。插值使用两个端点的加权和,避免直接相减时扩大范围。输入限制 B 的上界只是教学程序的资源契约,不是统计学要求;真实预算还应考虑 n 与 B 的乘积。

测试既检查普通重复性,也检查常量、二值样本、样本量不足和非法置信水平。固定种子能让同一实现稳定复现,Java 与 Python 使用不同随机数发生器时,不要求区间端点逐位一致。

为什么这样写是对的完成第 b 次循环后,数组前 b 项分别保存一次独立有放回抽 n 个观测得到的均值。

时间 O(B*n+B*log B)。额外空间 O(B) 额外空间。

生成 B 个均值各扫描 n 次,排序 B 个统计量需要 O(B log B),两个分位点插值为常数时间。

保存为 Main.java,运行 javac --release 17 -encoding UTF-8 Main.java,再运行 java Main。程序包含固定输入自测,断言失败时会抛出错误。

展开收起代码 · Main.java · 完整可运行程序Java · 36 行

长行可在代码区域内左右滚动,按 Tab 可把焦点移入代码区。

Main.java · 完整可运行程序 · Java
import java.util.*;
public class Main {
  record Interval(double low,double high){}
  static Interval estimate(double[] x,int count,double c,long seed){
    if(x==null||x.length<2||count<2||count>10000||!Double.isFinite(c)||c<=0||c>=1)throw new IllegalArgumentException("input");
    for(double v:x)if(!Double.isFinite(v))throw new IllegalArgumentException("finite");
    Random rng=new Random(seed);double[] means=new double[count];
    for(int b=0;b<count;b++){
      double mean=0;
      for(int i=0;i<x.length;i++)mean+=x[rng.nextInt(x.length)]/x.length; // 抽完放回,允许重复下标。
      if(!Double.isFinite(mean))throw new ArithmeticException("range");
      means[b]=mean;
    }
    Arrays.sort(means); // 百分位数针对重采样统计量,不是原始观测。
    double q=(1-c)/2;
    return new Interval(quantile(means,q),quantile(means,1-q));
  }
  static double quantile(double[] a,double q){
    double position=q*(a.length-1);int lo=(int)Math.floor(position),hi=(int)Math.ceil(position);
    if(lo==hi)return a[lo];
    double t=position-lo;
    return (1-t)*a[lo]+t*a[hi]; // 明确线性插值约定。
  }
  static void check(boolean ok){if(!ok)throw new AssertionError();}
  static void bad(Runnable r){try{r.run();}catch(IllegalArgumentException e){return;}throw new AssertionError();}
  public static void main(String[] args){
    Interval a=estimate(new double[]{1,2,3,4},2000,.95,2026);
    check(a.equals(estimate(new double[]{1,2,3,4},2000,.95,2026)));
    check(a.low<=a.high&&a.low>=1&&a.high<=4);
    check(estimate(new double[]{7,7,7},2000,.95,2026).equals(new Interval(7,7)));
    check(estimate(new double[]{0,1},2000,.95,2026).equals(new Interval(0,1)));
    bad(()->estimate(new double[]{1},2000,.95,0));
    bad(()->estimate(new double[]{1,2},2000,1,0));
    System.out.println("PASS 6");
  }
}

这些特殊情况也要试一试

  • 退化样本可能产生零宽度区间。
  • 相关数据需要改变抽样单位。
  • B 控制模拟精度,不增加原始信息。
  • 非法样本或置信水平明确拒绝。
进阶选读 · 配对比较与分组重采样

场景两个模型在同一用户群上比较,小样本内还有重复记录。

做法先明确用户级目标和配对差值,再按用户块重采样保留簇内依赖;比较效果区间与业务阈值。

复杂度通常 O(B*N),N 为每次抽样涉及的记录量。

好处与代价独立用户数可能远小于记录数,无法用大量相关行伪装有效样本规模。

05项目里怎么用

模型评估报告应记录样本时间窗、纳入规则、统计单位、指标定义和比较计划。均值区间与尾部风险回答的问题不同:平均响应更快,不代表最慢用户也改善。先选能对应决策的问题,再选推断方法,避免看到数据后不断更换指标直到显著。

重复运行实验时,需要区分数据抽样不确定性、训练随机性和 bootstrap 蒙特卡洛误差。固定模型对测试样本重采样,只估计当前模型在该样本机制下的评估波动,不包含重新训练得到不同模型的变化;要研究训练过程稳定性,还需要相应的重复训练设计。

若数据来自持续变化的在线系统,独立同分布假设可能不合适。应按时间、用户或实验分流单元设计分析,并考虑缺失、干扰和选择偏差。统计显著性是一个证据维度,可靠结论还需要效果大小、可重复性、数据质量和实际成本共同支持。

容易踩的坑

  • 把百分之九十五置信区间解释成固定参数的后验概率。
  • 独立重采样两个模型而破坏样本配对。
  • 用大量重采样次数替代独立观测数量。
  • 反复试验只报告显著结果而忽略多重比较。

几种做法,怎么选

表格有四列,窄屏可左右滑动查看代价和适用条件。

方案优势代价与限制适用条件
百分位 bootstrap实现直观,适合观察抽样波动有限样本覆盖率可能不佳条件合适的平滑统计量
参数区间假设正确时高效易解释依赖分布与模型条件有可信参数模型
配对或分组设计保留比较与依赖结构实现和报告要求更高重复用户与同样本模型比较

06检验是否读懂了

先自己想、自己写,再展开答案核对。场景题是假设的练习情境;遇到还没学过的内容,可以做完基础后再回来。

先用自己的话解释

01p 值小表示原假设概率小吗?

展开参考答案与推导

不是。它是在原假设及其模型条件下,检验统计量至少同样极端的概率;不能倒置条件解释成原假设给定数据的概率。

02为什么 bootstrap 可以抽到重复记录?

展开参考答案与推导

它从经验分布有放回抽样,每次下标选择都允许重复。无放回抽 n 个原记录只改变顺序,对均值不会产生抽样波动。

03增加 B 会消除小样本缺陷吗?

展开参考答案与推导

不会。它减少模拟近似误差,经验分布的信息仍来自同一份有限观测,偏差和错误依赖假设仍可能存在。

换个情况,还会处理吗

01两个模型在相同测试集上差一点,怎样比较?

展开参考答案与推导

保留每个样本的配对误差或指标贡献,在合适的独立单位上分析差值,报告效果和区间;若指标不可逐项分解,可共同重采样后重新计算两模型指标。

02常量样本得到零宽度区间说明什么?

展开参考答案与推导

说明重采样的经验分布退化,而非真实总体参数已完全确定。应检查样本规模和观测机制,并承认该方法无法从样本外推未知变异。

03每天看 p 值,一显著就停止可以吗?

展开参考答案与推导

普通固定样本检验的错误率解释可能失效。应预先固定设计或使用适合序贯观察的方法,并记录查看和停止规则。

写代码试一试

01定位百分位插值位置。

输入 / 条件
B=101,q=.025
输出 / 预期
位置2.5

提示 使用q*(B-1)。

展开参考答案与推导

位于排序后下标二与三之间,各取一半;下标从零开始,不应直接把百分位乘 B 后取整。

02核对区间端点。

输入 / 条件
所有观测都是7
输出 / 预期
[7,7]

提示 每次均值不变。

展开参考答案与推导

任何有放回样本仍由七组成,两个端点相等。代码结果正确不意味着对所有可能总体都具有所声称的覆盖率。

03设计配对重采样。

输入 / 条件
模型A与B各有同一用户的误差
输出 / 预期
共用用户下标

提示 抽单位一次,再同时取两边。

展开参考答案与推导

先抽用户下标,然后用同一索引收集两模型结果;若一个用户有多条数据,应保留其整组记录,以免破坏簇内结构。

读完之后,独立完成

课后作业:自己做一遍

本篇共 9 道作业,先完成 7 道基础与综合任务,再按前置知识挑战进阶题。其中包含 1 道思维拓展,试着换个条件,看看原来的办法是否还管用。不附参考答案。

这次练什么

能实现可重复的百分位 bootstrap,说明独立性假设和区间含义,并为模型比较选对需要一起抽样的单位。

本篇重点加练

区间解释与多次试验后的选择影响结论可信度,重点区分估计精度和决策规则。

  • 频率学派置信区间
  • 效果大小与多重比较

重点内容会多练几次。先说清楚怎么做,再试试空数据、出错或条件改变时会发生什么。

先自己做,卡住时记下问题,再回来查。问答题写清“为什么、什么时候适用”;动手题留下输入、输出和运行步骤,方便下次重做。

基础必做

  1. 作业 01原理问答

    用反复抽取样本的实验语言解释“95% 置信区间”的含义,分别指出对参数、单次区间和新个体可以做何种陈述。

    提交内容
    三个对象的解释表
    怎样算完成
    • 随机对象明确
    • 覆盖率含义一致

    练到的知识点统计量与抽样分布 · 频率学派置信区间

  2. 作业 02代码推演

    样本为 [1,2,2,8,9]。手工列出三次有放回抽样,计算均值,并对自建的十个 bootstrap 统计量求指定百分位数。

    提交内容
    抽样索引及计算记录
    怎样算完成
    • 样本重复合法
    • 插值约定完整

    练到的知识点有放回 bootstrap · 百分位插值

  3. 作业 03原理问答

    同一效果的区间因样本增加而变窄,但研究同时检查了十个终点。写出固定终点与事后选最好终点两种报告应披露的差异。

    提交内容
    两份结果声明与假设表
    怎样算完成
    • 覆盖对象明确
    • 选择过程完整公开

    练到的知识点频率学派置信区间 · 效果大小与多重比较

综合应用

  1. 作业 04编程实践

    生成 24 个任务家族、每族 3 个相关观测,比较逐行和按家族 bootstrap 的区间;固定随机种子并报告两种采样单位。

    提交内容
    CPU 脚本与区间比较
    怎样算完成
    • 成组结构保留
    • 重采样次数与随机误差报告

    练到的知识点有放回 bootstrap · 配对与分组重采样 · 蒙特卡洛误差

  2. 作业 05面试场景

    团队同时尝试 40 个设置,仅展示最小 p 值的那个。给出一份可审计的分析计划,区分探索结论和后续确认性检验。

    提交内容
    检验计划与结果呈现规则
    怎样算完成
    • 选择过程公开
    • 效果大小有独立报告

    练到的知识点原假设与 p 值 · 效果大小与多重比较

  3. 作业 06排错实验

    用已知参数的简单分布重复生成 200 份小样本,估计所选区间方法的覆盖率;改变样本量并保留失败或退化区间。

    提交内容
    覆盖率实验与原始统计
    怎样算完成
    • 真实参数固定
    • 经验覆盖和名义覆盖分开

    练到的知识点频率学派置信区间 · 配对与分组重采样 · 蒙特卡洛误差

  4. 作业 07编程实践

    用 CPU 模拟零效果下十组独立比较,每次只展示最大差异;重复 300 次,比较完整报告与筛选报告的区间覆盖表现。

    提交内容
    模拟代码与覆盖统计
    怎样算完成
    • 真效果和选择规则固定
    • 模拟误差及样本数报告

    练到的知识点频率学派置信区间 · 效果大小与多重比较

进阶挑战 · 掌握前置后选做

  1. 作业 08设计评审

    设计两个模型在共享测试题上的比较协议,测试题又按模板相关;同时考虑任务层不确定性和训练种子层不确定性。

    提交内容
    层级结构图与分析计划
    怎样算完成
    • 各随机来源明确
    • 相关观测不冒充独立样本

    练到的知识点配对与分组重采样 · 原假设与 p 值 · 效果大小与多重比较

思维拓展

先写出你的猜想,再用例子或实验验证。答案可以不同,但要说清依据、适用情况,以及还有什么没弄懂。

  1. 作业 09思维拓展 · 开放探究

    如果研究只有一份很小的样本,增加 bootstrap 次数能否支持任意精确的实际决策?自拟有成本阈值的场景,界定可消除和不可消除的不确定性。

    提交内容
    决策场景及不确定性分解
    怎样算完成
    • 数值采样误差与数据局限分开
    • 结论有明确目标总体

    练到的知识点频率学派置信区间 · 效果大小与多重比较

完成后,再检验一次

给每题标记“独立完成 / 查阅后完成 / 尚未完成”。查过资料或没做出的题,记下卡在哪里。隔一天换一组输入再试,能解释结果和出错原因,再把这个知识点标为掌握。

继续阅读

先看能帮你完成当前练习的部分。例子跑通后,再读更深入的解释。

打开资料库,找下一份学习材料 ↗