본문 바로가기
파이썬(Python), 머신러닝, 딥러닝

(머신러닝 with 파이썬) 붓꽃 품종 예측 모델 만들기 (Decision Tree Classifier) / 혼동행렬, 시각화(graphviz) 추가 / Gini 계수(Gini 불순도)

by 굳세라(goodsarah) 2023. 8. 15.
728x90
반응형

이번에 해볼 것은 분류 문제로 유명한 데이터인 붓꽃(iris) 데이터를 활용하여 분류 예측 모델을 만들어보는 것입니다.

 

이때 사용할 모델은 분류 모델 중 가장 기초적이지만, 설명력이 높은 결정나무(Decision Tree)를 활용하는 것입니다.

 

1. 데이터 설명

 

데이터는 총 3 종류의 붓꽃(Versicolor / Setosa / Virginica) 품종에 대한 각 특징들이 기록되어 있습니다.

 

데이터의 일부분을 추출해서 보면 아래와 같이 나타낼 수 있습니다.

여기서 label은 붓꽃의 품종을 뜻하며,   0 : Versicolor  /   1 : Setosa  / 2 : Virginica 입니다.

 

각 품종과 함께 수집된 변수(features)는 

a) sepal length : 꽃받침의 길이 (cm)

b) sepal width : 꽃받침의 넓이 (cm)

c) petal length : 꽃잎의 길이 (cm)

d) petal width : 꽃잎의 넓이 (cm)

 

입니다. 

 

2. 결정나무 분류(Decision Classifier)를 활용한 분류모델 만들기 

 

1) 필요한 라이브러리를 불러옵니다. 

 이번 분석에서 필요한 라이브러는

 

 a) from sklearn.datasets import load_iris : 사이킷런(Scikit-Learn)에 내장된 iris 데이터

 b) from sklearn.tree import DecisionTreeClassifier : 결정나무 분류기 

 c) from sklearn.model_selection import train_test_split 

    : 데이터를 모델 훈련용(train) 과 테스트(test) 용으로 나누는 라이브러리   

 d) import pandas as pd : 데이터 처리에 필요한 pandas 라이브러리

1
2
3
4
5
#필요한 라이브러리 불러오기
from sklearn.datasets import load_iris
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import train_test_split
import pandas as pd
cs

 

2) 다음은 데이터를 로드하고, 데이터에 대해 알아보는 과정을 거치겠습니다.

 

* 이때, iris.target 은 iris 데이터에서 label로 표현된 iris의 품종을 말합니다.

* 여기서 각 숫자는 위에서 언급했던 대로 

  0 : setosa / 1 : versicolor / 2 : virginica 입니다

1
2
3
4
5
6
7
8
9
10
# 붓꽃 데이터 세트를 로딩
iris = load_iris()
 
# scikit learn에 내장된 iris.data는 Iris 데이터 세트에서 피처(feature)만으로 된 데이터를 numpy로 가지고 있습니다. 
iris_data = iris.data
 
# iris.target은 붓꽃 데이터 세트에서 레이블(결정 값) 데이터를 numpy로 가지고 있습니다. 
iris_label = iris.target
print('iris target값:', iris_label)
print('iris target명:', iris.target_names)
cs

 

3) 이제 array의 형태로 되어 있는 데이터를 pandas 라이브러리의 DataFrame 기능을 활용하여 데이터프레임으로 만들어줍니다.

1
2
3
4
# 붓꽃 데이터 세트를 자세히 보기 위해 DataFrame으로 변환합니다. 
iris_df = pd.DataFrame(data=iris_data, columns=iris.feature_names)
iris_df['label'= iris.target
iris_df.head(3)
cs

 

1
iris_df.info()
cs

 

info() 함수를 활용하면 데이터의 전체 정보를 쉽게 확인할 수 있습다.

 

데이터는 총 150개의 관측치 (entries)가 있으며 

 

Column은 septal length / sepal width / petal length / petal width / label 로 구성되어 있습다. 

Non-Null Count를 봤을때 모든 데이터는 결측치가 없으며

 

4개의 변수(features)는 데이터타입이 실수형인 float64이며

품종을 나타내는 label 은 데이터타입이 정수형인 int64 입니다.

 

 

4) 훈련용(train)과 테스트(test)용 데이터로 나누기

 

1
2
3
4
5
6
# 데이터를 train 과 test로 나누기
X_train, X_test, y_train, y_test = train_test_split(iris_data, iris_label, 
                                                    test_size=0.2, random_state=11)
 
print("train 데이터의 갯수 : ", len(X_train))
print("test 데이터의 갯수 : ", len(X_test))
cs

 

위 코드에서는 train_test_split 이라는 함수를 사용해서 데이터를 훈련용과 테스트용으로 나눕니다.

 

이때,

a) iris_data는 위에서 규정한대로 features로 구성된 데이터로 X(대문자 x / 행렬을 의미)로 표현하며,

b) iris_label은 붓꽃의 품종을 나타내는 열을 의미합니다.

c) test_size = 0.2 는 전체 데이터의 크기에서 테스트 데이터의 비율(0.2 = 20%)을 의미하며

d) random_state = 11 은 위에서 말한 비율대로 데이터를 나눌때 난수(random number)를 넣어서 분류하는 것을 의미합니다.

 

 결과는 아래와 같으며

 

결국 총 150개의 데이터 중 20%인 30개가 test 데이터로 분류되고, 나머지 80%인 120개는 train 데이터로 분류됩니다.

 

5) 결정나무 분류기 생성

 

1
2
3
4
5
# DecisionTreeClassifier 객체 생성 
dt_clf = DecisionTreeClassifier(random_state=11)
 
# 학습 수행 
dt_clf.fit(X_train, y_train)
cs

* 결정나무 분류기의 객체를 dt_clf로 생성하며

* 분류된 데이터를 넣어서 학습을 수행한다.

  이때, 학습을 수행하여 모델을 만들기에 train 데이터를 사용합니다

 

 

6) 생성된 분류기를 통해서 test 데이터 예측

 

1
2
3
4
# 학습이 완료된 DecisionTreeClassifier 객체에서 테스트 데이터 세트로 예측 수행. 
pred = dt_clf.predict(X_test)
from sklearn.metrics import accuracy_score
print('예측 정확도: {0:.4f}'.format(accuracy_score(y_test,pred)))
cs

 

a) 이제 X_test를 모델에 넣어서 예측값(predicion value)을 만듭니다.

 * 이때 예측값이란, X(feautres)를 모델에서 나오는 leaf node를 활용해 각 관측치들이 어떤 종류의 붓꽃일지에 대한 확률을 구하고, 그 중 확률 값이 큰 쪽의 클래스를 택하는 것을 말합니다.

b) 다음은 사이킷런에서 accuracy_score(예측 정확도)를 도출해주는 함수를 불러오고, 이를 통해 예측의 정확도를 도출합니다.

도출된 예측의 정확도는 0.9333으로 93.33%의 정확도로 예측을 하였다는 것을 의미합니다.

 

 

그렇다면, 각 예측된 샘플은 어떤 과정을 거쳐 나오는지 알아보자

1
2
3
4
5
6
7
sample_index = 0  # 예측하고자 하는 샘플의 인덱스
sample = X_test[sample_index].reshape(1-1)
predicted_class = dt_clf.predict(sample)
probability = dt_clf.predict_proba(sample)
 
print("예측 클래스:", predicted_class)
print("각 클래스에 대한 확률값:", probability)
cs

위와 같이 예측하고자 하는 샘플(test 샘플)의 인덱스를 입력하고 모델에 넣고 각 확률을 구하면 아래와 같습니다.

 이를 해석해보면

0번째의 인덱스 (파이썬은 첫번째 인덱스가 0부터 시작한다)의 test 데이터의 예측값은 2(Virginica) 이며,

 

[0. 0. 1.]의 첫번째 0은 Versicolor 일 확률이 0% 임을 / 두번째 0은 Setosa 일 확률이 0% 임을 / 세번째 0은 Virginica일 확률이 100%임을 나타내고,

 

이러한 과정을 거쳐 최종적으로 0번째 인덱스의 예측값이 2(Virginica)임을 확인할 수 있습니다.

 

 

7) 혼동행렬(Confusion Matrix)를 활용하여 결과 해석

 

사이킷런 패키지에서 내장된 confusion_matrix 함수를 활용해 함수를 만들것입니다.

이때, 시각화를 위해 seaborn 라이브러리와 matplotlib의 pyplot을 활용해서 결과를 혼동핼렬로 시각화 해봅시다

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from sklearn.metrics import confusion_matrix
import seaborn as sns
import matplotlib.pyplot as plt
 
# 예측 결과와 실제 레이블 비교
y_pred = dt_clf.predict(X_test)
cm = confusion_matrix(y_test, y_pred)
 
# 클래스 이름 가져오기
class_names = iris.target_names
 
# 혼동 행렬 시각화
plt.figure(figsize=(86))
sns.heatmap(cm, annot=True, fmt="d", cmap="Blues", xticklabels=class_names, yticklabels=class_names)
plt.xlabel("Predicted Labels")
plt.ylabel("True Labels")
plt.title("Confusion Matrix")
plt.show()
cs

 

결과는 위와 같이 나옵니다. 

 

이를 해석해보면, 혼동행렬의 1x1 / 2x2 / 3x3   에 표시된 숫자는  실제 각 붓꽃의 품종을 결정나무 분류기 모델이 맞춘 결과를 의미합니다.

 

test 데이터에는 setosa가 총 9개 / versicolor 총 10개 / virginica가 총 11개(2 +9)개 있었으며

이 중 virginica의 경우에만 오분류된 경우가 있습니다.(3행 2열 )

 

즉, 전체 30개 중 2개 만 오분류 되었으며 나머지 28개는 제대로 분류되었습니다.

이를 정확도(Accuracy)의 정의에 의해 표현해보면,  93.33%  (= 28/30 *100 ) 입니다. 

 

 

8) 결정나무 분류 결과를 graphviz를 통해 시각화하기

 

이번에도 사이킷런에 내장된 export_graphviz를 통해 분류나무의 결과를 시각화 해보겠습니다.

 

코드는 아래와 같습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
from sklearn.tree import export_graphviz
import graphviz
 
# Graphviz 시각화
dot_data = export_graphviz(dt_clf, out_file=None
                           feature_names=iris.feature_names,  
                           class_names=iris.target_names,  
                           filled=True, rounded=True,  
                           special_characters=True)  
 
graph = graphviz.Source(dot_data)
graph.render("iris_decision_tree")  # 그래프를 파일로 저장
graph.view()  # 그래프 시각화
cs

구글 코랩으로 실행할 경우, 좌측의 파일에 만들어진 그래프가 파일로 저장된다. 이를 다운로드 받아 실행해주면 됩니다.

 

결과는 아래와 같습니다.

 

 

해석

a) 93.33%의 정확도로 붓꽃의 품종을 분류해낸 결정나무 분류기가 가장 중요하게 생각한 변수는 petal width가 0.8cm보다 작거나 또는 큰지에 대해서 분류한 것이다.

b) 그 다음은 순서도에 나온대로 해석하면 된다. 

c) 각 마지막에 나온 gini 는 Gini 계수를 의미하며 불순도(impurity)를 의미한다.

 

 

9) Gini 계수에 대한 설명

 

Gini 계수는 불순도(impurity)를 측정하기 위한 지표 중 하나로, 주로 의사결정 트리(Decision Tree)와 같은 분류 알고리즘에서 사용됩니다. 불순도란 데이터 집합 내에서 서로 다른 클래스의 데이터가 얼마나 혼합되어 있는지를 나타내는 지표로, 낮을수록 데이터가 한 클래스에 몰려 있는 것을 의미합니다.

Gini 계수는 0부터 1까지의 값을 가지며, 0에 가까울수록 불순도가 낮고, 1에 가까울수록 불순도가 높습니다. 다음과 같은 공식으로 계산됩니다

여기서 pi는 각 클래스 i에 속하는 데이터의 비율을 나타냅니다.

의사결정 트리의 분할 시, Gini 계수는 분할된 각 하위 그룹의 불순도를 계산하고, 이들의 가중 평균을 구함으로써 분할의 품질을 측정합니다. Gini 계수가 낮을수록 좋은 분할이라고 할 수 있습니다. 의사결정 트리에서 불순도를 최소화하도록 하는 분할을 선택하여 데이터를 잘 분류하는 결정을 내리는데 사용됩니다.

요약하면, Gini 계수는 분류 문제에서 의사결정 트리가 어떤 특성을 선택하여 데이터를 분할할 때, 얼마나 순수한 하위 그룹을 생성하는지를 나타내는 지표입니다.

728x90
반응형

댓글