ML - 1. Iris의 품종 분류

jaam._.mini·2024년 1월 15일
0

iris 데이터 불러오기


  • 모듈 insatall

(1) 데이터 불러오기

  • sklearn 에 올라와 있는 데이터 이용
    from sklearn.datasets import load_iris
    iris = load_iris()
    iris

(2) 데이터 타입 확인

  • 각각의 데이터 확인

    iris.keys()
    # 줄 바꿈을 위해 print 사용
    # 'DESCR' 칼럼은 데이터의 설명이 들어있음
    print(iris['DESCR'])
    print(iris['target'])
    len(iris['target'])
    # 위의 데이터와 함께 보면, 0번이 setosa, 1번이 versicolor, 2번이 virginica
    
    print(iris['target_names'])

(3) DataFrame 만들기

  • import pandas as pd
    
    iris_pd = pd.DataFrame(iris.data, columns=iris.feature_names)
    iris_pd.head()

(4) 품종 정보 column에 포함¶

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

(5) 그래프를 통해 데이터 확인

import matplotlib.pyplot as plt
import seaborn as sns
  • sepal length 와 species 의 관계

    • 관계가 나쁨?
    • 3개가 모두 겹쳐 있어, 구분이 어려움
  • sepal width (cm) 와 species 관계

    • 3개가 겹쳐 있어 구분이 어려움
  • petal length (cm) 와 species

    • 분류됨
  • pairplot

    • 구분되는 그래프가 있는지 확인하기
    sns.pairplot(iris_pd, hue='species')





1. Decision Tree


나머지 인덱스1,2 를 어떻게 구분할 것인가?

📌 df[df['column(class)']] : df데이터를 슬라이싱 : 데이터를 선택해라
📌 class가 0은 다 빼라 : 컬럼 0을 제외한 데이터를 보여줘

iris_pd[iris_pd['species'] != 0]
iris_12 = iris_pd[iris_pd['species'] != 0]
iris_12.info()



(1) Split Criterion (분할기준)


📌직선 하나로 두개를 나눠야 함
📌어디 경계선이 최고 일까? 를 찾아야 함

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



(2) 엔트로피


📌 -pi log2 pi

  • p는 해당 데이터가 해당 클래스에 속할 확률이고 위 식을 그려보면 다음과 같다
  • 어떤 확률 분포로 일어나는 사건을 표현하는 데 필요한 정보의 양이며 이 값이 커질수록 확률 분포의 불확실성이 커지며 결과에 대한 예측이 어려워짐

📌 엔트로피 = (-pi log2 pi)의 모든 합

  • 무질서할수록 엔트로피 값은 높다 (불확실 성이 높을 수록)
  • 엔트로피 값이 내려갈수록, 질서가 잡혀가는 것!!!
import numpy as np

p = np.arange(0.001, 1, 0.001)
plt.grid()
plt.title('$-p \log_{2}{p}$')
plt.plot(p, -p*np.log2(p));



(2)-1 예제


📌 기본

  • 파란공(10개) 빨간공(6개)
    -(10/16)*np.log2(10/16) - 6/16*np.log2(6/16)
    0.954434002924965

📌 정 중앙에 선을 하나 만들어서 나눔

  • (왼쪽) 파란공(1) 빨간공(7), (오른쪽) 파란공(5) 빨간공(3)

    0.5*(-(7/8)*np.log2(7/8) -1/8*np.log2(1/8)) + \
    0.5*(-(3/8)*np.log2(3/8) - 5/8*np.log2(5/8))

    0.7489992230622807

    엔트로피가 내려갔으므로, 분할 하는 것이 좋음!!!!



(3) 지니계수


  • Gini index 혹은 불순도율
  • 엔트로피의 계산량이 많아서 비슷한 개념이면서 보다 게산량이 적은 지니계수를 사용하는 경우가 많다.



(3)-1 예제


📌 기본

  • 파란공(10개) 빨간공(6개)
    # 1 - 파란색의 확률 - 빨간색의 확률
    1 - (6/16)**2 - (10/16)**2
    0.46875

📌 정 중앙에 선을 하나 만들어서 나눔

  • (왼쪽) 파란공(1) 빨간공(7), (오른쪽) 파란공(5) 빨간공(3)

    0.5*(1 - (7/8)**2 - (1/8)**2) + 0.5*(1 - (3/8)**2 - (5/8)**2)

    0.34375

    지니계수 값이 내려갔으므로, 분할 하는 것이 좋음!!!!






2. Scikit Learn


📌 모듈

from sklearn.tree import DecisionTreeClassifier

iris_tree = DecisionTreeClassifier()

📌 data 확인

  • 150개의 행, 4개의 열

    iris.data.shape

    (150, 4)


  • 첫번째 행 불러오기. 리스트 값으로 반환됨

    iris.data[0]

    array([5.1, 3.5, 1.4, 0.2])


  • 컬럼 확인

    iris_pd.head(1)


  • [모든행, petal length (cm) petal width (cm) 만 따오고 싶음]

    iris.data[:, 2:]


(1) 학습


📌학습 시킬 모델명 : iris_tree
📌fit 명령을 써서 정답과 함께 학습을 완료 시키고 싶음

  • fit : 학습해라 (데이터, 정답)
    iris_tree.fit(iris.data[:, 2:], iris.target)

(2) 성능 확인


📌 Accuracy 확인

  • y_pred_tr : 예측 결과 변수
  • iris.target : 참 값 (정답)

📌 99.3 % 의 정확성 도출

  • accuracy_score 모듈

    from sklearn.metrics import accuracy_score
  • 학습이 완료된 iris_tree에게 예측(predict)을 시킴 (원하는 데이터(값))

    y_pred_tr = iris_tree.predict(iris.data[:, 2:])
  • accuracy_score 함수 사용

  • (정답 알려주고, 예측한 결과도 알려줌)

    accuracy_score(iris.target, y_pred_tr)

    0.9933333333333333





3. 과적합


(1) 지도학습

  • Label(Y, 정답)을 붙여 학습 시킴
  • 새로운 데이터를 학습시킨 것에 넣음
  • 예측 결과를 뽑아줌



(2) plot tree


  • plot_tree 모듈

    from sklearn.tree import plot_tree
    
  • iris_tree 가 어떻게 생겼는지 보여줘~

    plt.figure(figsize=(10,7))
    plot_tree(iris_tree);



(3) mlxtend.plotting


  • 데이터의 경계선을 그려주는 함수
  • 쓸수 있는 상황이 많진 않음

📌 mlxtend 설치

# !pip install mlxtend

📌 plot_tree 데이터 확인
iris의 품종을 분류하는 결정나무 모델이 어떻게 데이터를 분류했는지 확인해보자

  • mlxtend 모듈
    from mlxtend.plotting import plot_decision_regions
  • X 는 대문자로 써야함....?
  • clf모델 : iris_tree에 학습되어 저장되어 있음
  • legend : 범례
    plt.figure(figsize=(14,8))
    plot_decision_regions(X=iris.data[:, 2:], y=iris.target, clf=iris_tree, legend=2)
    plt.show()
    • 저 경계면은 올바른 걸까?
    • 저 결과는 내가 가진 데이터를 벗어나서 일반화할 수 있는 걸까?
    • 어차피 얻은(혹은 구한) 데이터는 유한하고 내가 얻은 데이터를 이용해서 일반화를 추구하게 된다.
    • 이때 복잡한 경계면은 모델의 성능을 결국 나쁘게 만든다.





4. 데이터 분리

1. 데이터 훈련/테스트로 분리

from sklearn.datasets import load_iris
import pandas as pd

iris = load_iris()
# train_test_split 함수(나눠주는) 모듈
from sklearn.model_selection import train_test_split

# features : iris.data[:, 2:] 변수
# labels : iris.target (정답) 변수
features = iris.data[:, 2:]
labels = iris.target

# 4개의 변수를 반환 받을 것임 : train_test_split 라는 변수로
# 지정해야 할 것들 : features, labels, test_size (훈련용80%, 랜덤용20%), random_state
X_train, X_test, y_train, y_test = train_test_split(
    features, labels, test_size=0.2, random_state=13
)
X_train.shape, X_test.shape

((120, 2), (30, 2))



2. np.unique 검사

📌 (필수..! 잘 분리되었는지 확인)

  • ((120, 2), (30, 2))에 iris 3개 종이 각각 몇개 들어갔을까?
  • 꼭 확인하는 작업이 필요함
# 모듈
import numpy as np

np.unique(y_test, return_counts=True)

(array([0, 1, 2]), array([ 9, 8, 13], dtype=int64))



3. stratify

  • 문제가 각 클래스(setosa, versicolor, verginica) 별로 동일 비율이 아니다
  • 이럴때, class의 옵션을 맞춰주는 것이 좋음
  • 내가 맞춰야 될 특성이 있는 라벨로 넣어줘야 함
from sklearn.model_selection import train_test_split

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

# 📌 stratify=labels 추가 : class 별 분포를 맞춰 줌
X_train, X_test, y_train, y_test = train_test_split(
    features, labels, test_size=0.2, random_state=13, stratify=labels
)
import numpy as np

np.unique(y_test, return_counts=True)

(array([0, 1, 2]), array([10, 10, 10], dtype=int64))



4. 결정나무모델(DecisionTreeClassifier)

(1) max_depth : 과적합을 위해 제한해야 함

  • 깊을 수 록 내가 준 데이터의 성능이 100%에 다가감
  • 성능이 높은 것이 꼭 좋지 않음
  • 제한 시킬 필요가 있음
# DecisionTreeClassifier 모듈
from sklearn.tree import DecisionTreeClassifier

# max_depth 설정
iris_tree = DecisionTreeClassifier(max_depth=2, random_state=13)

# fit 훈련 : (데이터, 정답)
iris_tree.fit(X_train, y_train)



(2) plot_tree

  • iris_tree 가 어떻게 생겼는지 보여줘
# plot_tree 모듈
from sklearn.tree import plot_tree
import matplotlib.pyplot as plt

# iris_tree 가 어떻게 생겼는지 보여줘~
plt.figure(figsize=(5,5))
plot_tree(iris_tree);



(3) Accuracy 확인

  • 성능 확인
# accuracy_score 모듈
from sklearn.metrics import accuracy_score

# 학습이 완료된 iris_tree에게 예측(predict)을 시킴 (훈련된값)
y_pred_tr = iris_tree.predict(X_train)

# accuracy_score 함수 사용
# (정답 알려주고, 예측한 결과도 알려줌)
accuracy_score(y_train, y_pred_tr)

0.95



5. X_train의 결정경계 확인

# plot_decision_regions 모듈
from mlxtend.plotting import plot_decision_regions
import matplotlib.pyplot as plt

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



6. test data(위 쿼리s)에 accuracy(정확도 확인)

  • test 결과 96.6% 도출
y_pred_test = iris_tree.predict(X_test)
accuracy_score(y_test, y_pred_test)

0.9666666666666667



7. 잔기술

  • 150개 데이터 전체를 train과 test를 분리해 결정경계 까지 넣고자 함
scatter_highlight_kwargs = {'s':150, 'label':'Test data', 'alpha':0.9}
scatter_kwargs = {'s':120, 'edgecolor':None, 'alpha':0.7}

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})
plt.show()



8. 모델 사용 방법

  • 새로운 데이터를 가지고 예측 결과를 도출



(1) 새 데이터로 결과 도출해보기

  • features 4개를 새로 지정

    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)
  • 주운 꽃의 데이터 : 4.3,2.,1.2,1.0

    # 값으로 정답 도출
    test_data = [[4.3,2.,1.2,1.0]]
    iris_tree.predict(test_data)

    array([1])

    # 문자로 정답 도출
    iris.target_names[iris_tree.predict(test_data)]

    array(['versicolor'], dtype='<U10')

    # predict_proba : 각 데이터일 확률 확인
    iris_tree.predict_proba(test_data)

    array([[0. , 0.97222222, 0.02777778]])

    # list 형태로, shape을 보고 싶으면 np.array()로 감사줄 것
    
    test_data = np.array([[4.3,2.,1.2,1.0]])
    test_data.shape

    (1, 4)



(2) zip

  • zip 모델

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

    {'sepal length (cm)': 0.0,
    'sepal width (cm)': 0.0,
    'petal length (cm)': 0.421897810218978,
    'petal width (cm)': 0.578102189781022}

  • 리스트를 튜플로 만들기

    list1 = ['a','b','c']
    list2 = [1,2,3]
    pairs = [pair for pair in zip(list1, list2)]
    pairs

    [('a', 1), ('b', 2), ('c', 3)]

  • 튜플을 dict 으로

    dict(pairs)

    {'a': 1, 'b': 2, 'c': 3}

profile
비전공자의 데이터 공부법

0개의 댓글