这篇重点学什么
本篇重点:先说明想研究哪些对象、样本怎样抽取,再区分抽样与重复运行;用 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;固定种子检查可重复性和退化样本,不以这些断言声称已经证明覆盖率。
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],程序不会把它解释为总体完全确定。
正在加载流程图…
查看流程图源码(Mermaid)
flowchart LR
A["明确总体和抽样单位"] --> B["原始 n 个观测"]
B --> C["有放回抽 n 个"]
C --> D["计算一次统计量"]
D --> E["重复 B 次并排序"]
E --> F["取两端分位点"]
F --> G["说明假设与效果大小"]按顺序看,每一步做了什么
- 明确目标参数和独立抽样单位。
- 固定区间方法、置信水平和种子。
- 重复有放回抽样并计算均值。
- 排序后按明确插值规则取分位点。
- 报告端点、样本规模和失效条件。
03对照实现代码
SciPy v1.16.2;scipy/stats/_resampling.py · _bootstrap_resample
以下为原创精简教学实现,不是原样库源码;只演示本文说明的机制,省略真实实现的优化、调度和完整兼容边界。
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 等设置;库默认值与教学例子的选择不同,不应只比较函数名称就认为计算完全一致。
代码先调用谁,再调用谁
- 外层 bootstrap 验证数据与统计量
_bootstrap_resample生成重复下标- 按下标形成各次样本
- 外层计算统计量与区间
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 个观测得到的均值。
生成 B 个均值各扫描 n 次,排序 B 个统计量需要 O(B log B),两个分位点插值为常数时间。
保存为 Main.java,运行 javac --release 17 -encoding UTF-8 Main.java,再运行 java Main。程序包含固定输入自测,断言失败时会抛出错误。
展开收起代码 · Main.java · 完整可运行程序
长行可在代码区域内左右滚动,按 Tab 可把焦点移入代码区。
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,说明独立性假设和区间含义,并为模型比较选对需要一起抽样的单位。
本篇重点加练
区间解释与多次试验后的选择影响结论可信度,重点区分估计精度和决策规则。
- 频率学派置信区间
- 效果大小与多重比较
重点内容会多练几次。先说清楚怎么做,再试试空数据、出错或条件改变时会发生什么。
先自己做,卡住时记下问题,再回来查。问答题写清“为什么、什么时候适用”;动手题留下输入、输出和运行步骤,方便下次重做。
基础必做
- 作业 01原理问答
用反复抽取样本的实验语言解释“95% 置信区间”的含义,分别指出对参数、单次区间和新个体可以做何种陈述。
- 提交内容
- 三个对象的解释表
- 怎样算完成
- 随机对象明确
- 覆盖率含义一致
练到的知识点统计量与抽样分布 · 频率学派置信区间
- 作业 02代码推演
样本为 [1,2,2,8,9]。手工列出三次有放回抽样,计算均值,并对自建的十个 bootstrap 统计量求指定百分位数。
- 提交内容
- 抽样索引及计算记录
- 怎样算完成
- 样本重复合法
- 插值约定完整
练到的知识点有放回 bootstrap · 百分位插值
- 作业 03原理问答
同一效果的区间因样本增加而变窄,但研究同时检查了十个终点。写出固定终点与事后选最好终点两种报告应披露的差异。
- 提交内容
- 两份结果声明与假设表
- 怎样算完成
- 覆盖对象明确
- 选择过程完整公开
练到的知识点频率学派置信区间 · 效果大小与多重比较
综合应用
- 作业 04编程实践
生成 24 个任务家族、每族 3 个相关观测,比较逐行和按家族 bootstrap 的区间;固定随机种子并报告两种采样单位。
- 提交内容
- CPU 脚本与区间比较
- 怎样算完成
- 成组结构保留
- 重采样次数与随机误差报告
练到的知识点有放回 bootstrap · 配对与分组重采样 · 蒙特卡洛误差
- 作业 05面试场景
团队同时尝试 40 个设置,仅展示最小 p 值的那个。给出一份可审计的分析计划,区分探索结论和后续确认性检验。
- 提交内容
- 检验计划与结果呈现规则
- 怎样算完成
- 选择过程公开
- 效果大小有独立报告
练到的知识点原假设与 p 值 · 效果大小与多重比较
- 作业 06排错实验
用已知参数的简单分布重复生成 200 份小样本,估计所选区间方法的覆盖率;改变样本量并保留失败或退化区间。
- 提交内容
- 覆盖率实验与原始统计
- 怎样算完成
- 真实参数固定
- 经验覆盖和名义覆盖分开
练到的知识点频率学派置信区间 · 配对与分组重采样 · 蒙特卡洛误差
- 作业 07编程实践
用 CPU 模拟零效果下十组独立比较,每次只展示最大差异;重复 300 次,比较完整报告与筛选报告的区间覆盖表现。
- 提交内容
- 模拟代码与覆盖统计
- 怎样算完成
- 真效果和选择规则固定
- 模拟误差及样本数报告
练到的知识点频率学派置信区间 · 效果大小与多重比较
进阶挑战 · 掌握前置后选做
- 作业 08设计评审
设计两个模型在共享测试题上的比较协议,测试题又按模板相关;同时考虑任务层不确定性和训练种子层不确定性。
- 提交内容
- 层级结构图与分析计划
- 怎样算完成
- 各随机来源明确
- 相关观测不冒充独立样本
练到的知识点配对与分组重采样 · 原假设与 p 值 · 效果大小与多重比较
思维拓展
先写出你的猜想,再用例子或实验验证。答案可以不同,但要说清依据、适用情况,以及还有什么没弄懂。
- 作业 09思维拓展 · 开放探究
如果研究只有一份很小的样本,增加 bootstrap 次数能否支持任意精确的实际决策?自拟有成本阈值的场景,界定可消除和不可消除的不确定性。
- 提交内容
- 决策场景及不确定性分解
- 怎样算完成
- 数值采样误差与数据局限分开
- 结论有明确目标总体
练到的知识点频率学派置信区间 · 效果大小与多重比较
完成后,再检验一次
给每题标记“独立完成 / 查阅后完成 / 尚未完成”。查过资料或没做出的题,记下卡在哪里。隔一天换一组输入再试,能解释结果和出错原因,再把这个知识点标为掌握。
继续阅读
先看能帮你完成当前练习的部分。例子跑通后,再读更深入的解释。
- 必读参考文档英文
SciPy v1.16.2:bootstrap 的有放回索引抽样 (新标签页)↗
核对
_bootstrap_resample的索引维度和有放回机制,区分抽样小函数与完整区间流程。 - 深入参考文档英文
SciPy bootstrap 文档 (新标签页)↗
对照 paired、axis、method 与退化分布警告。
- 深入参考文档英文
ASA 关于 p 值的声明 (新标签页)↗
阅读条件概率解释、效果大小和完整报告原则。
- 深入参考文档英文
MIT 概率与统计课程 (新标签页)↗
学习估计、置信区间、假设检验及其前提。