카테고리 보관물: 인공지능, 기계학습 ML/AI

앙상블 모델 – 배깅 Bagging

기계학습 부류. 분류(classification) 또는 예측(prediction)에서 여러 모델을 합쳐서 더 좋은 결과를 얻는 방법을 앙상블(Ensemble) 모델이라고 합니다.  앙상블 기법은 배깅(Bagging), 부스팅(Boosting), 스태킹(Stacking) 3종류로 나눌 수 있습니다. 
이 포스트에서는 우선 배깅(Bagging)에 대해서 설명합니다.

앙상블 모델을 배울때 보통 Bagging과 Boosting을 알게 되고 그 다음 Stacking을 생각하게 됩니다. 순서는 중요하지 않지만 기법들이 생각보다 많이  다르고 복잡함의 종류도 다릅니다. 그래서 한꺼번에 설명하기 어렵습니다.

앙상블 모델은 보통은 지도학습(supervised learning)에 사용됩니다. 군집화나 학습데이터가 없는 아웃라이어 감지(outlier detection), 어노멀리 감지(anomaly detection), 클러스터링(clustering) 같은 것에는 쓰기 어렵습니다.

비지도학습(unsupervised learning)에도 앙상블을 할 수 있다고 하는데 실제로 사례를 본적은 없습니다.

배깅 Bagging

배깅은 모델을 병렬로 연결해서 취합하는 방법입니다.
예를들어 결정트리(Decision Tree; 분류 나무)와 같은 알고리즘을 병렬로 연결한다고 하면 여러 개의 트리를 만들어서 결과를 취합합니다.  결합할 때는 다수결(Majority vote)를 쓸 수도있고 가중치(Weighted Majority Vote)를 쓸 수 있는데 기본으로는 다수결을 쓴다고 알려져 있습니다.

배깅의 대표적으로 알려진 알고리즘은 Leo Brieman이 만든 그 유명한 랜덤포레스트(Random Forest)가 있습니다. 이름이 랜덤포레스트인 이유도 배깅과 관련이 있기 때문입니다. 랜덤요소를 이용해 트리를 여러 개 만들고 합쳐서 숲을 만듭니다.

앙상블에서 모델을 몇 개를 결합할지는 보통 초매개변수(Hyper parameter)로 만드는 사람에 의해서 정해지게 됩니다. 결정트리를 앙상블로 결합하는 경우는 보통 100개 이상입니다.

배깅을 조금 구체적으로 설명하면 데이터로 입력값을 주면 Y 또는 N를 알려주는 트리모델을 결합해서 배깅으로 앙상블시키려고 하면 가지고 있는 학습데이터로 100개의 트리 모델을 만들고 실제로 판별에 사용할 때 입력을 100개의 트리모델에 주고 각 트리들이 Y과 N을 각각 던져 주면 그 중 많은 것을 답으로 취하는 방식입니다.  물론 이것은 아주 간단한 예이고 더 복잡하게도 변형이 가능합니다.

그런데 한뭉치의 학습데이터로 모델을 여러 개를 만든다고 했는데 어떻게 여러 개를 만드느냐가 의문입니다.
100개의 결정트리를 만들려면 학습데이터를 100등분해서 각각 만들면 되지 않을까라고 생각하겠지만 그렇게 나눌 양이 되지 않는 경우가 많고 학습 데이터가 부족해서 10묶음 교차검증(10 Fold Cross Validation)같은 것 까지 하는 판국에 학습데이터를 잘게 쪼개서 모델을 만들 여유가 없게 됩니다.
지도학습에서는 학습데이터의 양이 항상 문제입니다. 언제나 부족하다고 느껴집니다. 사회과학이나 의료같은 문제에서는 대량의 학습데이터를 얻기 어려운 경우가 많으니까요.  이미지 인식같은 종류의 자연과학 데이터로 부터 문제를 해결하는 딥러닝하고는 입장이 많이 다릅니다. 100등분을 해서 나눌 여유도 없고 그렇게 나누면 각각의 모형들이 편향이 생기거나 분산이 커질 여지가 많습니다.
그래서 학습데이터를 분할해서 모델을 각각 만든다는 것이 다소 비현실적인 경우가 많습니다. (다 그런것은 아닙니다)

적은 데이터로 모델을 여러개 만드는 방법은 배깅이라는 명칭을 풀어보면 알 수 있습니다.

배깅이라는 단어는 영어사전에서 찾을 수 있는 단어는 아니고 부트스트랩 어그리게이팅 Bootstrap AGGregING의 약어 입니다.

풀어서 보면 부트스트랩(Bootstrap)은 샘플을 다시 샘플링하는 것을 부트스트래핑(Bootstraping)이라고 하고 어그리게이팅은 그냥 취합한다는 뜻입니다.  즉 부트스트래핑 기법으로 학습데이터를 뻥튀기하는 효과로 여러개의 트리를 만드는데 사용하고 그 결과들을 취합합니다. 그것을 배깅이라고 부릅니다.

부트스트래핑은 통계학의 샘플링에서 매우 중요하게 다루는 개념 중 하나입니다. 어렵고 내용이 길어지므로 설명은 다음기회에 해보겠습니다.

부트스트래핑(뻥튀기)을 조금 더 쉽게 설명하면
10000개의 레코드로 된 데이터세트가 있다고 가정합니다.
10000개의 레코드를 10000번 복원추출(resampling)을 합니다. 그러면 갯수는 똑같이 10000개가 됩니다. 다시 이 과정을 반복해서 100번을 해서 10000개 짜리 데이터세트를 100개를 만들고 이 것으로 각 모델들을 만듭니다. 그러면 100개의 조금씩 다른 모델을 만들 수 있습니다.

“10000개에서 10000개를 표본추출(샘플링)하면 똑같은 것 아닌가?”
라고 생각할 수 있습니다.  또
“똑같은 것 100개를 만들어서 각각 모델을 만들면 다 똑같은 것 아닌가?”
라고 생각할 수 있습니다.
복원추출을 했기 때문에 안 똑같습니다.
복원추출은 영어로 리샘플(Resample)이라고 합니다. 가지고 있는 학습데이터가 모집단으로 부터 표본추출한 데이터라고 볼 수 있습니다. 즉 모집단에 대한 샘플데이터입니다.  
표본추출한 것을 데이터 갯수 만큼 복원추출을 다시 하게 되면 어떤 것은 같은 것이 중복해서 뽑히고 어떤것은 아예 뽑히지 않게 됩니다.  이것이 배깅의 효과인데 이게 무슨짓인가 싶겠지만 이렇게 표본을 다시 복원추출하면 원래 모집단의 특성을 더 잘 반영되도록 재구성되는 경향이 있다고 알려져 있습니다. (중심극한정리와 비슷해 보이지만 다른 것입니다)

이 특성을 이용해서 조금씩 다른 모델들을 만들고 그것들의 결과를 취합하는 것입니다. 
“데이터가 전부 비슷하니 결과도 별차이가 없겠네”
라고 생각할 수 있겠지만 데이터가 빼곡해지는 효과가 있고 조금씩 다른 모델들이 투표를 하는 방식이므로 배깅으로 만들어진 앙상블 모델은 결과들에 대한 편차가 크지 않고 안정적인 결과를 보여지도록 향상됩니다.
학습데이터가 원래 편향이 있다면 그로 인한 편향문제까지는 해결하지는 못하지만 미지의 데이터(Unseen data)에 상당히 괜찮은 성능을 보이고 노이즈나 아웃라이어에 대해서도 강해지는 것으로 알려져 있습니다.
실제로 단순한 트리모형과 랜덤포레스트 모델을 만들고 비교를 해보면 차이를 알 수 있겠습니다.

유클리디안 거리 – Euclidean Similarity

유클리디안 유사도라고도 하는데 원래 유클리디안 거리(Euclidean distance)라고 말하는 것이 맞는 것 같습니다. 유클리디안 유사도는 다소 이상한 단어의 조합이라는 생각이 듭니다. 하지만 유클리디안 유사도라는 말도 많이 통용되므로 이 포스트에서도 그냥 그렇게 하기로 하겠습니다.

유클리디안 유사도(Euclidean similarity)는 유클리디안 거리를 구해서 두 벡터의 유사도로 사용한다는 뜻입니다.

유클리디안 거리는 직선 거리다

유클리디안 거리는 기하학적으로 볼 때 두 점의 직선거리를 구하는 것입니다.  또는 선형대수에서 주로 다루는 벡터 스페이스(Vector space)라고 불리는 선형 공간에서도 동일하게 최단 거리를 구하는 것을 말합니다.

코사인 유사도를 설명할 때 언급한 적이 있습니다만 유사도는 2개의 데이터만 가지고 계산해서 결과값을 뽑아내도 그것만으로는 아무짝에도 쓸모가 없습니다.

세상에 사람이 둘 만 남았다면 두 사람은 서로 닮은 걸까요? 안 닮은 걸까요? 모릅니다.

유사도는 다음과 같은 방식으로 주로 사용합니다.

  1. 여러 개의 데이터에서 주어진 것과 가장 가까운 것이 어떤것인가?
  2. 여러 개의  데이터에서 가장 가까운 것들끼리 묶어보자

유클리디안 거리는 데이터마이닝이나 기계학습에 익숙하시다면 K-means (K민즈, K중심값, K평균 이라고 번역합니다) 같은 것에서 사용하는 것을 본 적이 있을 것입니다. 유사도라는 것이 사실은 거리를 측정하는 방법(distance measurement)일 수 밖에 없습니다. 거리를 측정하는 방법을 어떤 것을 쓰느냐에 따라 이름을 무슨 무슨 유사도 이렇게 “유사도”라는 단어를 붙여서 부릅니다.

유클리디안 거리 구하기

유클리디안 거리를 구하는 방법은 간단하고 매우 쉽습니다.
피타고라스 정리를 알면 됩니다.

직각삼각형의 빗변의 길이를 구하는 것입니다.

위키피디아를 보면 거기에 그림을 아래와 같이 넣어놓고 설명해 놨습니다.

간단 한 수식이 있지만 그림으로 보니 눈이 아프군요.

그림에서 p와  q의 유클리디안 거리는 p와 q의 직선거리를 구하면 되는 것이고 가운데 만들어진 삼각형이 직각삼각형이니까 피타고라스 정리를 쓰면 빗변의 길이, 즉 대각선의 길이를 구할 수 있습니다. 이 대각선의 길이가 유클리디안 거리입니다.

결론은 삼각형의 빗변의 길이를 계산하면 됩니다.

참고로 피타고라스 정리가 3차원 이사의 고차원에서도 되는 건지 헷갈릴 수 있겠습니다.  당연히 3차원 이상에서도 적용이 됩니다.  3차원, 4차원, 5차원, …, R차원 다 됩니다.

수학자들이 증명해 놓은 것이 있습니다. 그냥 믿고 쓰시면 됩니다.

5차원인 경우를 예를 들어서 설명하면
아래와 같이 2개의 5차원 벡터가 있다고 하고

a = (1, 2, 3, 4, 5)
b = (2, 3, 4, 5, 6)

벡터의 멤버수가 5개씩이므로 둘 다 5차원 벡터입니다.  차원이 다르면 안됩니다. 맞춰 줘야지요.

각각 차원(축)을 맞춰서 순서때로 빼준 다음에 제곱해서 더한 다음에 루트를 씌우면 됩니다.

1번째 차원: 1 – 2를 계산해서 제곱 = 1
2번째 차원: 2 – 3을 계산해서 제곱 = 1
3번째 차원: 3 – 4를 계산해서 제곱 = 1
4번째 차원: 4 – 5를 계산해서 제곱 = 1
5번째 차원: 5 – 6를 계산해서 제곱 = 1

다 더한 다음에 루트

sqrt(1 + 1 + 1 + 1 + 1)

답은 2.236068 입니다.

R코드로는 이렇게 하면 됩니다.

a_vector <- c(1, 2, 3, 4, 5)
b_vector <- c(2, 3, 4, 5, 6)

dist(rbind(a_vector, b_vector))

추가로 유클리디안 거리는 양적인 것을 기반으로 하는 것이라서 축의 스케일이 맞지 않으면 이상한 측정이 됩니다.  축의 스케일을 맞춰야 할지 말아야 할지는 그때 그때 다릅니다.

이런 말이 나오면 항상 골치만 아픕니다만 어쨌든 뭐든 쉽게 쓸 수 있는 것은 없는 것 같습니다.

예를 들면 이런 경우입니다.

a = (1, 2, 3000000, 4, 5)
b = (2, 3, 4000000, 5, 6)
c = (3, 4, 5000000, 6, 7)

3번째 차원, 3번째 축의 값에 의해 가장 큰 영향을 받습니다. 다른 차원의 값들은 구실을 못하게 됩니다.

기회가 되면 다른 포스트에 스케일을 맞추는 여러가지 방법도 적어 보겠습니다.