코드 출처: http://scikit-learn.org/stable/auto_examples/tree/plot_iris.html#example-tree-plot-iris-py
저번 포스팅이 data를 tree를 생성하기에 적합하게 데이터를 load하는 것에 관한 것이었다면 이번 포스팅은 tree를 생성하고 그것을plotting 하는 것까지의 내용을 담고 있다. 또한 그 과정에서 나타나는 다양한 python 사용법에 대한 설명도 함께 정리한다.
#########################################
print(__doc__)
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import load_iris
from sklearn.tree import DecisionTreeClassifier
# Parameters
n_classes = 3
plot_colors = "bry"
plot_step = 0.02
# Load data
iris = load_iris()
#########################################
Decision tree를 생성하기 전에, data를 불러오고 그래프를 그리기 위한 설정을 하는 부분이다. plot_colors = "bry"는 코드 뒷부분에 'blue', 'red', 'yellow' 라는 색을 나타내기 위해 쓰이며 plot_step은 축의 단위를 설정해주는 부분이다.
#########################################
for pairidx, pair in enumerate([[0, 1], [0, 2], [0, 3],
[1, 2], [1, 3], [2, 3]]):
# We only take the two corresponding features
X = iris.data[:, pair]
y = iris.target
#########################################
enumerate는 입력값으로 시퀀스자료형(리스트, 터플, 문자열)을 입력으로 받아 enumerate객체를 리턴한다. enumerate객체는 첫번째로 그 순서값, 두번째로 그 순서값에 해당되는 시퀀스 자료형의 실제값을 갖는 객체이다. (출처: https://wikidocs.net/32) iris의 feature dimension은 4이다. 4개의 feature를 2개씩 짝지어 비교하여(4C2) 그래프를 그리고 그 그래프들을 한 화면에 나타나기 위해 enumerate 함수를 사용했다.
X = iris.data[:, pair]의 경우 하나의 pair에 들어가는 값이 만약 [0, 2] 라면 첫 번째, 세 번째 feature만 선택해서 X에 할당하겠다는 의미이다.
#########################################
# Shuffle
idx = np.arange(X.shape[0])
np.random.seed(13)
np.random.shuffle(idx)
X = X[idx]
y = y[idx]
# Standardize
mean = X.mean(axis=0)
std = X.std(axis=0)
X = (X - mean) / std
# Train
clf = DecisionTreeClassifier().fit(X, y)
#########################################
현재 X(Data), Y(Target)은 class 순서대로 정렬이 되어 있으므로 shuffle을 해준다. 사실 shuffle을 하나 하지 않으나 plotting 결과는 동일하다. 꽃받침과 꽃잎은 길이의 scale 차이가 있으므로 표준화 작업을 해준다.
DecisionTreeClassifier는 코드 윗 부분에서 이미 import해서 바로 쓸수 있고 fit에는 (Data, Target) 형식으로 입력을 해주면 Decision Tree를 return 한다.
#########################################
# Plot the decision boundary
plt.subplot(2, 3, pairidx + 1)
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, plot_step),
np.arange(y_min, y_max, plot_step))
Z = clf.predict(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)
cs = plt.contourf(xx, yy, Z, cmap=plt.cm.Paired)
#########################################
plt.subplot(행, 열, index) 로 지정해주면 해당 index 위치에 plot이 생성된다. x_min, x_max 부분은 plot의 처음과 끝 값을 지정해주기 위한 부분이다.
np.meshgrid(x(1d_array), y(1d_array) 함수는 두 개의 2D matrix들을 return한다. xx행렬은 x가 y의 dimension 크기의 행의 개수 만큼 반복되어 있고 yy행렬은 y가 x의 dimension 크기의 열의 개수 만큼 반복 되어 있다.
xx.ravel() 함수는 행렬의 1행부터 순차적으로 원소 값을 불러와서 1차원 array를 만드는 함수이다. Reshape 함수를 사용하여 Z를 xx와 같은 차원으로 만들어 준다.
clf에는 위에서 형성한 decision tree가 할당되어 있다. predict 함수를 쓰면 새로운 인풋에 대해 그 인풋이 갖는 class가 어떤 값인지 return한다.
contourf 는 xx, yy가 각각 x축, y축 좌표에 해당하며 Z에 해당하는 값을 cmap에서 지정해준 색으로 mapping해주는 함수이다. 이 경우 xx, yy가 매우 촘촘하게 되어 있어서 색칠을 하는 역할을 한다. (그런데 왜 2D matrix가input이 되는 지는 좀 더 살펴 봐야 할 거 같다.)
#########################################
plt.xlabel(iris.feature_names[pair[0]])
plt.ylabel(iris.feature_names[pair[1]])
plt.axis("tight")
# Plot the training points
for i, color in zip(range(n_classes), plot_colors):
idx = np.where(y == i)
plt.scatter(X[idx, 0], X[idx, 1], c=color, label=iris.target_names[i],
cmap=plt.cm.Paired)
plt.axis("tight")
plt.suptitle("Decision surface of a decision tree using paired features")
plt.legend()
plt.show()
#########################################
plt.axis("tight")는 어떤 기능인지 좀 더 조사를 해봐야 한다.
plt.scatter는 위에서 색칠한 영역에 training data를 표시해준다. 위의 코드를 전부 실행하면 다음과 같은 결과를 얻는다.