scipy.stats.

bootstrap#

scipy.stats.bootstrap(data, statistic, *, n_resamples=9999, batch=None, vectorized=None, paired=False, axis=0, confidence_level=0.95, alternative='two-sided', method='BCa', bootstrap_result=None, rng=None)[源代码]#

计算统计量的双侧自助法置信区间。

method'percentile'alternative'two-sided' 时,按照以下步骤计算自助法置信区间。

  1. 重采样数据:对于 data 中的每个样本,以及对于每个 n_resamples,从原始样本中抽取一个与原始样本大小相同的随机样本(可放回)。

  2. 计算统计量的自助分布:对于每组重采样,计算检验统计量。

  3. 确定置信区间:找到自助分布的区间,该区间

    • 关于中位数对称且

    • 包含 confidence_level 的重采样统计量值。

虽然 'percentile' 方法是最直观的,但在实践中很少使用。还有两种更常用的方法,'basic' (“反向百分位数”)和 'BCa' (“偏差校正和加速”);它们在执行步骤 3 的方式上有所不同。

如果从各自的分布中随机抽取 \(n\)data 中的样本,则 bootstrap 返回的置信区间将包含这些分布的统计量的真实值大约 confidence_level\(\, \times \, n\) 次。

参数:
data类似数组的序列

data 的每个元素都是一个样本,其中包含来自基础分布的标量观测值。 data 的元素必须可广播到相同的形状(可能除了由 axis 指定的维度)。

在 1.14.0 版本中更改:如果 data 的元素的形状不相同(除了由 axis 指定的维度),bootstrap 现在将发出 FutureWarning 。从 SciPy 1.16.0 开始,bootstrap 将在执行计算之前显式地将元素广播到相同的形状(除了沿 axis)。

statistic可调用对象

要计算置信区间的统计量。 statistic 必须是一个可调用对象,它接受 len(data) 个样本作为单独的参数,并返回结果统计量。如果 vectorized 设置为 True,则 statistic 还必须接受关键字参数 axis,并且可以向量化以沿提供的 axis 计算统计量。

n_resamplesint,默认值:9999

执行重采样的次数,以形成统计量的自助分布。

batchint,可选

在每次向量化调用 statistic 时要处理的重采样数。内存使用量为 O( batch * n ),其中 n 是样本大小。默认值为 None,在这种情况下,batch = n_resamples (或 batch = max(n_resamples, n) 对于 method='BCa')。

vectorizedbool,可选

如果将 vectorized 设置为 False,则不会将关键字参数 axis 传递给 statistic,并且预期仅计算 1D 样本的统计量。如果为 True,则会将关键字参数 axis 传递给 statistic,并且预期在传递 ND 样本数组时沿 axis 计算统计量。如果为 None(默认值),如果 axisstatistic 的参数,则会将 vectorized 设置为 True。使用向量化统计量通常会减少计算时间。

pairedbool,默认值:False

统计量是否将 data 中样本的对应元素视为成对的。如果为 True,则 bootstrap 将重采样一个索引数组,并对 data 中的所有数组使用相同的索引;否则,bootstrap 将独立地重采样每个数组的元素。

axisint,默认值:0

计算 statisticdata 中样本的轴。

confidence_levelfloat,默认值:0.95

置信区间的置信水平。

alternative{‘two-sided’,‘less’,‘greater’},默认值:'two-sided'

对于双侧置信区间,选择 'two-sided'(默认值),对于下限为 -np.inf 的单侧置信区间,选择 'less',对于上限为 np.inf 的单侧置信区间,选择 'greater'。单侧置信区间的另一个界限与 confidence_level 距离 1.0 两倍的双侧置信区间的界限相同;例如,95% 'less' 置信区间的上限与 90% 'two-sided' 置信区间的上限相同。

method{‘percentile’,‘basic’,‘bca’},默认值:'BCa'

是否返回“百分位数”自助法置信区间 ('percentile'),“基本” (又名“反向”) 自助法置信区间 ('basic'),或偏差校正和加速的自助法置信区间 ('BCa')。

bootstrap_resultBootstrapResult,可选

提供先前调用 bootstrap 返回的结果对象,以将先前的自助分布包含在新的自助分布中。例如,这可用于更改 confidence_level,更改 method,或查看执行其他重采样而不重复计算的效果。

rng{None, int, numpy.random.Generator},可选

如果通过关键字传递 rng,则会将 numpy.random.Generator 以外的类型传递给 numpy.random.default_rng 以实例化一个 Generator。 如果 rng 已经是 Generator 的实例,则使用提供的实例。 指定 rng 以实现可重复的函数行为。

如果此参数通过位置传递,或者 random_state 通过关键字传递,则应用参数 random_state 的旧版行为。

  • 如果 random_state 为 None (或 numpy.random),则使用 numpy.random.RandomState 单例。

  • 如果 random_state 是一个整数,则使用一个新的 RandomState 实例,并使用 random_state 作为种子。

  • 如果 random_state 已经是 GeneratorRandomState 的实例,则使用该实例。

1.15.0 版本更改: 作为从使用 numpy.random.RandomState 转换为使用 numpy.random.GeneratorSPEC-007 转换的一部分,此关键字从 random_state 更改为 rng。 在过渡期间,这两个关键字将继续工作,尽管一次只能指定一个。 过渡期结束后,使用 random_state 关键字的函数调用将发出警告。 random_staterng 的行为如上所述,但新代码中只应使用 rng 关键字。

返回:
resBootstrapResult

一个具有以下属性的对象

confidence_intervalConfidenceInterval

引导置信区间,作为 collections.namedtuple 的实例,具有 lowhigh 属性。

bootstrap_distributionndarray

引导分布,即每次重采样时 statistic 的值。最后一个维度对应于重采样 (例如 res.bootstrap_distribution.shape[-1] == n_resamples)。

standard_errorfloat 或 ndarray

引导标准误差,即引导分布的样本标准差。

警告:
DegenerateDataWarning

method='BCa' 且引导分布退化(例如,所有元素都相同)时生成。

说明

如果引导分布退化(例如,所有元素都相同),则对于 method='BCa',置信区间的元素可能为 NaN。 在这种情况下,请考虑使用另一种 method 或检查 data,以表明其他分析可能更合适(例如,所有观测值都相同)。

参考文献

[1]

B. Efron 和 R. J. Tibshirani,《An Introduction to the Bootstrap》,Chapman & Hall/CRC, Boca Raton, FL, USA (1993)

[2]

Nathaniel E. Helwig,“Bootstrap Confidence Intervals”,http://users.stat.umn.edu/~helwig/notes/bootci-Notes.pdf

[3]

自助法 (统计),维基百科,https://en.wikipedia.org/wiki/Bootstrapping_%28statistics%29

示例

假设我们从一个未知分布中采样了数据。

>>> import numpy as np
>>> rng = np.random.default_rng()
>>> from scipy.stats import norm
>>> dist = norm(loc=2, scale=4)  # our "unknown" distribution
>>> data = dist.rvs(size=100, random_state=rng)

我们对分布的标准差感兴趣。

>>> std_true = dist.std()      # the true value of the statistic
>>> print(std_true)
4.0
>>> std_sample = np.std(data)  # the sample statistic
>>> print(std_sample)
3.9460644295563863

引导法用于近似如果我们重复从未知分布中采样并在每次都计算样本的统计量时,我们期望的变异性。 它通过重复从原始样本中有放回地重采样值并计算每次重采样的统计量来实现这一点。 这导致了统计量的“引导分布”。

>>> import matplotlib.pyplot as plt
>>> from scipy.stats import bootstrap
>>> data = (data,)  # samples must be in a sequence
>>> res = bootstrap(data, np.std, confidence_level=0.9, rng=rng)
>>> fig, ax = plt.subplots()
>>> ax.hist(res.bootstrap_distribution, bins=25)
>>> ax.set_title('Bootstrap Distribution')
>>> ax.set_xlabel('statistic value')
>>> ax.set_ylabel('frequency')
>>> plt.show()
../../_images/scipy-stats-bootstrap-1_00_00.png

标准误差量化了这种变异性。 它被计算为引导分布的标准差。

>>> res.standard_error
0.24427002125829136
>>> res.standard_error == np.std(res.bootstrap_distribution, ddof=1)
True

统计量的引导分布通常近似正态分布,其尺度等于标准误差。

>>> x = np.linspace(3, 5)
>>> pdf = norm.pdf(x, loc=std_sample, scale=res.standard_error)
>>> fig, ax = plt.subplots()
>>> ax.hist(res.bootstrap_distribution, bins=25, density=True)
>>> ax.plot(x, pdf)
>>> ax.set_title('Normal Approximation of the Bootstrap Distribution')
>>> ax.set_xlabel('statistic value')
>>> ax.set_ylabel('pdf')
>>> plt.show()
../../_images/scipy-stats-bootstrap-1_01_00.png

这表明我们可以基于此正态分布的分位数构建统计量的 90% 置信区间。

>>> norm.interval(0.9, loc=std_sample, scale=res.standard_error)
(3.5442759991341726, 4.3478528599786)

由于中心极限定理,这种正态近似对于样本背后的各种统计量和分布是准确的; 但是,该近似并非在所有情况下都可靠。 因为 bootstrap 被设计为与任意基础分布和统计量一起工作,它使用更高级的技术来生成准确的置信区间。

>>> print(res.confidence_interval)
ConfidenceInterval(low=3.57655333533867, high=4.382043696342881)

如果我们从原始分布中采样 100 次,并为每个样本形成一个引导置信区间,则置信区间大约 90% 的时间包含统计量的真实值。

>>> n_trials = 100
>>> ci_contains_true_std = 0
>>> for i in range(n_trials):
...    data = (dist.rvs(size=100, random_state=rng),)
...    res = bootstrap(data, np.std, confidence_level=0.9,
...                    n_resamples=999, rng=rng)
...    ci = res.confidence_interval
...    if ci[0] < std_true < ci[1]:
...        ci_contains_true_std += 1
>>> print(ci_contains_true_std)
88

与其编写一个循环,我们还可以一次确定所有 100 个样本的置信区间。

>>> data = (dist.rvs(size=(n_trials, 100), random_state=rng),)
>>> res = bootstrap(data, np.std, axis=-1, confidence_level=0.9,
...                 n_resamples=999, rng=rng)
>>> ci_l, ci_u = res.confidence_interval

在这里,ci_lci_u 包含 n_trials = 100 个样本中每个样本的置信区间。

>>> print(ci_l[:5])
[3.86401283 3.33304394 3.52474647 3.54160981 3.80569252]
>>> print(ci_u[:5])
[4.80217409 4.18143252 4.39734707 4.37549713 4.72843584]

同样,大约 90% 包含真实值 std_true = 4

>>> print(np.sum((ci_l < std_true) & (std_true < ci_u)))
93

bootstrap 还可以用于估计多样本统计量的置信区间。 例如,要获得均值之差的置信区间,我们编写一个接受两个样本参数并仅返回统计量的函数。 使用 axis 参数可确保所有均值计算都在单个矢量化调用中执行,这比在 Python 中循环遍历成对的重采样要快。

>>> def my_statistic(sample1, sample2, axis=-1):
...     mean1 = np.mean(sample1, axis=axis)
...     mean2 = np.mean(sample2, axis=axis)
...     return mean1 - mean2

在这里,我们使用默认 95% 置信水平的“百分位数”方法。

>>> sample1 = norm.rvs(scale=1, size=100, random_state=rng)
>>> sample2 = norm.rvs(scale=2, size=100, random_state=rng)
>>> data = (sample1, sample2)
>>> res = bootstrap(data, my_statistic, method='basic', rng=rng)
>>> print(my_statistic(sample1, sample2))
0.16661030792089523
>>> print(res.confidence_interval)
ConfidenceInterval(low=-0.29087973240818693, high=0.6371338699912273)

引导标准误差的估计值也可用。

>>> print(res.standard_error)
0.238323948262459

配对样本统计量也适用。 例如,考虑皮尔逊相关系数。

>>> from scipy.stats import pearsonr
>>> n = 100
>>> x = np.linspace(0, 10, n)
>>> y = x + rng.uniform(size=n)
>>> print(pearsonr(x, y)[0])  # element 0 is the statistic
0.9954306665125647

我们封装 pearsonr,使其仅返回统计量,确保我们使用 axis 参数,因为它是可用的。

>>> def my_statistic(x, y, axis=-1):
...     return pearsonr(x, y, axis=axis)[0]

我们使用 paired=True 调用 bootstrap

>>> res = bootstrap((x, y), my_statistic, paired=True, rng=rng)
>>> print(res.confidence_interval)
ConfidenceInterval(low=0.9941504301315878, high=0.996377412215445)

结果对象可以传递回 bootstrap 以执行额外的重采样

>>> len(res.bootstrap_distribution)
9999
>>> res = bootstrap((x, y), my_statistic, paired=True,
...                 n_resamples=1000, rng=rng,
...                 bootstrap_result=res)
>>> len(res.bootstrap_distribution)
10999

或更改置信区间选项

>>> res2 = bootstrap((x, y), my_statistic, paired=True,
...                  n_resamples=0, rng=rng, bootstrap_result=res,
...                  method='percentile', confidence_level=0.9)
>>> np.testing.assert_equal(res2.bootstrap_distribution,
...                         res.bootstrap_distribution)
>>> res.confidence_interval
ConfidenceInterval(low=0.9941574828235082, high=0.9963781698210212)

而无需重复计算原始引导分布。