'기계학습 모델의 의사결정 경계 시각화하기'에 해당되는 글 1건

  1. 2020.08.02 [Python] 등고선 그래프 (contour plot)로 모델의 의사결정 경계(Decision Boundary) 시각화하기

이번 포스팅에서는 numpy의 meshgrid()와 matplotlib의 contourf(xx, yy, Z) 함수를 사용하여 Random Forest Classifer 의 의사결정 경계(Decision Boundary)를 시각화해보겠습니다.  


(1) iris dataset 의 species 를 분류할 수 있는 Random Forest 분류 모델 훈련

(2) numpy의 meshgrid() 로 설명변수 공간의 좌표들을 생성하여 Random Forest 분류 모델로 예측

(3) matplotlib의 contourf() 함수로 Random Forest Classifier 예측 결과 시각화(채우기)

    : 의사결정 경계(Decision Boundary)

(4) iris dataset 의 species 의 산점도를 겹쳐서 그리기


의 순서로 진행해보겠습니다. 


  (1) iris dataset 의 species 를 분류할 수 있는 Random Forest 분류 모델 훈련


먼저 iris dataset 을 업로드하고 어떻게 생긴 데이터인지 살펴보겠습니다. 



#%% import libraries

import pandas as pd

import numpy as np

import matplotlib.pyplot as plt

import seaborn as sns


#%% iris dataset

iris = sns.load_dataset('iris')

iris.info()

<class 'pandas.core.frame.DataFrame'>

RangeIndex: 150 entries, 0 to 149

Data columns (total 5 columns):

 #   Column        Non-Null Count  Dtype  

---  ------        --------------  -----  

 0   sepal_length  150 non-null    float64

 1   sepal_width   150 non-null    float64

 2   petal_length  150 non-null    float64

 3   petal_width   150 non-null    float64

 4   species       150 non-null    object 

dtypes: float64(4), object(1)

memory usage: 6.0+ KB



iris.groupby('species').size()

Out[1]: 

species

setosa        50

versicolor    50

virginica     50

dtype: int64



#%% scatter plot by 'species'

sns.scatterplot(x='petal_length', 

                y='petal_width', 

                hue='species', 

                style='species', 

                s=100, 

                data=iris)

plt.show()



이번 포스팅의 시각화 예에서는 'sepal_length', 'sepal_width' 의 두개 칼럼을 설명변수로 사용하고, 'species'를 목표변수로 하여 붓꽂 종류(species)를 Random Forest Classifier 로 분류하는 모델을 만들어보겠습니다. 


(* 이번 포스팅의 주 목적은 모델의 의사결정경계 시각화이므로, 모델링 단계에서의 train/test set 분할, 모델 성과 평가 등은 생략합니다.)



#%% Classification using Random Forest

from sklearn.ensemble import RandomForestClassifier


X = np.array(iris[['petal_length', 'petal_width']])

y = iris['species']

y = np.where(y=='setosa', 0, np.where(y=='versicolor', 1, 2))


rfc = RandomForestClassifier(max_depth=2, n_estimators=200, random_state=1004)

rfc.fit(X, y)

 



  (2) numpy의 meshgrid() 로 설명변수 공간의 좌표들을 생성하여 

      Random Forest 분류 모델로 예측


위의 (1)번에서 적합된 Random Forest Classifier 모델을 사용해서 붓꽂 종류를 예측하고자 할때는 predict() 라는 메소드를 사용하면 됩니다. 



#%% predict

pred = rfc.predict(X)

print(pred == y)

[ True  True  True  True  True  True  True  True  True  True  True  True

  True  True  True  True  True  True  True  True  True  True  True  True

  True  True  True  True  True  True  True  True  True  True  True  True

  True  True  True  True  True  True  True  True  True  True  True  True

  True  True  True  True  True  True  True  True  True  True  True  True

  True  True  True  True  True  True  True  True  True  True False  True

  True  True  True  True  True False  True  True  True  True  True False

  True  True  True  True  True  True  True  True  True  True  True  True

  True  True  True  True  True  True  True  True  True  True False  True

  True  True  True  True  True  True  True  True  True  True  True False

  True  True  True  True  True  True  True  True  True  True  True  True

  True False False  True  True  True  True  True  True  True  True  True

  True  True  True  True  True  True]

 



(a) 이제 x 축('petal_length')과 y 축('petal_width')의 최소값, 최대값을 구하고, (b) 이들 x축과 y축의 최소값 ~ 최대값 사이의 구간을 h = 0.01 단위의 간격으로 좌표를 생성하여, (c) np.meshgrid()로 이들 x축과 y축의 h=0.01 단위의 좌표 벡터를 가지고 격자 행렬을 생성합니다. 

(d) 이렇게 생성한 격자 행렬 좌표값들에 대해 Random Forest Classifier 훈련된 모델의 predict() 메소드로 예측을 하여 contour plot의 높이에 해당하는 Z 값을 구합니다. 



# create coordinate matrices from x_min~x_max, y_min~y_max coordinates

h = 0.01

x_min, x_max = X[:, 0].min() - .1, X[:, 0].max() + .1

y_min, y_max = X[:, 1].min() - .1, X[:, 1].max() + .1

xx, yy = np.meshgrid(np.arange(x_min, x_max, h), np.arange(y_min, y_max, h))

XY = np.c_[xx.ravel(), yy.ravel()]


XY.shape

Out[4]: (158600, 2)


# predict

pred_cls = rfc.predict(XY)


# align the shape of Z with xx

Z = pred_cls.reshape(xx.shape)

 




  (3) matplotlib.contourf() 로 Random Forest Classifier 예측 결과 시각화

      -->  (4) iris dataset 의 species 의 산점도를 겹쳐서 그리기


위의 (2)번에서 만들어놓은 x, y 격자 행렬 좌표값별로 Random Forest Classifier 예측 결과를 matplotlib의 confourf() 함수로 시각화 (채우기)를 하면 아래와 같습니다. 아래에 색깔로 구분된 영역들과 경계선이 바로 Random Forest Classifier가 훈련 데이터로 부터 학습한 species 분류 의사결정 경계(Decision Boundary)가 되겠습니다. 



# Random Forest Classifier: Decision Boundary

plt.contourf(xx, yy, Z)

plt.axis('off')




좀더 보기에 쉽도록 위의 의사결정경계 그래프 위에다가 학습에 사용했던 iris species 값들을 species별로 marker를 구분하여 겹쳐서 다시 한번 시각화해보겠습니다. 



plt.contourf(xx, yy, Z)

plt.axis('off')


sns.scatterplot(x='petal_length', 

                y='petal_width', 

                hue='species', 

                style='species', 

                s=100, 

                data=iris)

plt.title('Decision Boundary by Random Forest', fontsize=14)

plt.show()



 



iris species 별 산점도를 의사결정경계 배경 위에 겹쳐 그릴 때 seaborn.scatterplot() 대신에 아래의 코드처럼 matplotlib.scatter() 과 for loop을 사용해서 그릴 수도 있습니다. 



plt.contourf(xx, yy, Z)

plt.axis('off')


# or plot data points using matplotlib and for loop

N = 50

CLS_NUM = 3

markers = ['o', 'x', 's']

for i in range(CLS_NUM):

    plt.scatter(X[i*N: (i+1)*N, 0], X[i*N:(i+1)*N, 1], s=40, marker=markers[i])


plt.title('Decision Boundary by Random Forest', fontsize=14)
plt.show()



많은 도움이 되었기를 바랍니다. 

이번 포스팅이 도움이 되었다면 아래의 '공감~'를 꾹 눌러주세요. :-)



반응형
Posted by Rfriend

댓글을 달아 주세요