8.1 抽样框、入样概率与权重:样本能代表谁
仪表盘显示,使用新版客户端的站点活跃率更高。若直接把这个均值推广到所有站点,结论会忽略一个麻烦:旧客户端和网络较差的站点几乎没有进入数据。此时样本均值再精确,也只精确描述“被系统看见的人”。
分析能推广到谁,首先由数据怎样进入样本决定。本课先不讨论因果,专门解决代表性问题。
本课目标
- 区分目标总体、抽样框、抽样单位和观察单位;
- 为常见概率抽样设计计算入样概率与权重;
- 识别覆盖偏差、无应答和便利样本限制;
- 在估计方差时保留分层、聚类和权重信息。
1. 从目标总体到分析样本
抽样方案应依次定义:
- 目标总体:结论希望适用于谁,例如本季度所有在运服务;
- 抽样框:实际能够抽取的名单,例如资产登记系统中的服务;
- 抽样单位:从抽样框中随机选中的实体,例如一项服务;
- 观测单位:最终被测量的单位,例如该服务处理的一次请求;
- 分析样本:成功取得并通过质量检查的观测。
若随机选的是服务,却把它的全部请求作为独立样本,流量大的服务会贡献更多行。想估计“平均服务”的表现,应先按服务聚合;想估计“平均请求”的表现,则需另外定义请求的入样概率和分母。
2. 概率抽样的共同底线
概率抽样要求每个总体单位有已知且大于零的入样概率
一个样本单位的权重 20,可理解为它在设计中代表约 20 个总体单位。这不是重要性分数。
这里的入样概率由抽样设计决定,不等于抽中后成功取得响应的概率;后者需要另行处理。
若某类单位的
3. 简单随机抽样
不放回地从
import numpy as np
import pandas as pd
frame = pd.DataFrame({
"service_id": [f"svc-{i:02d}" for i in range(40)],
"traffic_tier": ["high"] * 8 + ["low"] * 32,
"error_rate": [0.10] * 8 + [0.01] * 32,
})
assert frame["service_id"].is_unique
rng = np.random.default_rng(42)
n = 10
if not 0 < n <= len(frame):
raise ValueError("n must be between 1 and frame size")
positions = rng.choice(len(frame), size=n, replace=False)
srs_sample = frame.iloc[positions].copy()
srs_sample["base_weight"] = len(frame) / n
assert len(srs_sample) == 10
assert srs_sample["base_weight"].eq(4).all()本页代码按顺序运行,使用 NumPy 和 pandas。例子估计 40 项服务各自错误率的等权平均,不是按请求量加权的全站错误率。每项服务只占一行;按位置抽取可避免重复 DataFrame 索引使 .loc 额外选中行。保存种子、名单版本、排序和去重规则,才能重现抽样。
4. 分层抽样
将总体按区域、任务类型或风险等级分层,再在每层独立抽样。它可以保证小群体进入样本,也可能提高精度。
第
等比例分配令
层定义必须在抽样前可得且互斥完备。把样本抽完后再按结果“分层”,不是分层抽样。
延续上面的总体,每个流量层各抽 4 项服务。高流量层抽中一半,低流量层只抽中八分之一:
strata = []
for _, group in frame.groupby("traffic_tier", sort=True):
positions = rng.choice(len(group), size=4, replace=False)
selected = group.iloc[positions].copy()
selected["base_weight"] = len(group) / 4
strata.append(selected)
stratified_sample = pd.concat(strata, ignore_index=True)
print(stratified_sample.groupby("traffic_tier")["base_weight"].first().to_dict())
# {'high': 2.0, 'low': 8.0}5. 整群与多阶段抽样
整群抽样先随机选群,再观察入选群内的全部单位;多阶段抽样继续在群内抽取部分单位。例如从 100 个站点抽 20 个,再在每个入选站点的 50 项服务中抽 10 项。用
本例为
6. 系统抽样不能从第一行固定开始
系统抽样以间隔
target_n = 8
if not 0 < target_n <= len(frame):
raise ValueError("target_n must be between 1 and frame size")
step = len(frame) / target_n
start = rng.uniform(0, step)
positions = np.floor(start + step * np.arange(target_n)).astype(int)
systematic_sample = frame.iloc[positions]例如名单按 [1, 0, 0, 0] 重复 10 次,间隔为 4。四个随机起点分别得到均值 1、0、0、0;它们的平均 0.25 等于总体均值,但任意一次都偏离总体。使用前检查排序与周期;k = len(df) // 1000; df.iloc[::k] 在不足 1000 行时还会得到非法步长 0。
7. 加权估计与权重诊断
总体均值可用加权均值估计:
weighted_mean = np.average(
stratified_sample["error_rate"], weights=stratified_sample["base_weight"]
)
print(round(stratified_sample["error_rate"].mean(), 3), round(weighted_mean, 3))
# 0.055 0.028
assert np.isclose(weighted_mean, frame["error_rate"].mean())实际权重可能经历:基本设计权重、无应答调整、校准或后分层。每一步都要记录。极端权重会放大方差;截尾可稳定估计,却引入偏差,必须做敏感性比较而非静默处理。
归一化加权均值属于比率估计,随机分母使它一般不具有严格的设计无偏性。若总体大小
设计效应比较复杂设计和相同样本量简单随机抽样的方差:
它随估计量和变量改变,也可小于 1,例如分层提高精度时。它描述方差,不会诊断或消除覆盖偏差。
8. 无应答与选择偏差
若是否回答与研究变量有关,扩大样本量不会消除偏差。可采取:
- 记录接触次数和无应答原因;
- 用抽样框中的辅助变量建模响应概率;
- 按已知总体边际做校准;
- 比较早答、晚答和未答者可观察特征;
- 对不可观测差异做敏感性分析。
这些调整依赖“给定辅助变量后,无应答可被解释”等假设。便利样本、主动报名和平台日志也可以有分析价值,但不能包装成总体概率样本。
9. 方差估计要尊重设计
普通标准误公式通常假设独立同分布。复杂抽样应使用支持 survey design 的方法:Taylor linearization、replicate weights、按主抽样单位重采样的 bootstrap 等。
不能把整群抽样中的个体逐行 bootstrap;那会破坏原设计。有限总体且抽样比例较大时,还可能需要有限总体修正。
不放回简单随机抽样的均值标准误可估计为
常见误区
- 样本量大就有代表性:大便利样本仍可能系统漏掉某些人。
- 随机抽的是数据行,所以是随机样本:行不一定等于抽样单位。
- 分层样本直接求平均即可:不等比例抽样要使用相应权重。
- 加权能修复任何偏差:入样概率为零或缺少关键辅助变量时不能。
练习
- 为“本季度全部服务的错误率”定义目标总体、抽样框、单位和分析样本。
- 设计一个按流量层分层的样本,并计算各层分析权重。
- 对按服务抽样的数据,比较逐行标准误与 cluster-design 标准误。
- 检查一份系统抽样名单是否含周期,并改用随机起点。
小结
样本能代表谁,不由行数决定,而由抽样框、入样概率和响应机制决定。权重负责把设计带回估计,方差方法则负责保留分层和聚类造成的不确定性。
下一课进入随机实验:代表性回答“对谁成立”,随机分配则帮助回答“处理是否造成结果变化”。