콘텐츠로 이동

붓스트랩-t 방법

동기

고전적인 \(t\) 구간 \(\hat{\theta} \pm t_{\alpha/2} \cdot \hat{\text{se}}\)는 추축량 \((\hat{\theta} - \theta)/\hat{\text{se}}\)가 알려진 분포(스튜던트 \(t\) 또는 표준정규)를 따른다고 가정한다. 붓스트랩-\(t\) 방법(스튜던트화 붓스트랩이라고도 한다)은 붓스트랩으로 추축량 자체의 분포를 추정하여 이 가정을 피한다. 그 결과 2차 정확도를 갖는 신뢰구간을 얻는다. 포함확률의 정밀도는 BCa 방법과 맞먹지만, 변환 불변성은 갖지 않는다.

핵심 발상은 통계량 \(\hat{\theta}\)만이 아니라 분모를 포함한 \(t\) 통계량 전체를 붓스트랩한다는 것이다.

스튜던트화 붓스트랩 통계량

각 붓스트랩 표본에서 추정값과 그 추정 표준오차를 함께 계산한다.

\[ t^{*(b)} = \frac{\hat{\theta}^{*(b)} - \hat{\theta}}{\hat{\text{se}}^{*(b)}} \]

여기서 \(\hat{\theta}^{*(b)}\)는 \(b\)번째 붓스트랩 표본에서 계산한 통계량이고, \(\hat{\text{se}}^{*(b)}\)는 같은 붓스트랩 표본에서 계산한 \(\hat{\theta}\)의 추정 표준오차이다.

\(t^{*(b)}\)는 추축량 \((\hat{\theta} - \theta)/\hat{\text{se}}\)의 붓스트랩 판본이다. 붓스트랩 표본에 걸친 그 분포가 추축량의 참 분포를 근사한다.

알고리즘

  1. 원표본에서 관측 통계량 \(\hat{\theta}\)와 그 추정 표준오차 \(\hat{\text{se}}\)를 계산한다.
  2. \(b = 1, \ldots, B\)에 대해:
    • 크기 \(n\)인 붓스트랩 표본을 복원추출한다.
    • 붓스트랩 표본에서 \(\hat{\theta}^{*(b)}\)를 계산한다.
    • 붓스트랩 표본에서 \(\hat{\text{se}}^{*(b)}\)를 계산한다(아래 참고).
    • \(t^{*(b)} = (\hat{\theta}^{*(b)} - \hat{\theta}) / \hat{\text{se}}^{*(b)}\)를 계산한다.
  3. \(\{t^{*(1)}, \ldots, t^{*(B)}\}\)의 \(q\)번째 분위수를 \(t^*_{(q)}\)라 하자.
  4. \(100(1-\alpha)\%\) 붓스트랩-\(t\) 신뢰구간은
\[ \left[\hat{\theta} - t^*_{(1-\alpha/2)} \cdot \hat{\text{se}}, \quad \hat{\theta} - t^*_{(\alpha/2)} \cdot \hat{\text{se}}\right] \]

분위수가 뒤바뀐 것에 주목하라. \(t^*\)의 상위 분위수가 구간의 하한에 쓰이고 그 반대도 마찬가지이다. 이는 추축량 부등식 \(t^*_{(\alpha/2)} \le (\hat{\theta} - \theta)/\hat{\text{se}} \le t^*_{(1-\alpha/2)}\)을 \(\theta\)에 대해 풀면 나온다.

내부 표준오차의 추정

붓스트랩-\(t\)에서 가장 결정적이고 계산이 무거운 부분은 각 붓스트랩 표본마다 \(\hat{\text{se}}^{*(b)}\)를 계산하는 일이다. 흔한 세 가지 접근이 있다.

공식 기반. \(\hat{\text{se}}\)의 닫힌 공식이 있으면(예: 평균의 \(s/\sqrt{n}\)) 각 붓스트랩 표본에 같은 공식을 적용한다. 빠르고 수치적으로 안정적이다.

붓스트랩 안의 잭나이프. 각 붓스트랩 표본에서 관측값을 하나씩 빼며 잭나이프 표준오차를 계산한다. 붓스트랩 복제마다 \(n\)번의 추가 계산이 필요하다.

중첩 붓스트랩(이중 붓스트랩). 각 붓스트랩 표본에서 \(B_2\)개의 2단계 재표본을 뽑아 \(\hat{\text{se}}^{*(b)}\)를 추정한다. 총 \(B \times B_2\)번의 계산이 들어 대개 감당하기 어렵다.

내부 표준오차에 대한 실무 권고

공식이 있으면 공식 기반 추정을 쓴다. 없으면 각 붓스트랩 표본 안에서 잭나이프를 쓴다. 중첩 붓스트랩은 실무에서 거의 필요 없고, \(B \times B_2\)의 계산비용이 정당화되는 경우가 드물다.

2차 정확도를 달성하는 이유

붓스트랩-\(t\) 구간의 포함확률 오차는 백분위수 구간의 \(O(n^{-1/2})\)에 비해 \(O(n^{-1})\)이다. 이유는 스튜던트화된 통계량 \(t^* = (\hat{\theta}^* - \hat{\theta})/\hat{\text{se}}^*\)이 \((\hat{\theta} - \theta)/\hat{\text{se}}\)의 분포를 근사하는 정확도가, 스튜던트화하지 않은 \(\hat{\theta}^* - \hat{\theta}\)가 \(\hat{\theta} - \theta\)를 근사하는 정확도보다 한 차수 높기 때문이다.

스튜던트화는 분산이 일정하지 않은 데서 오는 선행 효과를 흡수한다. \(\text{Var}(\hat{\theta})\)가 \(\theta\)에 의존하면 스튜던트화하지 않은 붓스트랩 분포는 산포가 틀리는데, 스튜던트화 판본은 \(\hat{\text{se}}^*\)로 나누어 스스로를 보정한다.

BCa와의 비교

BCa와 붓스트랩-\(t\) 둘 다 2차 정확도를 달성한다. BCa 구간은 변환 불변이지만 가속을 위한 잭나이프 계산이 필요하다. 붓스트랩-\(t\)는 변환 불변이 아니지만 추축량을 직접 쓰므로 어떤 맥락에서는 더 자연스럽다. 모의실험 연구에서 매끄러운 통계량에 대해 두 방법의 포함확률은 대체로 비슷하다.

\(t^*\) 분포는 무엇을 학습하는가

말로 하면 추상적이니, 추축량의 참 분포와 그것을 근사하는 두 후보를 한 자리에 놓고 보자.

참 추축량 분포, 붓스트랩 t* 분포, t(14) 밀도의 비교

위 칸의 파란 히스토그램은 \(\text{Exp}(1)\) 모집단에서 \(n = 15\)를 20만 번 새로 뽑아 계산한 \(T = (\bar{x} - \mu)/\widehat{\text{se}}\)의 참 분포이다. 현실에서는 결코 그릴 수 없는 그림이며, 여기서는 정답지로만 쓴다. 이 분포는 왼쪽으로 심하게 치우쳐 있다. 붉은 파선인 \(t(14)\) 밀도는 대칭이라 이 모양을 전혀 담지 못한다.

주황 계단이 표본 하나에서 얻은 붓스트랩 \(t^*\)이다. 놀라운 것은 그것이 20만 번 표집한 정답지를 거의 따라간다는 점이다. 축 아래 삼각형이 각자의 \(2.5\) 백분위수로, 참값이 \(-3.46\)인데 \(t^*\)가 \(-3.68\)을 내놓았다. 반면 \(t(14)\)는 \(-2.15\)로 왼쪽 꼬리의 길이를 절반 가까이 과소평가한다. 스튜던트화를 하지 않고 \(\hat\theta^* - \hat\theta\)만 보면 자료의 척도가 그대로 남아 이만한 정확도가 나오지 않는다. \(\widehat{\text{se}}^*\)로 나누는 순간 척도가 빠지고 모양만 남기 때문에 표본 하나로도 참 분포의 꼬리를 배울 수 있다.

아래 칸이 그 차이가 구간에 미치는 영향이다. 세 구간 모두 같은 표본(\(\bar{x} = 1.182\))에서 나왔다. 고전 \(t\) 구간 \([0.449,\ 1.915]\)와 백분위수 구간 \([0.617,\ 1.899]\)는 위쪽 한계가 \(1.9\) 언저리인데, 붓스트랩-\(t\)는 상한을 \(2.439\)까지 늘린다. 분위수 반전 때문에 \(t^*\)의 긴 왼쪽 꼬리가 구간의 오른쪽 끝을 만들기 때문이다. \(\bar{x}\)가 참값을 아래로 크게 빗나가는 일이 흔하다면, 구간은 위쪽으로 길어야 그 경우를 덮는다. 연습문제 1의 포함확률 \(0.944\) 대 \(0.896\)의 차이가 바로 이 길어진 오른쪽 끝에서 나온다.

보기 1. 평균의 붓스트랩-t 구간. \(n = 20\)인 표본에서 \(\bar{x} = 7.3\), \(s = 2.1\)을 얻어 \(\hat{\text{se}} = s/\sqrt{n} = 0.470\)이라 하자.

붓스트랩-\(t\) 절차:

  1. \(b = 1, \ldots, 10{,}000\)에 대해 20개를 복원추출하여 \(\bar{x}^{*(b)}\)와 \(s^{*(b)}/\sqrt{20}\)을 계산한다.
  2. \(t^{*(b)} = (\bar{x}^{*(b)} - \bar{x}) / (s^{*(b)}/\sqrt{20})\)을 계산한다.
  3. \(\{t^{*(b)}\}\)의 2.5 백분위수와 97.5 백분위수가 \(t^*_{(0.025)} = -2.18\), \(t^*_{(0.975)} = 2.31\)이라 하자.
  4. 95% 붓스트랩-\(t\) 구간은
풀이
\[ [7.3 - 2.31 \times 0.470, \quad 7.3 - (-2.18) \times 0.470] = [6.21, \; 8.32] \]

고전적 \(t\) 구간 \(7.3 \pm 2.093 \times 0.470 = [6.32, 8.28]\)과 비교하라. 붓스트랩-\(t\) 구간은 비대칭이며, 표본분포의 완만한 치우침을 반영한다.

장점

  • 2차 정확도: 포함확률 오차가 \(O(n^{-1})\)이다.
  • 추축량 기반 추론에 자연스럽다: 고전적 \(t\) 통계량 접근의 직접적 확장이다.
  • 잭나이프가 필요 없다(\(\hat{\text{se}}\)의 공식이 있는 경우). BCa와 대비된다.

한계

계산비용. 닫힌 공식이 없으면 붓스트랩 루프 안에서 \(\hat{\text{se}}^{*(b)}\)를 계산하는 것이 비쌀 수 있다.

변환 불변이 아니다. \(\phi = m(\theta)\)의 붓스트랩-\(t\) 구간이 일반적으로 \([m(L), m(U)]\)가 아니다. 변환 불변성이 중요하면 BCa가 낫다.

꼬리가 불안정하다. \(\hat{\text{se}}^{*(b)}\)가 이따금 매우 작으면(소표본에서 그렇다) \(t^{*(b)}\)가 극단적으로 커져 분위수 추정이 요동친다. 극단적인 \(t^*\) 값을 윈저화하거나 절사하면 도움이 된다.

붓스트랩 표본의 표준오차가 작을 때

붓스트랩 표본이 우연히 변동이 매우 작으면(예: 같은 값이 많이 반복되면) \(\hat{\text{se}}^{*(b)}\)가 \(0\)에 가까워져 극단적인 \(t^{*(b)}\)가 나온다. 이 이상치가 구간 폭을 부풀린다. 실무에서는 극단적인 \(t^*\)를 감시하고 대응하는 일이 중요하다.

연습문제

연습문제 1. 붓스트랩-\(t\)가 정말로 백분위수법보다 나은지 확인하라. \(\text{Exp}(1)\) 자료의 평균(참값 \(=1\))에 대해 \(n = 15, 30, 100\)에서 포함확률과 구간 폭을 비교하라.

풀이
import numpy as np
rng = np.random.default_rng(2)

for n in (15, 30, 100):
    M, B = 2000, 1000
    ct = cp = cn = 0
    wt, wp = [], []
    for _ in range(M):
        x = rng.exponential(1, n)
        th = x.mean(); se = x.std(ddof=1) / np.sqrt(n)
        idx = rng.integers(0, n, (B, n)); xb = x[idx]
        bs = xb.mean(axis=1)
        seb = xb.std(axis=1, ddof=1) / np.sqrt(n)
        t = (bs - th) / seb

        tl, tu = np.percentile(t, [2.5, 97.5])
        lo, hi = th - tu*se, th - tl*se
        ct += lo <= 1 <= hi; wt.append(hi - lo)

        lo2, hi2 = np.percentile(bs, [2.5, 97.5])
        cp += lo2 <= 1 <= hi2; wp.append(hi2 - lo2)

        cn += th - 1.96*se <= 1 <= th + 1.96*se
    print(n, round(ct/M, 3), round(cp/M, 3), round(cn/M, 3),
          round(np.mean(wt), 3), round(np.mean(wp), 3))

출력:

15 0.944 0.896 0.903 1.314 0.918
30 0.953 0.924 0.926 0.799 0.673
100 0.94 0.934 0.936 0.404 0.384
\(n\) 붓스트랩-\(t\) 백분위수 정규근사 \(t\) 구간 폭 백분위수 폭
15 0.944 0.896 0.903 1.314 0.918
30 0.953 0.924 0.926 0.799 0.673
100 0.940 0.934 0.936 0.404 0.384

\(n = 15\)에서 붓스트랩-\(t\)가 \(0.944\)로 명목값에 거의 도달하는 반면 백분위수는 \(0.896\)에 그친다. 5%p 가까운 차이이다.

대가는 더 넓은 구간이다. \(n = 15\)에서 폭이 \(1.314\) 대 \(0.918\)로 43% 넓다. 그러나 이것은 손해가 아니다. 백분위수 구간이 좁은 것은 참값을 자주 놓친다는 뜻이기 때문이다. 정직한 비교는 같은 포함확률을 달성하는 데 필요한 폭이다.

\(n = 100\)이 되면 세 방법이 \(0.934\)--\(0.940\)으로 수렴하고 폭 차이도 5%로 줄어든다. 붓스트랩-\(t\)의 이득은 소표본에서 크다.

왜 지수분포에서 이렇게 차이가 나는가. \(\text{Exp}(1)\)의 왜도가 \(2\)로 크다. \(\bar{X}\)의 표본분포가 오른쪽으로 치우쳐 있고, 결정적으로 \(\bar{X}\)와 \(s\)가 강한 양의 상관을 갖는다(16장 연습문제 1 참조). 스튜던트화가 이 상관을 자동으로 흡수한다.

연습문제 2. "꼬리가 불안정하다"는 한계를 실제로 보라. \(n = 8\)인 지수 자료에서 \(t^*\) 분포가 어떻게 되는가?

풀이
import numpy as np
rng = np.random.default_rng(11)
n = 8
x = rng.exponential(1, n)
th = x.mean(); se = x.std(ddof=1) / np.sqrt(n)

B = 20000
idx = rng.integers(0, n, (B, n)); xb = x[idx]
bs = xb.mean(axis=1)
seb = xb.std(axis=1, ddof=1) / np.sqrt(n)
t = (bs - th) / seb

print("최소 se*  :", round(seb.min(), 5))          # 0.01019
print("최대 |t*| :", round(np.abs(t).max(), 1))     # 66.0
print(np.round(np.percentile(t, [0.5, 2.5, 50, 97.5, 99.5]), 3))
# [-30.537 -11.302  -0.089   1.502   2.054]

출력:

최소 se*  : 0.01019
최대 |t*| : 66.0
[-30.537 -11.302  -0.089   1.502   2.054]
백분위수 0.5 2.5 50 97.5 99.5
\(t^*\) \(-30.54\) \(-11.30\) \(-0.09\) \(1.50\) \(2.05\)

\(t^*\) 분포가 극도로 비대칭이다. 2.5 백분위수가 \(-11.3\)인데 97.5 백분위수는 \(+1.50\)이다. 정상적인 \(t\) 분포라면 \(\pm 2.4\) 정도여야 한다.

결과적으로 신뢰구간이

\[ [\hat\theta - 1.50 \times \hat{\text{se}}, \; \hat\theta + 11.30 \times \hat{\text{se}}] = [0.086, \; 5.856] \]

으로 폭이 \(5.77\)이다. 자료의 척도가 \(1\) 정도인데 구간이 그 6배에 이른다.

왜 이런 일이 생기는가. \(n = 8\)에서 붓스트랩 표본이 같은 값 몇 개로만 채워지는 일이 드물지 않다. 그러면 \(s^*\)가 \(0\)에 가까워지고 \(t^*\)가 폭발한다. 최소 \(\hat{\text{se}}^* = 0.0102\)이고 최대 \(|t^*| = 66\)이다.

비대칭이 한쪽으로 쏠리는 것은 지수분포의 오른쪽 꼬리 때문이다. 큰 값이 붓스트랩 표본에서 빠지면 \(\bar{x}^*\)가 작아지는 동시에 \(s^*\)도 작아져, 분자가 음수이고 분모가 작아 \(t^*\)가 크게 음수가 된다.

완화 방법.

# 극단 1%를 절사한다
m = np.abs(t) < np.percentile(np.abs(t), 99)
tl, tu = np.percentile(t[m], [2.5, 97.5])
print("절사 후 폭:", round((tu - tl) * se, 4))   # 5.4318 (원래 5.7699)

출력:

절사 후 폭: 5.4318

절사가 도움이 되지만 \(5.77 \to 5.43\)으로 6% 줄이는 데 그친다. 근본 문제는 \(n = 8\)이 붓스트랩-\(t\)에 너무 작다는 것이다.

권고: \(n < 15\) 정도에서는 붓스트랩-\(t\)를 피하거나, 표준오차의 안정적인 공식이 있는 통계량에만 쓴다. 평균처럼 \(s/\sqrt{n}\)을 쓰는 경우에도 \(n\)이 작으면 \(s^*\)의 변동이 문제가 된다.

연습문제 3. 붓스트랩-\(t\) 구간의 분위수 반전이 왜 일어나는지 추축량 부등식에서 유도하라.

풀이

추축량 \(T = (\hat{\theta} - \theta)/\hat{\text{se}}\)의 분포를 안다고 하자. \(T\)의 \(q\)번째 분위수를 \(t_q\)라 하면 정의에 의해

\[ P\!\left(t_{\alpha/2} \le \frac{\hat{\theta} - \theta}{\hat{\text{se}}} \le t_{1-\alpha/2}\right) = 1 - \alpha \]

이다. \(\hat{\text{se}} > 0\)을 곱하면

\[ t_{\alpha/2}\,\hat{\text{se}} \le \hat{\theta} - \theta \le t_{1-\alpha/2}\,\hat{\text{se}} \]

이다. 각 항에서 \(\hat\theta\)를 빼고 \(-1\)을 곱하면 부등호의 방향이 뒤집힌다.

\[ -t_{1-\alpha/2}\,\hat{\text{se}} \le \theta - \hat{\theta} \le -t_{\alpha/2}\,\hat{\text{se}} \]
\[ \hat{\theta} - t_{1-\alpha/2}\,\hat{\text{se}} \le \theta \le \hat{\theta} - t_{\alpha/2}\,\hat{\text{se}} \]

따라서 신뢰구간은 \(\left[\hat{\theta} - t_{1-\alpha/2}\hat{\text{se}}, \; \hat{\theta} - t_{\alpha/2}\hat{\text{se}}\right]\)이고, \(T\)의 상위 분위수가 구간의 하한을 만든다. \(\square\)

\(t_q\)를 붓스트랩으로 추정한다. 붓스트랩 원리에 따라 \(T\)의 분포를 \(T^* = (\hat{\theta}^* - \hat{\theta})/\hat{\text{se}}^*\)의 분포로 근사하므로 \(t_q \approx t^*_{(q)}\)이다.

고전적 \(t\) 구간에서 반전이 보이지 않는 이유

고전적 \(t\) 구간에서도 같은 반전이 일어나지만 \(t\) 분포가 대칭이라 눈에 띄지 않는다. \(t_{1-\alpha/2} = -t_{\alpha/2}\)이므로

\[ [\hat\theta - t_{1-\alpha/2}\hat{\text{se}}, \; \hat\theta - t_{\alpha/2}\hat{\text{se}}] = [\hat\theta - t_{1-\alpha/2}\hat{\text{se}}, \; \hat\theta + t_{1-\alpha/2}\hat{\text{se}}] \]

이 되어 익숙한 \(\hat\theta \pm t\,\hat{\text{se}}\) 형태가 된다. 붓스트랩-\(t\)에서는 \(t^*\)의 분포가 비대칭이라 반전이 실제 효과를 낸다.

연습문제 4. 스튜던트화를 하지 않으면 무엇을 잃는가? 같은 붓스트랩 복제값에서 \((\hat\theta^* - \hat\theta)\)의 분위수만 쓰는 기본 구간과 붓스트랩-\(t\)를 비교하라.

풀이

두 구간의 차이는 분모의 유무뿐이다.

방법 사용하는 붓스트랩 양 구간
기본 (추축) \(\hat\theta^* - \hat\theta\) \([2\hat\theta - \hat\theta^*_{(1-\alpha/2)}, \; 2\hat\theta - \hat\theta^*_{(\alpha/2)}]\)
붓스트랩-\(t\) \((\hat\theta^* - \hat\theta)/\hat{\text{se}}^*\) \([\hat\theta - t^*_{(1-\alpha/2)}\hat{\text{se}}, \; \hat\theta - t^*_{(\alpha/2)}\hat{\text{se}}]\)
import numpy as np
rng = np.random.default_rng(2)
for n in (15, 30, 100):
    M, B = 2000, 1000
    ct = cb = 0
    for _ in range(M):
        x = rng.exponential(1, n)
        th = x.mean(); se = x.std(ddof=1) / np.sqrt(n)
        idx = rng.integers(0, n, (B, n)); xb = x[idx]
        bs = xb.mean(axis=1)
        seb = xb.std(axis=1, ddof=1) / np.sqrt(n)
        t = (bs - th) / seb
        tl, tu = np.percentile(t, [2.5, 97.5])
        ct += th - tu*se <= 1 <= th - tl*se
        lo, hi = np.percentile(bs, [2.5, 97.5])
        cb += 2*th - hi <= 1 <= 2*th - lo
    print(n, round(ct/M, 3), round(cb/M, 3))

출력:

15 0.944 0.878
30 0.953 0.906
100 0.94 0.927
\(n\) 붓스트랩-\(t\) 기본 (추축)
15 0.944 0.878
30 0.953 0.906
100 0.940 0.927

스튜던트화 하나로 \(n = 15\)에서 포함확률이 \(0.878 \to 0.944\)로 6.6%p 개선된다.

무엇이 개선되는가. \(\hat{\theta}^* - \hat{\theta}\)의 분포는 \(\hat{\text{se}}\)가 얼마나 큰지에 따라 산포가 달라진다. 우연히 \(s\)가 큰 표본을 얻으면 붓스트랩 분포도 넓어지고, 그 넓은 분포를 그대로 구간에 쓰면 폭이 자료에 따라 요동친다.

\(\hat{\text{se}}^*\)로 나누면 이 요동이 제거된다. \(t^*\)는 척도에 대해 (근사적으로) 불변이므로 자료마다 다른 척도를 자동으로 표준화한다. 이것이 "스튜던트화가 추축성을 개선한다"는 말의 구체적 의미이다.

비유. 고전적 통계학에서 \(\sigma\)를 알면 \(z = (\bar X - \mu)/(\sigma/\sqrt n)\)을 쓰고, 모르면 \(t = (\bar X - \mu)/(s/\sqrt n)\)을 쓴다. \(t\) 분포가 \(z\)보다 꼬리가 두꺼운 것은 \(s\)의 변동을 반영하기 때문이다. 붓스트랩-\(t\)는 이 논리를 비모수 상황으로 옮긴 것이며, \(t^*\) 분포가 그 두꺼운 꼬리를 자료에서 직접 학습한다.


정리하며

붓스트랩-\(t\) 방법은 붓스트랩 재표집으로 스튜던트화된 추축량 \((\hat{\theta} - \theta)/\hat{\text{se}}\)의 분포를 추정한다. 각 붓스트랩 복제에 표준오차 추정값을 포함시킴으로써 2차 정확도의 포함확률을 달성한다. 주된 난점은 내부 표준오차 \(\hat{\text{se}}^{*(b)}\)를 효율적으로 계산하는 일이다. 표준오차의 공식이 있으면 붓스트랩-\(t\)가 직관적이고 매우 효과적이며, 그렇지 않으면 BCa가 더 실용적일 수 있다.