본문 바로가기
부트스트랩에 관한 이게 무슨 소리인가 하는 이야기

뜬금없지만, 이번엔 부트스트랩을 다뤄볼까 합니다. 아무래도 신뢰구간으로 추정을 하니까 지금이 아니면 얘기하기 어려울 것 같아서 말이죠. 부트스트랩은 이름이 참 거창하긴 한데, 요즘 들어 통계뿐 아니라 여기저기에서 불쑥불쑥 많이 튀어나오는 용어입니다. 부트스트랩은 부츠에 위쪽에 달린 끈으로 부츠를 신기 어려우니까, 그 끈을 당겨서 쏙 신발이 신겨지게 하는 뭐 그런 용도의 끈을 말합니다. 보통은 발목이 있는 신발에 달려 있습니다만.

OS 쪽에서는 스스로 실행되는 Process를 부트스트랩이라고 부르기도 하고, Booting이 부트스트랩이 어원이라는 얘기도 있고, 부트스트랩을 이용한 Web Front Framework도 있고 다양합니다만, 그 느낌적인 느낌으로는 시작만 하면 외부의 도움 없이 스르륵 알아서 진행되는 그런 느낌과 관련이 있습니다. 어떨 때는 외부의 도움 없이, 어떨 때는 스스륵 트리거만 있다면 알아서 척척의 느낌을 따다 쓰는데, 통계에서는 외부의 도움 없이 혼자 가능하다 뭐 그 정도의 느낌을 차용했다고 보면 조금은 자연스럽지 않을까 합니다. 조금 더 실생활적인 번역은 "자력갱생" 정도가 좋지 않을까 생각합니다. 

사실 부트스트래핑을 얘기하다 보면 늘 나오는 얘기가 마술, 손오공 복제술 등을 그 설명으로 달아놓는데, 처음 볼 때는 이게 무슨 소리인가 하고 의아할 수밖에 없었습니다. 처음의 느낌은 부트스트래핑만 있다면 세상 편해지는 것인가, 표본에 대한 걱정은 더 이상 안 해도 되는 것인가 하는 기대가 생겨 버려서 조금은 곤란한 일입니다. 

모수를 추정하기 위해 중심극한정리를 이용하고자 한다면, 모집단에서 n개의 표본을 복원 추출해서 이 표본의 통계량을 이용해서 모수를 추정하면 아주 마음 편하고 느긋해지겠지만, 아무래도 n크기의 표본 세트가 하나밖에 없을 때에는 모수를 추정하는데 많이 불안한 감이 없지 않아 있게 되는데 이런 문제에 봉착하게 될 때, 부트스트랩을 이용하면 아주 간편하게 모수(평균)를 신뢰구간으로 추정할 수 있습니다. 

방금 알아보았듯이 부트스트랩은 일단 "적은" 데이터에 관련된 용어라는 점이 매우 중요한데, 표본을 가지고 그 표본 안에서 또 표본추출을 하는 방법이라는 점, - 좀 말 장난 같긴 합니다만 - 예를 들어 추출한 표본이 150개 있다면 그 안에서 복원 추출로 50개의 표본을 꺼내서 이것의 평균을 구하고, 이런 평균을 구하는 짓을 100번 반복해서 평균을 구하는 방법 뭐 그런 것입니다. 스스로 자력갱생이죠. 

부트스트래핑 방법을 좀 있어 보이게 다음과 같이 잘 정리하면 - 

① n개의 표본이 있다. 
② 1개씩 n'번 표본을 복원추출로 꺼낸다. (복원 추출이란 꺼냈던 1개 표본(원소)을 다시 넣는 것을 의미하고, 결국 n'개로 이루어진 표본을 만든다는 뜻입니다.)
③ 이 모여진 n'개의 표본의 평균을 구합니다. 
④ 앞의 전체 과정을 k번 반복합니다. 
이것을 부트스트래핑이라고 합니다. 방법 자체는 꽤나 쉽죠. 

그래서, 뭘 어쩌겠다는 의미란 말인가 하면, 정확한 설명하기를 일찌감치 포기하고, 어떻게 하는지 실예를 들면 매우 쉽게 이해할 수 있을 것 같아서 부트스트래핑을 통한 모수의 신뢰구간 추정을 한번 해 보도록 하겠습니다. 

막상 부트스트래핑을 해보면, "본격 수학 없이 신뢰구간 추정하는 마법!!!!"이라는 말을 이해할 수 있게 될 것인데, 마법이라는 말은 "수학 없이"라는 부분이 마법이어야 한다고 생각합니다. 여러 개를 "복제"하면 된다는 것이 마법이어서는 안 된다고 생각합니다. 

지금 하려는 것은 표본 평균에 대한 90% 신뢰구간을 구해보려고 합니다. 원래 신뢰구간을 구하기 위해 중심극한정리를 이용하려면, 웬만큼 큰 표본(n>30)을 (여러 번) 구해서 그것의 통계량을 활용해서 신뢰구간을 구하게 되지만, 부트스트랩에서는 지금 갖고 있는 표본 외에 다른 것을 아무것도 필요로 하지 않습니다. 

자, 이제 우리가 추출한 어떤 표본이 있다고 합시다. 
그 표본이 2, 3, 5, 5, 9 였다고 한다면, 
이 표본에서 복원추출(중복을 허용하여) 5번씩 뽑은 새로운 표본을 20개 영차영차 뽑아보았습니다. 다음과 같은 표본이 뽑혔군요. 뽑힌 표본을 자세히 보면 어떻게 복원 추출했는지 잘 보일 것입니다. 

[5, 3, 3, 5, 5], [3, 5, 3, 5, 9], [5, 9, 2, 2, 5], [3, 2, 5, 9, 5], 
[3, 5, 2, 9, 3], [5, 5, 9, 5, 2], [5, 5, 2, 3, 3], [2, 9, 9, 5, 3], 
[5, 5, 5, 5, 3], [9, 5, 5, 5, 9], [5, 2, 5, 5, 3], [9, 5, 5, 9, 5], 
[5, 3, 5, 5, 5], [9, 5, 2, 5, 9], [5, 5, 3, 2, 5], [3, 5, 5, 2, 2], 
[2, 9, 9, 2, 3], [3, 5, 9, 3, 2], [2, 2, 5, 5, 5], [2, 9, 5, 2, 5]
 
이 20개의 새로운 표본에 대한 각 평균은 (오름차순으로 정렬하면)
3.6, 3.8, 3.8, 4.0, 4.0, 4.0, 4.4, 4.4, 4.6, 4.6, 5.0, 5.2, 5.4, 5.6, 5.8, 6.0, 6.2, 6.2, 7.0, 7.4 
이렇게 20개를 계산하여 만들 수 있습니다. 

이때, 90%신뢰구간을 따진다면 20개 평균에서 1개의 평균은 1/20을 차지하므로 5%를 의미합니다. 그러니까 하위 5% 1개, 상위 5% 1개를 제외한 구간이 90% 신뢰구간이 되고, 그 해당 값이 3.8~7.0까지가 부트스트래핑에 의한 모평균의 추정의 90% 신뢰구간이라고 할 수 있습니다. 어? 막상 예로 보니 꽤나 간단하지요? 그러니까, 수학(산수) 없이 구하는 신뢰구간이고 이것을 마법이라고 부르는 그런 것이겠는데요. 

간단합니다. 그렇다면, 이런 것도 할 수 있겠군요.

예를 들어 이런 표본이 있다고 합시다요. 20개의 표본입니다. 
우리가 관심있는 것은 구매한 사람과 구매하지 않은 사람의 나이가 차이 나는지 알고 싶습니다. 

그렇다면 20개 표본에서 1개씩 다시 뽑아서 20개 크기의 표본을 100개 만든 후에 각 표본의 평균의 차이를 구한 후, 95% 신뢰구간을 만들어 보겠습니다. 이럴 때는 컴퓨터의 힘을 빌리는 것이 상책입니다. 이 코드를 보면 조금은 더 실무적으로 어떻게 할지 감이 오지 않을까 기대하고 있습니다. 

나이 차이를 모을 바구니

for 100번 돌림 :
  20개씩 복원 추출
  그중에 비구매한 사람의 나이 평균 내고, 
  그중에 구매한 사람의 나이 평균 내서,
  두개의 차이를 계산해서 나이 차이 바구니에 넣는다. 
  
나이 차이 바구니를 늘어 놓고, 하위 2.5%, 상위 2.5%에 대한 값을 계산해서 신뢰구간을 구한다.

이 것이 주요 아이디어인데요, 

iteration_loop = 100
lst_diff_Age = []
for _ in range(iteration_loop):
    bootStrapSample = df_raw_buy.sample(20, replace=True) # 하나씩 다시 뽑아 복원 추출
    nonBuyAgeMean = bootStrapSample[bootStrapSample['상품구매여부'] == '비구매']['나이'].mean() #비구매한 사람의 평균 나이  
    BuyAgeMean = bootStrapSample[bootStrapSample['상품구매여부'] == '구매']['나이'].mean() # 구매한 사람의 평균 나이 
    lst_diffAge.append(nonBuyAgeMean - BuyAgeMean) # 비구매 평균나이 - 구매 평균나이 모음 

#  신뢰수준 95% 신뢰구간
np.percentile(lst_diffAge, 2.5), np.percentile(lst_diffAge, 97.5)

이걸 실제로 돌려보니 결과는 다음과 같습니다. 
(-10.14375, -1.2235897435897436) (비구매한 사람의 나이 평균 - 구매한 사람의 나이 평균)

이렇습니다. 이렇다는 얘기는? 구매한 사람의 평균나이가 더 많다는 의미겠군요. (95% 신뢰 구간이 마이너스가 나왔으니까요)  

다시 한번 정리하면 일반적으로 평균을 추정하기 위하여 (여러 개의) 큰 샘플(n>30) 평균을 구해서 중심극한정리를 적용하지만, 부트스트랩을 이용하면 중심극한정리를 이용하지 않고도 신뢰구간을 구할 수 있다는 뜻입니다. 

예를 보면 알겠지만, 기본적으로 컴퓨터를 사용할 수 있는 경우에 매우 편리합니다. 이것을 사람손으로 한다고 생각하면 끔찍하기까지 합니다. 

이것은 마치 데이터가 모자를 때 조금 씩 변형해서 데이터를 부풀리는 augmentation과 느낌적으로 비슷하기도 합니다. 

그리고, 데이터가 모자를 때 부트스트랩 아이디어를 그대로 차용하여, 적은 학습 데이터를 이용해 여러 개의 모델을 만든 후, 최종적으로 각 모델의 예측 결과를 평균 내서 종합(aggregate)해서 판단하는 Enssemble적인 방법을 Bagging이라고 부릅니다.

Enssemble(앙상블)이 나왔으니까, 잠시 얘기하자면 Enssemble은 여러개의 모델을 학습시킨 후에 여러 개의 모델의 투표 결과를 예측 결과로 활용하는 방법입니다. Enssemble 하면 항상 따라 나오는 것이 있는데 그것은 Randdom Forest입니다. Random Forest는 말 그대로 숲인데 무슨 숲이냐면 여러 개의 Decision Tree를 만들어서 Enssemble로 예측한다는 뭐 그런 것인데, Enssemble방법 중에 Bagging을 이용한 대표적인 방법이 Random Forest입니다. 또 다른 얘기들도 있지만, 이 이야기는 나중에 머신러닝에서 살펴보도록 하는 것이 지금 어중 띄게 보는 것보다는 나을 거라 생각합니다. 

친절한 데이터 사이언스 강좌 글 전체 목차 (링크) -



댓글





친절한 데이터 사이언스 강좌 글 전체 목차 (링크) -