Iris Dataset

김은비·2024년 4월 26일
0
  • EDA
  • Decision Tree
  • 과적합
  • Splitting

EDA

from sklearn.datasets import load_iris

iris = load_iris()
import pandas as pd

iris_pd = pd.DataFrame(iris.data, columns=iris['feature_names'])
iris_pd

품종 정보도 column에 포함

print(iris['target_names'])

print(iris['target'])

iris_pd['species'] = iris.target
iris_pd.head()

Box plot

import matplotlib.pyplot as plt
import seaborn as sns

plt.figure(figsize=(12, 6))
sns.boxplot(x='sepal length (cm)', y='species', data=iris_pd, orient='h');

plt.figure(figsize=(12, 6))
sns.boxplot(x='sepal width (cm)', y='species', data=iris_pd, orient='h');

plt.figure(figsize=(12, 6))
sns.boxplot(x='petal width (cm)', y='species', data=iris_pd, orient='h');

plt.figure(figsize=(12, 6))
sns.boxplot(x='petal width (cm)', y='species', data=iris_pd, orient='h');

-> petal length, petal width가 setosa는 구분 잘 하지만
3종을 다 분류하긴 어렵다.

Pairplot

sns.pairplot(iris_pd, hue='species')

-> petal length, petal width가 setosa를 확실히 구분을 잘 한다.

petal length, petal width로 품종 세 개를 구분할 수 있을까?

sns.pairplot(data=iris_pd,
             vars=['petal length (cm)', 'petal width (cm)'],
             hue = 'species', height=4)

-> 일단 setosa는 가능하다.
대략 peetal length가 2.5보다 작다면 모두 setosa로 분류하면 된다.

versicolor: petal length가 2.5보다 크면서 width가 1.6보다 작을 경우
verginica: petal length가 2.5보다 크면서 width가 1.6보다 클 경우

그게 최선인가? -> 그 기준이 되는 숫자가 어디가 최선인지 확인해야 한다.
왜 이 숫자인지에 대한 결론="알고리즘"의 역할


Decision Tree

versicolor와 verginica를 어떻게 구별할 것인가?
0(setosa)를 제외한 나머지만 선택 - 1,2

iris_12 = iris_pd[iris_pd['species']!=0]

0과 1을 구분하는 구분선이 어디에 있는 게 최적일까?
-> Decision Tree에서 "분할 기준" (split criterion)이라 한다.

plt.figure(figsize=(12, 6))
sns.scatterplot(x='petal length (cm)', y='petal width (cm)', 
	data=iris_12, hue='species', palette='Set2');

이 둘은 어떻게 가를까?

-> 모든 경우의 수의 (분할의 수) 지니계수를 계산해서 가장 낮은 지니계수값을 찾으면 된다.

사이킷런으로 결정나무를 구현

from sklearn.tree import DecisionTreeClassifier

iris_tree = DecisionTreeClassifier()

학습

iris_tree.fit(iris.data[:, 2:], iris.target)

성능 확인 (accuracy 확인)

from sklearn.metrics import accuracy_score

y_pred_tr = iris_tree.predict(iris.data[:, 2:])
accuracy_score(iris.target, y_pred_tr)

정확도는 99.33%이다.


과적합

plot_tree

from sklearn.tree import plot_tree

plt.figure(figsize=(12, 8))
plot_tree(iris_tree);

결정 경계 확인

from mlxtend.plotting import plot_decision_regions

plt.figure(figsize=(14,8))
plot_decision_regions(X=iris.data[:, 2:], y=iris.target, clf=iris_tree, legend=2)
plt.show()

저 복잡한 경계면 때문에, accuracy가 높게 (99퍼) 나왔다고해도 좀 더 들여다 볼 필요가 있다.

저 경계면은 완벽한 걸까? 일반화할 수 있는 것인가?
경계면 사이 저 애들이 돌연변이들이라면?

저런 "복잡한 경계면"을 가진 모델이 일반적인 다른 iris 데이터셋에도 좋은 성능이 나올까?
-> 내가 가진 데이터에만 너무 fit해졌다. -> 그런 머신러닝 모델은 "일반적"이라 할 수 없다
-> "과적합"이라 한다.

"복잡한 경계면은 모델의 성능을 결국 나쁘게 만든다."


Splitting

훈련/테스트용으로 데이터 분리하기

from sklearn.model_selection import train_test_split

features = iris.data[:, 2:]
labels = iris.target

X_train, X_test, y_train, y_test = train_test_split(features, labels, 
                                                    test_size=0.2, 
                                                    stratify=labels,
                                                    random_state=13)

stratify 옵션 - 비율을 맞춰준다.

train 데이터만 대상으로 결정나무 모델을 만들어 보자

from sklearn.tree import DecisionTreeClassifier

iris_tree = DecisionTreeClassifier(max_depth=2, random_state=13)
iris_tree.fit(X_train, y_train)

max_depth는기다란 결정나무를 중간에서 잘라줌 -> 성능 나빠짐 ->
depth가 깊을수록 내가 준 데이터의 성능이 100퍼가 됨.
근데 그게 좋은 것만은 아니라 했자나(과적합 때문에)

그래서 성능을 제한시켜준다. = "규제"
내가 준 트레이닝 데이터에 최적화되지 않도록 모델의 성능을 제한!

plt.figure(figsize=(12, 8))
plot_tree(iris_tree);

accuracy 확인

from sklearn.metrics import accuracy_score

y_pred_tr = iris_tree.predict(iris.data[:, 2:])
accuracy_score(iris.target, y_pred_tr)

-> 0.9533333333333334

정확도 떨어짐.

y_pred_test = iris_tree.predict(X_test)
accuracy_score(y_test, y_pred_test)

-> 0.9666666666666667

결정 경계 확인

plt.figure(figsize=(14,8))
plot_decision_regions(X=X_train, y=y_train, clf=iris_tree, legend=2)
plt.show()

더 틀렸지만, "복잡하지 않다"

-> 데이터는 split하는 게, max_depth를 한정하는 것이 좋다! -> 과적합을 막기 위해서

scatter_highlight_kwargs = {'s':150, 'label':'Test data', 'alpha':0.9}
scatter_kwargs = {'s':120, 'edgecolor':None, 'alpha':0.9} 

plt.figure(figsize=(12, 8))
plot_decision_regions(X=features, y=labels, 
                      X_highlight=X_test, clf=iris_tree, legend=2,
                      scatter_highlight_kwargs=scatter_highlight_kwargs,
                      scatter_kwargs=scatter_kwargs,
                      contourf_kwargs={'alpha':0.2})

전체 데이터 중 무엇이 테스트 데이터로 선정되었는지 보여준다.

feature_importances_

features를 이제 4개 주고 다시 fit하였다.

features = iris.data
labels = iris.target

X_train, X_test, y_train, y_test = train_test_split(features, labels,
                                                    test_size=0.2,
                                                    stratify=labels,
                                                    random_state=13)
iris_tree = DecisionTreeClassifier(max_depth=2, random_state=13)
iris_tree.fit(X_train, y_train)
plt.figure(figsize=(12, 8))
plot_tree(iris_tree);

iris_tree = DecisionTreeClassifier(max_depth=5, random_state=13)
iris_tree.fit(X_train, y_train)

dict(zip(iris.feature_names, iris_tree.feature_importances_))

모델을 결정하는 데에 필요한 중요 feature를 알 수 있다.

0개의 댓글