ㅅㅇ

머신러닝 _ 02 머신러닝분석 - lris 분석 본문

AI_STUDY/머신러닝

머신러닝 _ 02 머신러닝분석 - lris 분석

SO__OS 2022. 6. 27. 23:25
플레이데이터 빅데이터캠프 공부 내용 _ 6/27

머신러닝 _ 02 머신러닝분석 - lris 분석

1. Iris DataSet

꽃받침(Sepal)과 꽃잎(Petal)의 길이,  너비  네가지 feature로

Setosa, Versicolor, Virginica  아이리스 세가지 품종 Label 을 분류

- 식물에 대한 전문가가 아닌 프로그래머가 꽃에 대한 규칙을 알기 어렵다. 

  사람이 직접 찾는 규칙기반에서는 iris 전문가가 필요하다.
- 머신러닝은 데이터만으로 컴퓨터가 직접 패턴을 찾는 것이다.
    - 사실, 머신러닝에서 중요도를 따지면 알고리즘은 20~30%이다.

      성능의 차이는 데이터에서 난다. 머신러닝에서는 데이터 전처리가 중요하다.

      패턴을 알 수 있는 유의미한 데이터를 구하는 것이 중요. (딥러닝에서는 또 다름.)

 

 

2. 데이터 셋 확인하기

2.1 scikit-learn 내장 데이터셋 가져오기

- scikit-learn은 머신러닝 모델을 테스트 하기위한 데이터셋을 제공한다.
    - 이런 데이터셋을 Toy dataset이라고 한다. 실무에서 이것을 사용하진 않는다.


- 패키지 : sklearn.datasets
- 함수   : load_xxxx()
    - xxxx : 어떤 데이터 셋인지
    - bunch 반환

 

from sklearn.datasets import load_iris
iris = load_iris() # iris 라는 데이터 셋을 load

 

2.2 scikit-learn 내장 데이터셋의 구성


- 'scikit-learn의 dataset'  은   딕셔너리 구조의 Bunch 클래스 객체이다.
    - keys() 함수로 key값들을 조회. 

 

# bunch type : dictionary 구현체 (dict처럼 여러 개 값이 있고 key값이 있음.)
type(iris)
sklearn.utils.Bunch
 
 

- 구성

iris.keys()
dict_keys(['data', 'target', 'frame', 'target_names', 'DESCR', 'feature_names', 'filename', 'data_module'])

 

위와 같은 key 를 가지고 있다.


    - target_names : 예측하려는 값(class)을 가진 문자열 배열. label숫자의 의미를 가지고 있다.
    - target : Label(출력데이터) 숫자로 구성되어 있다.


    - data : Feature(입력변수)
    - feature_names : 입력변수 각 항목의 이름


    - DESCR : 데이터셋에 대한 설명

    - filename : 파일 이름 (이전 버전에서는 경로까지 였으나 현재는 'iris.csv' 파일 이름만이 뜬다.

 

 

1) DESCR 조회 : 데이터셋에 대한 설명

iris.DESCR

 

 

2) Target 조회

 

- target 조회

 target 의 타입은 numpy.ndarray 로 (150, ) 1차원 배열 구조에  Label(출력데이터) 숫자가 담겨 있다.

# 방법1
iris.target

# 방법2
iris['target']
array([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])

 

 

- target_names 조회

 

ndarray의  index :  label(숫자label),     ndarray의  value : label name

  0 : 'setosa',    1: 'versicolor',   2 : 'virginica'

iris.target_names
array(['setosa', 'versicolor', 'virginica'], dtype='<U10')

 

 

- target 출력 데이터  (정답개수, )  = > (150, )     # 정답개수니 당연히 하나의 축으로 끝남.

iris.target.shape
(150,)

 

 

3) Feature 조회

 

- Feature 조회

target 의 타입은 numpy.ndarray 로 (150, 4)   2차원 배열 구조에  Feature(입력변수) 데이터가 담겨 있다.

 

iris.data
array([[5.1, 3.5, 1.4, 0.2],
       [4.9, 3. , 1.4, 0.2],
       [4.7, 3.2, 1.3, 0.2],
       [4.6, 3.1, 1.5, 0.2],
       [5. , 3.6, 1.4, 0.2],
       [5.4, 3.9, 1.7, 0.4],
       [4.6, 3.4, 1.4, 0.3],
       [5. , 3.4, 1.5, 0.2],
       [4.4, 2.9, 1.4, 0.2],
       .
       .
       .

 

 

- Feature 데이터  (150, 4)  = >  (0번 축 : 데이터 개수, 1번 축 : Feature의 개수)

iris.data.shape
(150, 4)

 

 

- feature_names 조회 

입력변수 각 항목의 이름이 리스트로 담겨져 있다.

 

#  네가지 feature 의 name
iris.feature_names
['sepal length (cm)',
 'sepal width (cm)',
 'petal length (cm)',
 'petal width (cm)']

 

2.2  데이터 셋을 판다스 데이터프레임으로 구성

 

1) 데이터 프레임 생성

import numpy as np
import pandas as pd
iris_df = pd.DataFrame(iris.data, columns=iris.feature_names) 
iris_df['species'] = iris.target
iris_df.head()

 

2) 데이터프레임 info() 확인

iris_df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 150 entries, 0 to 149
Data columns (total 6 columns):
 #   Column             Non-Null Count  Dtype  
---  ------             --------------  -----  
 0   sepal length (cm)  150 non-null    float64
 1   sepal width (cm)   150 non-null    float64
 2   petal length (cm)  150 non-null    float64
 3   petal width (cm)   150 non-null    float64
 4   species            150 non-null    int32  
 5   species_name       150 non-null    object 
dtypes: float64(4), int32(1), object(1)
memory usage: 6.6+ KB

 

 

3) 각 species(target) 별  describe() 통계값 확인

iris_df.groupby('species').describe().T

 

 

4) 전체 데이터에 대한 descirbe() 통계량 확인

iris_df.describe()

 

 

 

5) 만약, label (숫자)에 따른 target name 을 보고 싶다면?

iris_df['species_name'] = iris_df['species'].apply(lambda x:iris.target_names[x])
iris_df.head()

 

 
 

3.  머신러닝을 이용한 예측

 

문제 정의

          내가 발견한 Iris 꽃받침(Sepal)의 길이(length)와 폭(width)이 각각 5cm, 3.5cm이고

          꽃의 꽃잎(Petal)의 길이와 폭은 각각 1.4cm, 0.25cm이 이었다.

          이 꽃는 Iris의 무슨 종일까?

 

- 규칙기반으로 찾아본다면?

   꽃받침(Sepal)의 길이(length): 5cm, 폭(width): 3.5cm
   꽃잎(Petal) 의 길이(length): 1.4cm, 폭(width): 0.25cm

 

내가 가지고 있는 150 개의 데이터를 가지고 우리가 직접 규칙 패턴을 찾는다.

조회 결과 setosa 뿐이다. 이를 통해 setosa 라 예측할 수 있다. 

iris_df.loc[(iris_df['sepal length (cm)']==5) & (iris_df['sepal width (cm)']==3.5)]

 

그러나, 우리가 가지고 있는 데이터는 150개 뿐이다. 전세계 모든 데이터를 가지고 있지 않으며, 심지어 시간에 따라 데이터는 변할 텐데, 규칙기반의 경우 데이터가 바뀔 때 마다 조건을 바꿔주며 규칙을 찾을 것이다.

 

 

- 머신러닝으로 우리가 하려는 것은?


 프로그래머가 직접 규칙(패턴)을 만드는  대신

 컴퓨터가 데이터를 학습하여 규칙을 자동으로 만들도록 하는 것

 

 

 

4. 결정 트리(Decision Tree) 알고리즘을 이용한 분류

결정 트리 알고리즘 개요


 : 독립 변수의 조건에 따라 종속 변수를 분리 


- 머신러닝의 몇 안되는 White box 모델
    - 결과에 대한 해석이 가능하다.

 

white box model : 모델이 물리 법칙으로 표현이 가능한 수준이며, 변수도 모두 아는 모델.
gray box model : 어느 정도 물리 법칙으로 표현이 가능하며, 변수도 어느 정도 알고 있는 모델.
black box model : 모델이 물리 법칙으로 표현하기 어려울 정도로 복잡하고, 변수도 알기 힘든 모델.

 


- 과적합(Overfitting)이 잘 일어나는 단점이 있다. 
- 랜덤 포레스트(Random Forest), Gradient Boosting, Adaptive boosting과 같은 Boosting 계열 앙상블이 결정트리를  기반으로 하고 있다

- 분류와 회귀 모두 가능하다. 범주나 연속형 수치 모두 예측할 수 있다.

 

 

- Decision Tree 의 개념

    해당 질문(조건)에 한 범주로 유일하게 만족하는 결과가 나오도록 계속해서 데이터를 분리하며 찾는다.

    계속적인 질문으로 그룹 짓어 분리하며 하나의 그룹에 하나의 종류만 나오게 한다.

    질문을 던져 대상을 좁혀나가는 스무고개 와 비슷한 개념이다.

         - 가장 완벽하게 나눌 수 있는, 가장 분류가 잘 되는 질문을 가장 먼저 한다. - 불순도(불확실성)을 낮게 만드는 질문

         - root node : 아무런 분기가 일어나지 않은 상태

 

'sepal length (cm)'] > 5 입니까? 그 질문에 따라 Yes or No로 데이터를 분리하였다. 이와 같이 분리해가는 것과 같다.

# target 별 5 이상인 데이터 개수
iris_df.loc[iris_df['sepal length (cm)'] > 5, 'species_name'].value_counts()
virginica     49
versicolor    47
setosa        22
Name: species_name, dtype: int64



4.2 결정트리 모델을 이용해 머신러닝 구현

 

실제로 이렇게 하지 않음. 평가가 빠졌다.  설명을 위해 따로.   

 

 

1) import 모델

 

import numpy as np
from sklearn.tree import DecisionTreeClassifier

 


2) 모델 생성

 

- DecisionTreeClassifier 클래스의 객체를 생성

tree_model = DecisionTreeClassifier(max_depth=2, random_state=0)

 


3) 모델 학습시키기

 

- 생성된 모델객체는 기본공식만 가지고 있다. 이를 학습을 시킨다.
  학습 : '기본공식' 을 '내 데이터셋' 에 맞추는 작업.    = = >  fit(feature, label)

 

# tree_model 객체 에 나의 150 개의 데이터가 fit 학습 되었다.
tree_model.fit(iris.data, iris.target)
 

4) 예측 

 

- 분류예측에서 


    모델.predict(추론할 데이터의 feature) : 확률이 가장 높은 class를 반환

    -  모델.predict_proba(추론할 데이터의 feature) : 각 class별 확률.  
    

 

  ex) 내가 본 iris 꽃의 꽃잎/꽃받침의 길이, 너비를 재서 종류를 예측해보자.

# 두 꽃 데이터에 대한 [[데이터1], [데이터2]] # 데이터 여러 개면 중복 리스트로 넣기
my_iris = np.array([[5, 3.5, 1.4, 0.25], [6.7, 3.0, 5.2, 2.2]]) 

# 추론 : 모델.predict(추론할 데이터의 feature)
result = tree_model.predict(my_iris)

# 예측 결과 
print(result)
print(iris.target_names[result])
[0 2]
['setosa' 'virginica']

 

 

ex) 추론결과를 확률로 반환해보자.

 

# index가 label 

# [1, 0, 0]                                         = >  0번꽃일 확률이 1,      1번,2번꽃일 확률은 0
#  [0. , 0.02173913, 0.97826087]    = >  2번 꽃일 확률이 확실하게 높다. 

 

 

그러나, 위와 같은 프로세스를 거친 결과를 신뢰할 수 있나?

- 모델이 추론한 결과가 맞다는 것을 어떻게 보증할 수 있을까? 근거가 필요하다. 그래서 평가가 필요하다.
모델을 최종 서비스에 적용하기 전에 모델의 성능을 확인하는 작업이 필요하다.

  그리고 평가를 위해서는 훈련 데이터셋과 테스트 데이터 분할 작업이 필요하다.

 

 

5. 훈련데이터셋과 평가(테스트)데이터 분할

- 위의 예는 우리가 만든 모델이 성능이 좋은 모델인지 나쁜 모델인지 알 수 없다.


- 전체 데이터 셋을 두개의 데이터셋으로 나눠 
    - 하나는 모델을 훈련(패턴 찾을)할 때 사용하고   => 훈련 데이터 셋 
    - 다른 하나는 그 모델을 평가할 때 사용한다.       => 평가 데이터 셋


- 보통 훈련데이터와 테스트데이터의 비율은 8:2 또는 7:3 정도로 나누는데, 데이터셋이 충분하다면 6:4까지도 나눈다.

 

 

- 데이터셋 분할시 주의할 점


    - 분류 문제의 경우, 각 클래스(분류대상)가 같은 비율로 나뉘야 한다. = > stratify = iris.target
    - 만약, 0, 1, 2 분류 데이터(원본데이터)가 1:1:1 이라면,

      나눠진 학습데이터와 테스트데이터들도 분류 데이터 간의 비율이 똑같아야 한다.

 

6. 머신러닝 프로세스

 

 

1. 데이터 셋 분리 : scikit-learn의  train_test_split() 함수를 이용해 iris 데이터셋 분할

 

- scikit-learn의  train_test_split() 함수 : 하나의 데이터를 두 세트로 분할하는 함수

 

- X_train, X_test,    y_train, y_test   =>   train F, test F, train L, test L

        변수  :   Feature - X ,    Label - y

        훈련용 - train,    평가용 - test,    검증용 - val/validation (다음 ch에 배움)

 

- train_test_split() 매개변수

  iris.data, 

  iris.target,

  test_size =   ,

  random_state=0,

  stratify = iris.target

 

 

1) 데이터 셋 분할

from sklearn.model_selection import train_test_split 

X_train, X_test, y_train, y_test = train_test_split(iris.data, # Feature - input - x
                                                    iris.target, # label(target) - output - y
                                                    test_size=0.2, # test set의 비율(train:0.8, test:0.2)
                                                    random_state=0, # random seed 값
                                                    stratify = iris.target) # class 별로 같은 비율로 나눠지도록 설정. (분류에서 필수!)

 

 

2) shape 확인

   # feature (150,4) 을 (120,4), (30,4)으로 나눈 것
   # label (150,) 을 (120,), (30,)으로 나눈 것.

X_train.shape, X_test.shape, y_train.shape, y_test.shape
((120, 4), (30, 4), (120,), (30,))
 
 
 
 
3)  훈련 데이터 (y_train), 테스트 데이터 (y_test) 의  각 범주 별 비율 확인
 
- stratify = iris.target 를 설정했기 때문에 원본 데이터와 같은 비율로 나눠진다.
 
  ( iris.target 을 통해 원본 label 비율과 최대한 같은 비율로 나눈다.)
 
     = > 원본 비율 iris.target = 1:1:1       y_train = 1:1:1       y_test  =  1:1:1
 
print(np.unique(y_train, return_counts=True)) # return_counts=True 갯수까지 열려줌
print(np.unique(y_test, return_counts=True))
print(np.unique(iris.target, return_counts=True))
(array([0, 1, 2]), array([40, 40, 40], dtype=int64))
(array([0, 1, 2]), array([10, 10, 10], dtype=int64))
(array([0, 1, 2]), array([50, 50, 50], dtype=int64))

 

 

2. 모델 생성

 

from sklearn.tree import DecisionTreeClassifier

tree_model = DecisionTreeClassifier(max_depth=2, random_state=0) # 함수 내부적으로 random한 값을 사용한다는 것을 알 수 있다.

 

 

3. 모델 학습

 

 학습 fit : '기본공식' 을 '내 데이터셋' 에 맞추는 작업.   = > 의사결정나무 객체에 iris 데이터에 맞추는 과정 
                                                                                       =  > 데이터에 맞춰 어떤 질문을 하는 것을 찾아내는 학습하는 과정 

 

의사결정나무 알고리즘
# 답을 결정하기 위해 트리 구조를 만든다.
# 질문으로 노드에 하나의 클래스 값만 있게 나눈다. 계속적으로 질문하며 분류한다. 

 

 

= = >  fit(feature, label)    == >  train dataset    X_train,     y_train   을 이용해서 학습

 

tree_model.fit(X_train, y_train) # (input-X, output-y)

 

 

4. 예측 

 

pred_train : Train dataset (Train할 때 사용한 데이터 셋) 의 Feature를 가지고 예측 

pred_test  : Test dataset (새로운 데이터 셋 - train 시 사용하지 않은 데이터 셋) 의 Feature를 가지고 예측

 

1)  .predict(X_train)  .predict(X_test)  예측

 

- 추론할 데이터의 feature 로   X_train 과  X_test 를 넣었다.

pred_train = tree_model.predict(X_train) # Train dataset의 Feature를 가지고 예측 

pred_test = tree_model.predict(X_test) # Test dataset의 Feature를 가지고 예측

 

 

2)  X_train 각각의 120개의 데이터에 대해서 pred_train 의 결과가 120개 나온다.

     X_test 각각의 30개의 데이터에 대해서 pred_test 의 결과가 30개 나온다.

         = > index로 확인 가능.

X_train.shape, pred_train.shape, X_test.shape, pred_test.shape
((120, 4), (120,), (30, 4), (30,))
 
 
 
3) '훈련 데이터 X_train ' 에 대한  '예측 결과 pred_train' 과   '정답 y_train'  를 비교.
 
print(X_train[:5]) # 훈련 데이터 셋
print('--------')
print(pred_train[:5]) # 훈련 데이터 셋 정확도. 학습데이터 예측 평가
print('--------')
print(y_train[:5]) # 정답 데이터

 

- 다섯 개 중에 다섯 개 다 맞음. 정확도 100% 

[[4.8 3.  1.4 0.3]
 [4.9 3.  1.4 0.2]
 [4.4 3.  1.3 0.2]
 [5.  3.4 1.5 0.2]
 [5.8 2.7 3.9 1.2]]
--------
[0 0 0 0 1]
--------
[0 0 0 0 1]

 

 

 

5. 평가

 

- 머신러닝 평가지표 함수들은 sklearn.metrics 모듈에 있다.


- accuracy(정확도)
    - 전체 데이터셋중 맞춘 개수의 비율

 

- '훈련데이터'와 '테스트 데이터' 두 가지를 평가 한다.

 

pred_train : Train dataset (Train할 때 사용한 데이터 셋) 의 Feature를 가지고 예측 

pred_test  : Test dataset (새로운 데이터 셋 - train 시 사용하지 않은 데이터 셋) 의 Feature를 가지고 예측

 

 

 

1) 평가 : 정확도 계산 함수를 통해 정확도 확인

 

- 평가지표 : 0 ~ 1 사이 실수

- 함수 : accuracy_score(정답, 예측한 결과)

from sklearn.metrics import accuracy_score 

acc_train = accuracy_score(y_train, pred_train) # (정답, 예측한 결과)
acc_test = accuracy_score(y_test, pred_test)

print('훈련데이터셋 정확도: {}, 테스트데이터셋 정확도: {}'.format(acc_train, acc_test))

 

- 정확도가 1 이 아니다.  뭐가 틀렸는 지는 Confusion Matrix를 통해 확인한다.

훈련데이터셋 정확도: 0.9666666666666667, 테스트데이터셋 정확도: 0.9333333333333333

 

 

2) 평가 : 혼동행렬 (Confusion Matrix) 을 통해 확인

 

    - 모델이 예측한 결과와 실제 정답간의 개수를 표로 제공
    - 분류의 평가 지표로 사용된다.

 

    - 함수 : confusion_matrix(정답, 예측한 결과)


    - axis=0: 실제(정답)

      axis=1: 예측

 

from sklearn.metrics import confusion_matrix
train_cm = confusion_matrix(y_train, pred_train) # (정답, 예측한 결과)
train_cm

 

# axis =0 : 예측 label 0,1,2
# axis=1 : 정답 label 0,1,2
# value :  예측한 갯수

# 답이 0인 40개의 데이터는 모두 예측 성공 하였다. / 답이 1인데 2로 예측한 게 1개 / 답이 2인데 1로 예측한 것이 3개

array([[40,  0,  0],
       [ 0, 39,  1],
       [ 0,  3, 37]], dtype=int64)

 

 

- pred_train_confusion_matrix 를 판다스 데이터 프레임으로

import pandas as pd
pred_train_cm = pd.DataFrame(train_cm, columns=[['예측', '예측', '예측'], iris.target_names], index=[['실제','실제','실제'], iris.target_names])
pred_train_cm

 

 

- pred_test_confusion_matrix 를 판다스 데이터 프레임으로

pred_test_cm = pd.DataFrame(test_cm, columns=[['예측', '예측', '예측'], iris.target_names], index=[['실제','실제','실제'], iris.target_names])
pred_test_cm

 

 

https://github.com/cso6005/Big-Date-Camp/blob/master/%EB%A8%B8%EC%8B%A0%EB%9F%AC%EB%8B%9D%20%EC%8B%A4%EC%8A%B5/01%20iris%20%EB%B6%84%EC%84%9D.ipynb

 

GitHub - cso6005/Big-Date-Camp

Contribute to cso6005/Big-Date-Camp development by creating an account on GitHub.

github.com