Hello Computer Vision

[머신러닝]랜덤 포레스트(Random Forest)에 대한 이해, 파이썬 코드 본문

머신러닝

[머신러닝]랜덤 포레스트(Random Forest)에 대한 이해, 파이썬 코드

지웅쓰 2023. 1. 28. 15:51

출처 : https://www.youtube.com/watch?v=lIT5-piVtRw

머신러닝 쪽에서 아주 유명한 앙상블 기법이며 정확도가 아주 높은 기법 중 하나이다.

활용할 데이터가 어떤 분포를 가질 지에 대한 가정이 필요없으며(비모수적 방법) 훈련시간이 적어 다양하게 활용된다.

또한 의사결정나무의 단점들을 보완한 방법이다.(과적합, 이상치민감)

 

랜덤포레스트의 핵심적인 아이디어는 Diversity, Random을 확보하는 것이다.

Diversity는 Bootstrap, Bagging을 이용함으로서 충족시킨다. 이에 대한 설명은 이전 글에 간략하게 설명해놓았다 Diversity에대한 설명

Random을 충족시키기 위해서는 각각의 의사결정나무를 구축시 변수를 무작위로 선택한다.

이를 잘 설명해주는 이미지가 있어서 가져와봤다. 이미지출처

그림 왼쪽부터 분석해보자면 기존 데이터셋에서 Bootstrap을 이용해 데이터를 복원추출한다.

그리고 이 추출된 데이터에서 또한 랜덤으로 데이터를 추출해 Tree를 만든다. 그림에서는 같은 모양의 트리가 나왔지만

실제로는 다양한 모습을 가질 것이다. 이렇게 랜덤으로 뽑힌 데이터를 이용해 Tree를 만드는 과정은 다음과 같다.

1. 원래 변수들 중 모델 구축에 쓰일 입력 변수를 무작위로 선택

2. 선택된 입력 변수 중에 분할된 변수를 선택

3. 이러한 과정을 나무가 full grown tree가 될 때까지 반복한다.

이렇게 전체 데이터셋에서 일부만 이용하는 것은 Random Subspace를 활용하는 것과 같은데 이는 랜덤포레스트의 Random을 잘 충족시킨다고 볼 수 있다.

 

각각의 Tree는 과적합 될 수 있지만 다양한 Tree를 학습한 랜덤포레스트의 경우 Tree의 수가 많을 수록 Strong Law of Large Number에 의해 과적합 되지 않고 에러는 limiting value에 수렴

$Generalization error  ≤ \frac{p(1 - s^{2})}{s^{2}}$ 

에러의 upper bound를 나타낸 것이다. (에러가 낮을 수록 좋으므로 upper bound가 작을 수록 좋다)

p : Decision Tree간의 평균 상관관계

s : 올바르게 예측한 tree수와 잘못 예측한 tree수 차이의 평균

분자에 들어간 p값은 작을 수록 좋다. --> Tree사이의 상관관계가 없을 수록 더 좋다.(핵심 아이디어인 Diversity, Random 잘 수행할 수록 낮다)

 s가 클 수록 좋다 --> 올바르게 예측한 트리의 수 차이가 클 수록 좋다.(개별 트리의 정확도가 높을수록 s증가)

 

변수에 대한 중요성 파악해보기

처음에 우리가 랜덤포레스트 모델을 만들 때 개별 모델은 전체데이터셋에서 복원추출을 이용해 만들어진 모델이다.

이 모델을 만들 때 사용되지 않은 데이터들이 다수 있을 것이다.(복원추출 했기 때문에) 이러한 데이터들을 Out of bag(OOB)라고 한다.

그렇다면 이러한 OOB데이터들을 활용해 test를 해보고 나온 error를 OOB error라고 한다. --> 각 트리마다 OOB error계산이 가능하다.($r_{i}, i = 1,2,3,4..t$)

w그리고 우리의 목적은 각 데이터의 중요도를 파악해보는 것이었다. 

위에 이미지를 다시 한번 가져와봤다. 1번 트리에서 V9 변수의 중요도를 알고 싶다고 했을 때 V9의 값을 임의로 뒤섞는다.

그리고 그리고 나서 다시 1번 Tree에 대해 OOB error를 측정해보는 것이다. ($e_{i} i = 1,2,3,4,...t$)

r기존 1번 트리의 OOB error와 임의로 섞은 트리의 OOB error의 차이를 d 라고 하였을 때 (직관적으로 뒤섞은 트리의 에러가 더 클 것이다)

$\bar{d} = \frac{1}{t}\sum^{t}_{i=1}{d_{i}}, S^{2}_{d} = \frac{1}{t-1}\sum^{t}_{i=1}({d_{i} - \bar{d}}^{2})$

$X_{i}$변수의 중요도 :  $ v_{i} = \frac{\bar{d}}{s_{d}}$

이렇게 t개의 트리에서 나온 각각의 차이의 평균과 표준편차를 활용하여 변수의 중요도를 구하는 것이다.(에러가 클 수록 해당 변수가 중요하다는 것이다)

여기서 표준편차로 나눈 이유는 scaling역할을 하는데 표준편차가 크면 고려해볼 필요가 있으므로 약간의 페널티를 주는 것이라 할 수 있다.

(복원추출을 하였기 때문에 각 트리마다 원하는 변수가 없을 수도 있는데 해당 트리에 대해서는 그냥 넘어가는건가..?)

 

중요 파라미터: Tree의 개수(기본값 100), 노드 분할 시 무작위로 선택되는 변수의  수

 

파이썬 코드

데이터셋은 sklearn에 내장된 breast cancer 데이터셋을 활용했다. 전체코드는 제 깃헙에서 확인할 수 있습니다.

 

GitHub - JiWoongCho1/hello-machinelearning: repository of machine learning i studied

repository of machine learning i studied. Contribute to JiWoongCho1/hello-machinelearning development by creating an account on GitHub.

github.com

kfold를 이용해 데이터를 나눠준 후 훈련을 해보았고 성능은 괜찮네요. 

kfold = KFold(n_splits = 5, shuffle = False)
rand_clf = RandomForestClassifier(max_depth = 5) #나무
acc_list = []

for i, (train_index, valid_index) in enumerate(kfold.split(x)): 
    train_data = x_train[train_index]
    train_label = y_train[train_index]
    valid_data = x_val[valid_index]
    valid_label = y_val[valid_index]
    
    model = rand_clf.fit(train_data, train_label)
    acc = model.score(valid_data, valid_label)
    acc_list.append(acc)
    
    print('{}번째 Fold'.format(i+1), '정확도:{}'.format(acc))
avg = sum(acc_list) / 5

print(avg)
1번째 Fold 정확도:0.9333333333333333
2번째 Fold 정확도:1.0
3번째 Fold 정확도:0.9333333333333333
4번째 Fold 정확도:0.9666666666666667
5번째 Fold 정확도:0.9666666666666667
0.96

그리고 변수 중요도 또한 가볍게 알 수 있습니다. 

plt.figure(figsize = (10,10))
sns.barplot(x = rand_clf.feature_importances_, y = dataset.feature_names)