본문 바로가기
Tensorflow

Iris dataset classification with Keras

by 청양호박이 2020. 2. 13.

지난번에는 임의로 데이터 셋을 생성하여, Logistic Regression 과 Softmax Regression을 사용해서 모델링을 해보았습니다. 이 두가지 방식은 종속변수가 범주형인 데이터 셋에 적용이 가능하며, 범주가 2개인지 3개이상인지를 가지고 각 각 다르게 사용했었습니다. 

 

이번에는 유명한 dataset을 사용해서 적당한 분류기를 사용해서 모델링을하고 학습을 하여, 검증하는 방식으로 진행해 보겠습니다. 아주 유명한 예제인 Iris(붓꽃) 데이터를 사용하겠습니다. Iris(붓꽃) dataset (Fisher Iris Dataset)은... 영국 통계 학자 및 생물학자인 로널드 피셔 (Ronald Fisher)가 1936 년 논문에서 소개 한 다변량 데이터 세트입니다.

 

해당 데이터는 총 150개로 이루어져 있으며, 꽃받침(Sepal) 과 꽃잎(Petal)의 길이와 폭을 가지로 총 3가지의 종으로 분류한 정보를 제공합니다. 이 데이터 셋을 가지고 Keras를 이용해서 Iris 분류를 진행해 보겠습니다.

 

 

0. 기본 패키지 import


import numpy as np
import pandas as pd
import tensorflow as tf
import matplotlib.pyplot as plt
from sklearn.utils import shuffle
from sklearn.datasets import load_iris
from tensorflow.keras.utils import to_categorical

 

 

1. Dataset 분석


Iris는 너무 유명하여 여러가지 패키지에서 해당 dataset을 제공하는데, 대표적으로 sci-kit learn에서도 간단하게 load( )하여 사용이 가능합니다. 그럼 이제 load_iris( )로 불러오고, dataset 형태를 분석해 보겠습니다.

 

[Dataset 불러오기]

dataset = load_iris()

print(dataset)
print(dataset.keys())
print(dataset.feature_names)
print(dataset.target)
print(dataset.target_names)
print(len(dataset.data))

#############################
dict_keys(['data', 'target', 'target_names', 'DESCR', 'feature_names', 'filename'])
['sepal length (cm)', 'sepal width (cm)', 'petal length (cm)', 'petal width (cm)']
[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2
 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
 2 2]
['setosa' 'versicolor' 'virginica']
150

dataset을 확인해 보면, dictionary형태를 띕니다. 그래서 keys( )를 확인해 보면 제공되는 항목들을 확인이 가능합니다.

 

data : 독립변수

target : 종속변수

target_names : 종속변수 종의 종류(이름)

feature_names : 독립변수의 이름 (cm)

 

그럼 제공되는 데이터를 가지고 꽃받침(Sepal) 과 꽃잎(Petal)의 길이와 폭에 대해서 각 각 종속변수에 어떤 영향을 미치는지 간단하게 분포를 확인해 보겠습니다.

 

[Dataset 분포 확인]

f, ax = plt.subplots(1, 2, figsize=(14,6))
ax[0].scatter(dataset.data[:,0], dataset.data[:,1], c=dataset.target)
ax[0].set_title('scatter with Sepal')
ax[1].scatter(dataset.data[:,2], dataset.data[:,3], c=dataset.target)
ax[1].set_title('scatter with Petal')
plt.show()

꽃받침(Sepal)의 경우도 그렇고, 꽃잎(Petal)의 경우도 그렇고, 1개의 종은 완벽하게 구분이 되는 반면에... 나머지 2개에 대해서는 일부 혹은 다소많이 특징이 겹치는 부분이 존재함을 알 수 있습니다.

 

 

2. Dataset 분할


총 150개의 데이터가 제공되기 때문에, 이를 가지고 Trining용 / Test용으로 분할을 진행합니다. Training으로 모델을 학습시키고... Test를 통해서 해당 모델을 검증합니다. 그리고, 추가적으로 작업이 필요한 부분이 있습니다. 데이터를 보면 Iris의 종 별로 데이터가 모여있어서 분할을 하게되면 연속적으로 되기 때문에, 해당 종에 대해서만 학습이 될 가능성이 있습니다. 따라서 shuffle을 진행 후 Dataset division이 필요합니다.

 

또한, 종속변수가 범주형이지만 3가지로 되어있기 때문에, Softmax에서 수행했던 one-hot encoding을 추가로 진행해야 합니다.

 

[One-hot encoding]

dataset_y = to_categorical(dataset.target)
print(dataset_y)

dataset_y = np.array(dataset_y, dtype=np.int32)
print(dataset_y)
##########################################
[[1. 0. 0.]
 [1. 0. 0.]
 [1. 0. 0.]
 [1. 0. 0.]
 
 
 [[1 0 0]
 [0 0 1]
 [0 1 0]

여러가지 방법이 있겠지만, tensorflow.keras.utils에서 제공하는 메소드를 사용하겠습니다. to_categorical( )에 원하는 항목을 넣으면 결과와 같이 알아서 one-hot encoding된 결과가 나옵니다.

 

이렇게 하면 문제가 발생합니다. 왜냐하면 변환된 one-hot encoding이 dtype이 float의 형태를 띄기 때문입니다. 따라서 강제로 int로 바꿔줍니다.

 

[Dataset shuffle]

x = [[1,1,1],[2,2,2],[3,3,3],[4,4,4],[5,5,5]]
y = [[1],[2],[3],[4],[5]]

x, y = shuffle(x, y)

print(x)
print(y)

##############################################
[[4, 4, 4], [1, 1, 1], [5, 5, 5], [3, 3, 3], [2, 2, 2]]
[[4], [1], [5], [3], [2]]

sklearn.utils에 shuffle( )이라는 메소드는 위의 예시와 같이 x, y를 하나의 set으로 shuffle을 수행해 줍니다. 그렇다면 실제 Iris data로 돌아와서 적용을 해본다면...

dataset_x = dataset.data
dataset_x, dataset_y = shuffle(dataset_x, dataset_y)

[Dataset Division]

train_x = dataset_x[:120,]
test_x = dataset_x[120:,]

train_y = dataset_y[:120,]
test_y = dataset_y[120:,]

보기좋게... Train : Test = 120 : 30 로 진행하겠습니다.

 

 

3. Build Model using Keras


Model은 1개의 Dense layer를 사용하며, 아래의 조건으로 compile하겠습니다.

  • Optimizer =SGD (Stochastic Gradient Descent)
  • Loss Function = Categorical CrossEntropy
  • Activate Function = Softmax
class IrisModel():
    def __init__(self):
        self.epochs = 200
        self.learning_rate = 0.04

    def buildModel(self):
        self.model = tf.keras.Sequential()
        self.model.add(tf.keras.layers.Dense(3, activation='softmax'))

        optimizer = tf.keras.optimizers.SGD(learning_rate=self.learning_rate)

        self.model.compile(loss='categorical_crossentropy', optimizer=optimizer, metrics=['accuracy'])

 

 

4. Fit Model & Evaluate Model


    def fitModel(self, x, y):
        hist = self.model.fit(x, y, epochs=self.epochs, batch_size=10, shuffle=True)
        return hist

    def evaluateModel(self, x, y):
        self.model.evaluate(x, y)

[Fit Model 진행]

model = IrisModel()
model.buildModel()
hist = model.fitModel(train_x, train_y)

########################################
Epoch 198/200
120/120 [==============================] - 0s 220us/sample - loss: 0.1318 - accuracy: 0.9833
Epoch 199/200
120/120 [==============================] - 0s 199us/sample - loss: 0.1262 - accuracy: 0.9750
Epoch 200/200
120/120 [==============================] - 0s 160us/sample - loss: 0.1287 - accuracy: 0.9750

[학습경과]

plt.plot(hist.history['loss'])
plt.plot(hist.history['accuracy'])
plt.show()

Loss는 급격히 0으로 수렴하다가... 거의 줄지 않는 모습을 보이고, 정확도는 1에 근접하는 모습니다. 학습이 잘 됬네요...

 

[Evaluate Model]

model.evaluateModel(test_x, test_y)

###################################
30/30 [==============================] - 0s 2ms/sample - loss: 0.1771 - accuracy: 0.9667

Test 데이터에 대해서도 좋은 결과가 도출되었습니다. 이렇게 Iris분류를 마치겠습니다.

 

-Ayotera Lab-

댓글