ブートストラップ法について
概要
- 復元抽出にて何度もサンプルすることで、その統計値の分布を(できるだけロバストに)知る
- ブートストラップの名前の由来
- 靴のブートストラップという紐を用いて自分自身を持ち上げるという
自己完結できる手段・プロセス
を示すものから
- 靴のブートストラップという紐を用いて自分自身を持ち上げるという
- 復元抽出でのサンプルサイズと求めたい統計量の分散は関連する
numpyで復元抽出
# np.random.choiceで復元抽出で重なりあり
src = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
display(np.sort(np.random.choice(src, 10))) # array([1, 1, 3, 3, 4, 6, 6, 6, 7, 8])
display(np.sort(np.random.choice(src, 10))) # array([ 2, 3, 6, 6, 6, 7, 7, 8, 9, 10])
display(np.sort(np.random.choice(src, 10))) # array([ 4, 5, 6, 7, 8, 9, 9, 9, 10, 10])
具体例(身長のデータが10サンプルのとき、95%信頼区間の近似値を求める)
最初の10サンプルを適当な正規分布から生成
import numpy as np
import matplotlib.pyplot as plt
import scipy.stats as stats
np.random.seed(1)
pop_mean = 171.2
pop_std = 6
sample_size = 10
sample = np.random.normal(pop_mean, pop_std, sample_size)
sample_mean = np.mean(sample)
sample_uvar = np.var(sample, ddof=1)
sample_std = np.sqrt(sample_uvar)
display(sample)
"""
array([180.94607218, 167.52946152, 168.03096949, 164.76218827,
176.39244578, 157.39076782, 181.66887059, 166.63275859,
173.11423458, 169.70377775])
"""
ブートストラップでサンプルサイズ増やす
n_boots = 10000
resample_means = []
for i in range(n_boots):
resample = np.random.choice(sample, 10)
resample_means.append(np.mean(resample))
95%の範囲のデータ
conf_prob = np.array([0.025, 0.975])
resample_conf = np.percentile(resample_means, conf_prob*100)
display(resample_conf)
"""
array([166.26765934, 175.09959133])
"""
t分布を用いての95%の信頼区間
sample_conf = sample_mean + stats.t.ppf(conf_prob, df=sample_size-1) * np.sqrt(sample_uvar / sample_size)
display(sample_conf)
"""
array([165.22915528, 176.00515403])
"""
具体例(少ないデータから相関を求めたい時の信頼性を上げる)
テストの成績が以下の結果であったとき、Eng <-> Math
, Math <-> Sci
の相関をブートストラップする
Eng | Math | Sci | |
---|---|---|---|
0 | 60 | 88 | 90 |
1 | 89 | 82 | 87 |
2 | 65 | 60 | 60 |
3 | 60 | 65 | 61 |
4 | 73 | 85 | 82 |
5 | 52 | 56 | 53 |
6 | 70 | 57 | 60 |
7 | 65 | 75 | 74 |
8 | 65 | 82 | 85 |
9 | 70 | 90 | 95 |
結果
コード
df = pd.DataFrame(total.T)
corrs = []
for n in tqdm(range(10**3 * 5)):
df_cache = []
for n in range(len(df)):
tmp = df.sample(frac=1).iloc[0].to_dict()
df_cache.append(tmp)
corr = pd.DataFrame(df_cache).corr()
corr_sci_math = float(corr.loc[corr.index == "Sci", "Math"])
corrs.append( corr_sci_math )
corrs
ax0 = sns.distplot(corrs)
復元抽出でのサンプルサイズと求めたい統計量の分散は関連する
- サンプルサイズが大きいほど、統計量の分散は小さくなる
- サンプルサイズが小さいほど、統計量の分散は大きくなる