Decision Tree 실습 - 지니 계수 및 서울 지역 다중 분류 (2)

2022. 1. 19. 21:00AI/ML

이 포스트는 허민석님의 유튜브 머신러닝 내용을 정리한 글입니다. 실습 코드는 도서 나의 첫 머신러닝/딥러닝에서 발췌해왔습니다. 실습 코드와 자료는 링크의 Github에서 볼 수 있습니다

이번 포스트에서는 서울 지역의 위치 정보(위도, 경도)로 임의의 지역을 한강을 기준으로 하는 네 지역(강북, 강남, 강동, 강서)로 분류하는 Decision Tree 모델을 생성하고 학습해보겠습니다.

모든 머신러닝 문제는 문제 정의 및 데이터 수집에서 출발합니다. 바로 위에서 말했듯이 우리는 이번 실습에서 서울 지역의 위치 정보(위도, 경도)를 데이터로 서울을 한강을 기준으로 하는 네 지역(강북, 강남, 강동, 강서)로 분류하고, 임의의 지역의 위치 정보를 테스트 데이터로 삼아 분류해보겠습니다. 서울의 위치 정보는 구(district)와 동(dong)으로 나누었으며 district_dict_list는 모델 학습에, dong_dict_list는 테스트에 사용합니다. 리스트들을 데이터 프레임으로 만들어 저장한 다음, 두 데이터 레이블의 분포를 확인합니다.

레이블의 분포가 각각 5개로 동일한 것을 알 수 있습니다.

이제 데이터를 시각화해보겠습니다. 상위 5개의 데이터의 확인해보고, 파이썬의 데이터 시각화 라이브러리 matplotlib.plyplot을 활용해 데이터 분포를 2차원 그래프에 그려보겠습니다. 이전 포스트에서는 상위 데이들을 확인해보고 학습에 필요한 특징인지를 판단 후 제거, 수정하는 데이터 전처리 과정을 거쳤는데, Decision Tree는 각 특징을 독립적으로 사용하기 때문에 이번 모델에서는 별도의 데이터 전처리 과정이 필요하지 않습니다.

fig_reg = 회귀선 제거, scatter_kws = 좌표 상 점의 크기, https://seaborn.pydata.org/generated/seaborn.lmplot.html

이제 데이터를 학습 데이터(train_df, X_train, y_train)와 테스트 데이터(test_df, X_test, y_test)로 나눕니다. 단, 학습과 테스트에는 구(district)와 동(dong)의 실제 지명은 중요하지 않으므로, 삭제한 다음 나눕니다.

이제 Decision Tree 모델을 생성해보겠습니다.  preprocessing.LabelEncoder()로 생성된 le를 fit_transform()하면 중복된 레이블들이 하나로 통합된 One-Hot Encoding된 레이블들로 인코딩됩니다. 이제 인코딩된 레이블과 학습 데이터를 DecisionTreeClassifier에 넣어 모델을 생성해보겠습니다. 사실 Decision Tree의 모델은 사이킷런에 이미 다 구현되어 있으며 tree.DecisionTreeClassifier().fit(학습 데이터와 인코딩 된 레이블)을 통해 모델을 생성할 수 있습니다. DecisionTreeClassifier()에는 다양한 매개변수들이 존재하는데, 이 매개변수들의 쓰임새와 사용 방법은 아래에서 알아보겠습니다. 이제 학습된 모델을 시각화해보겠습니다. 2차원 그래프에 deicision boundary를 그리고, 다른 색상으로 표현하여 구간을 구분해보겠습니다.

구간을 나눠 모델을 시각해보니, 학습 데이터에만 아주 잘 맞게끔 학습된 과적합 상태임을 알 수 있습니다. 

학습된 모델을 시각화해보니, 데이터별로 색상에 맞게 decision boundary가 잘 형성된 상태임이 보입니다. 하지만 과연 좋은 모델이라고 할 수 있을까요? 빨간색으로 분류된 강북 지역의 경우, decision boundary가 둘로 나뉘어 있습니다. 이 점이 말하는 바는 즉 모델이 학습 데이터에만 너무 딱 맞게끔 학습하다보니, 과적화된 모델이 생성되었다는 의미입니다. 예를 들어 가장 높은 latitude를 갖는 강북 지점에서 longitude를 살짝만 낮추면, 사실 강북에 가깝다고 보는 것이 맞지만 이 모델에서는 강동으로 분류할 것 입니다. 다른 말로는 학습에는 없는 임의의 데이터에 대해서는 정확도가 낮을 것 입니다. 이전 Decision Tree 포스트에서 설명했듯 Decision Tree는 과적합되기 매우 쉬운 모델입니다. 모든 특징을 독립적으로 사용하기 때문에 하나의 데이터 포인트의 영향이 모델에 미치는 영향이 큽니다. 이는 이전 SVM 모델에서 gamma값이 커지게 되면 decision boundary가 작아지며 데이터에 맞춰 구부러지는 것과 같습니다. 이제 DecisionTreeClassifier()의 매개변수들이 필요한 차례입니다. tree.DecisionTreeClassifier()의 매개변수들을 잘 이용하면 과적합을 방지할 수 있는데, 이번에는 4가지의 매개변수를 이용하여 모델의 과적합을 해소해보겠습니다. 쓰이는 매개변수들은 다음과 같습니다.

모델 과적합을 방지하고자 DecisionTreeClassifier()에 사용되는 매개변수

 max_depth, 트리의 최대 한도 깊이를 제한하는 매개변수입니다. 트리의 깊이가 깊다는 의미는 특징들을 세세하게 분류하고 있다는 의미입니다. 스무고개에서 세 네번만에 정답을 맞출 수도 있지만, 스무번까지 질문을 하면 정답의 폭이 굉장히 좁아집니다. 정답의 폭이 굉장히 좁다는 것은 다르게는 과적합되어 있다는 의미로 해석할 수 있습니다. 보다 일반적인 decision boundary를 위해, 트리의 최대 한도 깊이를 줄이는 것 또한 좋은 방법입니다. max_depth와 마찬가지로 min_samples_split와 min_sample_leaf를 설정하며, random_state는 사실 모델의 과적합과는 별개로 난수 seed를 직접 설정하여 같은 값에 대해 동일한 학습 결과를 만드는 매개변수입니다. 이제 이 매개변수들을 활용해 과적합을 방지한 모델을 학습해보겠습니다.

매개변수를 활용해 새로 학습한 모델. 조금 더 좋은 decision boundary로 분류되어 있습니다.

학습된 모델을 시각화해보니 실제 임의의 데이터들을 넣어도 괜찮을법한 좋은 모델이 된 것으로 보입니다. 이제 학습 트리를 시각화해보겠습니다. Decision Tree 시각화에 graphviz를 사용할 것이며 사용된 매개변수에 대한 설명은 아래 사진에서 확인할 수 있습니다.

out_file: 파일로 변환의 여부. feature_names: 사용되는 특징들의 이름. filled: 그림에 색상을 넣는지의 여부. rounded: 반올림 여부. special_characters: 특수문자 사용 여부
gini: 불순도 척도, 낮을 수록 순도가 높음. samples: 노드 안에 있는 데이터들의 개수. values: 레이블 별 데이터의 개수. class: 레이블

마지막으로 생성한 모델을 테스트해서 정확도를 측정하고, 실제 값과 예측 값을 비교해보겠습니다. 정확도가 1.0인 것을 보니 모든 예측이 맞았음을 알 수 있습니다. 실제로 Decision Tree는 각각의 특징들을 독립적으로 사용하기 때문에 데이터의 크기가 너무 크지만 않다면, 매우 높은 정확도를 보입니다.