본문 바로가기

CS/AI

[ML] Scikit-learn을 사용한 분류 (1)

반응형

 

안녕하세요, 쉽지 않은 길에 들어선 짐민입니다.

 

사이킷런을 이용해서 먼저 가벼운 비지도학습을 해보기 위한 기능들을 알아보겠습니다.

 

# 첫 예제

import pandas as pd
import numpy as np
import sklearn
from sklearn.datasets import load_iris
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score

iris = load_iris()

iris_data = iris.data

iris_label = iris.target
# print('iris target값:', iris_label)
# print('iris target명:', iris.target_names)

iris_df = pd.DataFrame(data=iris_data, columns=iris.feature_names)
iris_df['label'] = iris.target
iris_df.head()

x_train, x_test, y_train, y_test = train_test_split(iris_data, iris_label, test_size=0.2, random_state=112)

dt_clf = DecisionTreeClassifier(random_state=1154)
dt_clf.fit(x_train, y_train)

pred = dt_clf.predict(x_test)

print('예측 정확도: {0:.4f}'.format(accuracy_score(y_test, pred)))

 

target으로 레이블값을 불러올 수 있고,

 

DecisionTreeClassifier()으로 결정 트리 분류를 할 수 있습니다.

 

train_test_split으로 학습 데이터와 테스트 데이터를 나눌 수 있습니다.

 

이 예제에서는 결정트리를 사용하여 fit()predict()를 하였습니다.

fit 함수에 데이터와 레이블 값을 넣어주면 된다고 합니다.

 

random_state는 테스트값이 일정하게 나오게 유지하기 위해 넣었습니다.

원래는 일정하면 오히려 학습에 안 좋을 수 있기 때문에 안 넣는 게 나을지도 모르겠습니다.

 

 

이렇게 옆의 데이터가 있으면 학습해서 레이블 값을 유추해내는 것입니다.

 

matplotlib, seaborn으로 만들어진 그래프입니다. (colab이 만들어줌)

 

K-Fold 교차 검증

<파이썬 머신러닝 완벽가이드> 에서 가져옴.

 

학습이 잘 되었더라도, 특정 테스트 데이터에만 잘 맞는 오버피팅이 발생할 수 있습니다.

이를 방지하기 위하여 교차 검증이 필요합니다.

 

K-Fold 교차 검증 방식은 학습 데이터도 또 나눠서 학습/검증 데이터로 나누어서 학습-검증을 진행,

이 단계를 여러 번 해서 알고리즘의 적합성을 판단하는 방식입니다.

 

분류 알고리즘에서는 Stratified K 폴드가 적합합니다.

Stratified는 데이터가 특정 위치에 몰려있는 걸 방지하기 위해 사용되는 방식입니다.

 

회귀 알고리즘은 연속된 값들을 다루기 때문에 이 방식은 사용할 수가 없습니다.

 


 

아무튼 교차 검증을 해봅시다.

 

kfold = KFold(n_splits=5)
cv_accuracy = []

print("붓꽃의 데이터 사이즈:", iris_data.shape[0])

for train_index, test_index in kfold.split(iris_data):
  x_train, x_test = iris_data[train_index], iris_data[test_index]
  y_train, y_test = iris_label[train_index], iris_label[test_index]

  dt_clf.fit(x_train, y_train)
  pred = dt_clf.predict(x_test)
  accuracy = np.round(accuracy_score(y_test, pred), 4)

  print("검증 신뢰도:",accuracy,"검증 인덱스", test_index)
  cv_accuracy.append(accuracy)

print('검증 정확도:', np.mean(cv_accuracy))

 

 

이렇게 0.9 이상의 정확도를 보입니다.

 

다만 지금 사용하고 있는 붓꽃의 데이터는

0~49 인덱스까지는 Setosa, 50~99까지는 Versicolor, 100~149까지는 Virginica 품종으로

KFold가 3이 될 시 어느 분류는 아예 학습을 할 수 없기 때문에 아예 테스트가 불가능해집니다.

 

 

정확도 0.0이 나오네요.

 

이럴 때 Stratified K-Fold를 사용합니다.

 

# kfold = KFold(n_splits=3)
skfold =  StratifiedKFold(n_splits=3)
cv_accuracy = []

print("붓꽃의 데이터 사이즈:", iris_data.shape[0])

for train_index, test_index in skfold.split(iris_data, iris_label):
  x_train, x_test = iris_data[train_index], iris_data[test_index]
  y_train, y_test = iris_label[train_index], iris_label[test_index]

  dt_clf.fit(x_train, y_train)
  pred = dt_clf.predict(x_test)
  accuracy = np.round(accuracy_score(y_test, pred), 4)

  print("검증 신뢰도:",accuracy,"검증 인덱스", test_index)
  cv_accuracy.append(accuracy)

print('검증 정확도:', np.mean(cv_accuracy))

 

StratifiedKFold는 split에 데이터와 레이블 값까지 모두 넣어줘야 합니다.

 

인덱스가 조금 더 불규칙해지면서 정확도를 올릴 수 있게 되었습니다.

 

pd의 value_counts()를 사용해보면 각 품종에서 33 33 34개씩으로 고루 가져온 것도 알 수 있습니다.

 

이렇게 일일이 분류하는 것은 근데 조금 귀찮습니다.

다행히 우리에겐 훌륭한 라이브러리가 있습니다.

 

cross_val_score()을 통하여 알아서 교차 검증을 시킬 수 있습니다.

 

scores = cross_val_score(dt_clf, iris_data, iris_label, scoring='accuracy', cv=4)
print("교차 검증별 정확도:", np.round(scores, 4))
print("평균 정확도:", np.round(np.mean(scores), 4))

 

cross_val_score(estimator, x, y, scoring, cv=fold 개수, ...)

 

esimator에 classifier(회귀일 때는 Regressor), x에 데이터, y에 레이블을 넘겨주면 검증을 자알 해줍니다.