介绍
\quad \quad Bootstrap又称自展法、自举法、自助法、靴带法 , 是统计学习中一种重采样(Resampling)技术,用来估计标准误差、置信区间和偏差
\quad \quad Bootstrap是现代统计学较为流行的一种统计方法,在小样本时效果很好。机器学习中的Bagging,AdaBoost等方法其实都蕴含了Bootstrap的思想,在集成学习的范畴里 Bootstrap直接派生出了Bagging模型.
用子样本来类比总体
举例
\quad \quad
我要统计鱼塘里面的鱼的条数,怎么统计呢?假设鱼塘总共有鱼1000条,我是开了上帝视角的,但是你是不知道里面有多少。
步骤:
- 承包鱼塘,不让别人捞鱼(规定总体分布不变)。
- 自己捞鱼,捞100条,都打上标签(构造样本)
- 把鱼放回鱼塘,休息一晚(使之混入整个鱼群,确保之后抽样随机)
- 开始捞鱼,每次捞100条,数一下,自己昨天标记的鱼有多少条,占比多少(一次重采样取分布)。
- 重复3,4步骤n次。建立分布。
(原理是中心极限定理)
假设一下,第一次重新捕鱼100条,发现里面有标记的鱼12条,记下为12%,放回去,再捕鱼100条,发现标记的为9条,记下9%,重复重复好多次之后,假设取置信区间95%,你会发现,每次捕鱼平均在10条左右有标记,所以,我们可以大致推测出鱼塘有1000条左右。其实是一个很简单的类似于一个比例问题。这也是因为提出者Efron给统计学顶级期刊投稿的时候被拒绝的理由–“太简单”。这也就解释了,为什么在小样本的时候,bootstrap效果较好,你这样想,如果我想统计大海里有多少鱼,你标记100000条也没用啊,因为实际数量太过庞大,你取的样本相比于太过渺小,最实际的就是,你下次再捕100000的时候,发现一条都没有标记,就尴尬了。。。
上述是通过 Bootstrap 方法对鱼塘中鱼的数目进行估计,通过这个举例我们可以总结如下:设总体的分布 F F F未知,但已经有一个容量为 n n n的来自分布 F F F的数据样本,通过有放回抽样的方法抽取 m m m个容量为 n n n的样本,对这 m m m个抽样容量统一计算结果来估计原始的总体分布 F F F, 称为Bootstrap方法
下面继续介绍,如果要估计出某个特征数据的原始均值,标准差,方差等情况,应该是怎么样的呢?
传统估计方法
传统方法中一般会考虑直接使用样本方差(sample variance)来作为估计值。
μ
^
=
x
ˉ
=
∑
i
=
1
n
x
i
n
\hat{\mu} = \bar{x} = \frac{\sum_{i=1}^nx_i}{n}
μ^=xˉ=n∑i=1nxi
S
^
2
=
∑
i
=
1
n
(
x
i
−
x
ˉ
)
2
n
−
1
\hat{S}^2 = \frac{\sum_{i=1}^n(x_i - \bar{x})^2}{n - 1}
S^2=n−1∑i=1n(xi−xˉ)2
σ
^
=
S
2
n
\hat{\sigma} = \frac{S^2}{n}
σ^=nS2
其中: μ ^ \hat{\mu} μ^ 为均值估计, S ^ 2 \hat{S}^2 S^2 为方差估计值, σ ^ \hat{\sigma} σ^ 为标准差估计值
比如有三个样本 X = 1 , 2 , 3 X = 1, 2, 3 X=1,2,3,求样本的方差作为估计值。
Bootstrap 方法
放回抽样,比如上述例子中,有可能第一次抽到 ①,第二次也抽到 ①,第三次还是抽到 ①,对三个样本 X = 1 , 2 , 3 X = 1, 2, 3 X=1,2,3,放回抽样 1000 次,用这 1000 次抽样的结果分别计算出各自的均值 x ˉ \bar{x} xˉ , 然后再利用这 1000 个值,计算其整体的均值,方差等统计量,这就是 Bootstrap 方法,如下图所示:
实际案例
假设有两个金融资产 X X X和 Y Y Y,现在想要合理配置这两个资产,使得其资产组合的风险最小。也就是找到一个 α \alpha α,使得 V a r ( α X + ( 1 − α ) X ) Var(\alpha X + (1 - \alpha) X) Var(αX+(1−α)X)最小。(Var 表示方差)
将上式展开得到
α
2
V
a
r
(
X
)
+
(
1
−
α
)
2
V
a
r
(
X
)
+
α
(
1
−
α
)
C
o
v
(
X
Y
)
\alpha^2 Var(X) + (1 - \alpha)^2Var(X) + \alpha(1 - \alpha)Cov(XY)
α2Var(X)+(1−α)2Var(X)+α(1−α)Cov(XY),首先,通过对
α
\alpha
α 求一阶导等于0,再求二阶导大于0,得到最优
α
\alpha
α 表达式如下:
α
=
σ
Y
2
−
σ
X
Y
σ
X
2
+
σ
Y
2
−
2
σ
X
Y
\alpha = \frac{\sigma_Y^2 - \sigma_{XY}}{\sigma_X^2 + \sigma_Y^2 - 2\sigma_{XY}}
α=σX2+σY2−2σXYσY2−σXY
其中 σ X 2 = V a r ( X ) , σ Y 2 = V a r ( Y ) , \sigma_X^2 = Var(X), \sigma_Y^2 = Var(Y), σX2=Var(X),σY2=Var(Y), and σ X Y = C o v ( X , Y ) \sigma_{XY} = Cov(X, Y) σXY=Cov(X,Y)
实际的 σ X 2 , σ Y 2 , σ X Y \sigma_X^2, \sigma_Y^2, \sigma_{XY} σX2,σY2,σXY 的值并不知道,只能通过现有的样本 X X X 和 Y Y Y 对其进行估计,并用估计值 σ ^ X 2 , σ ^ Y 2 \hat{\sigma}_X^2, \hat{\sigma}_Y^2 σ^X2,σ^Y2 以及 σ ^ X Y \hat{\sigma}_{XY} σ^XY 计算出估计值 α ^ \hat{\alpha} α^,如下:
α ^ = σ ^ Y 2 − σ ^ X Y σ ^ X 2 + σ ^ Y 2 − 2 σ ^ X Y \hat{\alpha} = \frac{\hat{\sigma}_Y^2 - \hat{\sigma}_{XY}}{\hat{\sigma}_X^2 + \hat{\sigma}_Y^2 - 2\hat{\sigma}_{XY}} α^=σ^X2+σ^Y2−2σ^XYσ^Y2−σ^XY
现在的任务就是用一种合理方式去估计 σ ^ X 2 , σ ^ Y 2 \hat{\sigma}_X^2, \hat{\sigma}_Y^2 σ^X2,σ^Y2 以及 σ ^ X Y \hat{\sigma}_{XY} σ^XY,Bootstap 方法如下:对样本进行有放回采样 1000 次,每次采样 100 个样本,计算每个抽样结果的 α ^ \hat{\alpha} α^,在这 1000 个 α ^ \hat{\alpha} α^ 上计算 α ^ \hat{\alpha} α^ 的均值作为 α \alpha α 的估计结果:
可以发现,通过Bootstrap方法,竟然不仅可以估计 α \alpha α的值( 这点普通方法也可以很容易做到),还可以估计 α \alpha α的accuracy也就是其Standard Error。这可是只利用原有的样本进行一次估计所做不到的。那么Bootstrap对于分布特性的估计效果究竟如何呢?请看下图:
左边是真实的
α
\alpha
α,右边则是基于bootstrap方法得到的1000个
α
\alpha
α的分布,可以看到,二者是比较相近的,也就是说Bootstrap有着不错的估计效果。而且当重复次数增多,Bootstrap的估计效果会更好。
不仅是
α
\alpha
α的标准差,如果我们想要估计
α
\alpha
α的中位数、分位数等统计量,也是可以通过Boostrap方法做到的。
本质上,Bootstrap 方法,是将一次的估计过程,重复上千次上万次,从而便得到了得到上千个甚至上万个的估计值,于是利用这不止一个的估计值,我们就可以估计 α \alpha α均值以外的其他统计量:比如标准差、中位数等。
代码实现解决案例中的问题
数据集: 共 100 条数据
导入包和数据
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
df = pd.read_csv('Bootstrap.csv')
df.head(3) # 取前 3 条数据
用传统方法估计 X 总体均值和方差
#普通统计方法估计总体均值和方差
sample_mean = np.mean(df.X)
print("population mean is ",sample_mean )
sample_variance = np.var(df.X)
print("population variance is ",sample_variance/len(df.X ))
Bootstrap估计 X 总体均值和方差:
# 有放回的抽样一次后计算均值代码示例
from random import choices
index = np.random.choice(range(100),100) # 从 1 - 100 个数据中,随机选取,共选 100 个
np.mean(df.X[index])
sample_mean_list = [] # 存储每次抽样后的样本均值
for i in range(1000): # 共计又放回抽样 1000 次
index = np.random.choice(range(100),100) # 每次抽样 100 个样本
sample_mean_list.append(np.mean(df.X[index]))
print("population mean is ",np.mean(sample_mean_list ))
population_variance = np.var(sample_mean_list)
print("population variance is ",population_variance)
# 通过柱状图展现 1000 次抽样结果
plt.hist(sample_mean_list)
plt.show()
解决案例中的选择 α \alpha α 来最小化 V a r ( α X + ( 1 − α ) X ) Var(\alpha X + (1 - \alpha) X) Var(αX+(1−α)X):
# 用公式定义求解 alpha 的函数
def alpha_hat(data):
x = data.X
y = data.Y
covariance = np.cov(x,y)[0][1] # 计算 x 与 y 的协方差
var_x =np.var(x) # 计算 x 的方差
var_y =np.var(y) # 计算 y 的方差
return (var_x-covariance)/(var_y+var_x-2*covariance)
执行 Bootstrap 方法进行抽样,获得最终结果
sample_mean_list = []
for i in range(100):
index = np.random.choice(range(100),100)
sample_mean_list.append(alpha_hat(df.iloc[index,:]))
print("The optimal alpha is: ",np.mean(sample_mean_list))
print("The variance of alpha is ",np.var(sample_mean_list))
plt.hist(sample_mean_list)
References
[1] 统计学中的Bootstrap方法(Bootstrap抽样)
[3] 『迷你教程』机器学习的Bootstrap及Python实现
[4] 机器学习:Bootstrap