본문 바로가기
  • 문과생의 백엔드 개발자 성장기
|Playdata_study/AI

210806_MachinLearning 3 (Random Forest, Confusion Matrix)

by 케리's 2021. 8. 9.

지도학습 

 

1. 분류

2. 회귀 

   2.1 Linear Regression 

 

 

 

분류모델의 성능평가 (정답 률 맞추기 위함)

 

1. score ()

   : 내부적으로 predict 사용 (x_test, y_test) → predict, y_test 비교

2. accuracy_score()

   : 먼저 predict를 사용 후에 비교

 

 

 

분류모델의 성능 평가 지수

 

1. Accuracy

    : 일반적으로 Accuracy 가 높으면 precision, Recall 지수도 높아진다.

      일반적이지 않은 경우를 위해 정리를 해야한다.

2. precision : 정밀도

3. Recall : 재현율

 

 

 

 

Decision Tree

 

 

엔트로피 지수

 

   : (0~1) 0에 가까울수록 좋다, 엔트로피가 1이면 불순도가 최대 

     0에 가까울 수록 한 영역에  타깃이 하나 존재할 가능성이 높다. 

 

 

트리의 특성중요도 

 

특성 중요도(feature importance)는 트리를 구성하는데 얼마나 중요한 속성인가를 평가하는 값

이 값은 0과 1 사이의 값, 특성 중요도의 전체 합은 1이다.

 

 

장점

 

알고리즘 단순 : 속도가 빠름, 대용량 data에 적합 

 

 

단점

 

유연하게 나누기 어렵다.

직각으로만 나누어지고 곡선형이 나누어 지지 않는다.


실습

 

06_ML_DecisionTree_cancer

 

from sklearn.tree import DecisionTreeClassifier
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
cancer = load_breast_cancer()
cancer
# ----- 결과

{'data': array([[1.799e+01, 1.038e+01, 1.228e+02, ..., 2.654e-01, 4.601e-01,
         1.189e-01],
        [2.057e+01, 1.777e+01, 1.329e+02, ..., 1.860e-01, 2.750e-01,
         8.902e-02],
        [1.969e+01, 2.125e+01, 1.300e+02, ..., 2.430e-01, 3.613e-01,
         8.758e-02],
        ...,
        [1.660e+01, 2.808e+01, 1.083e+02, ..., 1.418e-01, 2.218e-01,
         7.820e-02],
        [2.060e+01, 2.933e+01, 1.401e+02, ..., 2.650e-01, 4.087e-01,
         1.240e-01],
        [7.760e+00, 2.454e+01, 4.792e+01, ..., 0.000e+00, 2.871e-01,
         7.039e-02]]),
 'target': array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1,
 ...]])}

 

 

1  SKLEARN DATA 조회 및 핸들링 하기

 

X = cancer.data # 속성 데이터 입력
y = cancer.target # 라벨 데이터 할당
print("Feature_Names \n", cancer.feature_names)
print('*'*100)
print("Target_Names \n", cancer.target_names)
print('*'*100)
print("Cancer Data Shape \n", cancer.data.shape)
# ----- 결과

Feature_Names 
 ['mean radius' 'mean texture' 'mean perimeter' 'mean area'
 'mean smoothness' 'mean compactness' 'mean concavity'
 'mean concave points' 'mean symmetry' 'mean fractal dimension'
 'radius error' 'texture error' 'perimeter error' 'area error'
 'smoothness error' 'compactness error' 'concavity error'
 'concave points error' 'symmetry error' 'fractal dimension error'
 'worst radius' 'worst texture' 'worst perimeter' 'worst area'
 'worst smoothness' 'worst compactness' 'worst concavity'
 'worst concave points' 'worst symmetry' 'worst fractal dimension']
****************************************************************************************************
Target_Names 
 ['malignant' 'benign'] # 악성, 양성
****************************************************************************************************
Cancer Data Shape 
 (569, 30)

 

 

dir(cancer)
# --- 결과 
['DESCR',
 'data',
 'feature_names',
 'filename',
 'frame',
 'target',
 'target_names']

 

import numpy as np

# dir(cancer)
# Class 의 Balance를 반드시 확인해야 한다.
# ImBalance Data는 머신러닝 넣기전에 반드시 처리한 후 학습해야 한다.

np.bincount(cancer.target)
cancer.target[cancer.target==0].shape
cancer.target[cancer.target==1].shape
# --- 결과 
# class 의 balance 를 확인해야한다.

array([212, 357], dtype=int64)
(212,)
(357,)

 

sklearn.dataset 한눈에 보기 

print("1. cancer.keys() : \n{}".format(cancer.keys()))
print("2. Shape of Cancere Data : \n{}".format(cancer.data.shape))
print("3. Sample Count per Class : \n{}".format(
        {n: v for n, v in zip (cancer.target_names, np.bincount(cancer.target))}
       ))
print("4. Feature Name : \n{}".format(cancer.feature_names))
# ----- 결과 

1. cancer.keys() : 
dict_keys(['data', 'target', 'frame', 'target_names', 'DESCR', 'feature_names', 'filename'])


2. Shape of Cancer Data : 
(569, 30)


3. Sample Count per Class : 
{'malignant': 212, 'benign': 357}


4. Feature Name : 
['mean radius' 'mean texture' 'mean perimeter' 'mean area'
 'mean smoothness' 'mean compactness' 'mean concavity'
 'mean concave points' 'mean symmetry' 'mean fractal dimension'
 'radius error' 'texture error' 'perimeter error' 'area error'
 'smoothness error' 'compactness error' 'concavity error'
 'concave points error' 'symmetry error' 'fractal dimension error'
 'worst radius' 'worst texture' 'worst perimeter' 'worst area'
 'worst smoothness' 'worst compactness' 'worst concavity'
 'worst concave points' 'worst symmetry' 'worst fractal dimension']

 

for i , name in enumerate(cancer.feature_names):
    print("%02d : %s" %(i,name))
# ---- 결과

00 : mean radius
01 : mean texture
02 : mean perimeter
03 : mean area
04 : mean smoothness
05 : mean compactness
06 : mean concavity
07 : mean concave points
08 : mean symmetry
09 : mean fractal dimension
10 : radius error
11 : texture error
12 : perimeter error
13 : area error
14 : smoothness error
15 : compactness error
16 : concavity error
17 : concave points error
18 : symmetry error
19 : fractal dimension error
20 : worst radius
21 : worst texture
22 : worst perimeter
23 : worst area
24 : worst smoothness
25 : worst compactness
26 : worst concavity
27 : worst concave points
28 : worst symmetry
29 : worst fractal dimension

 

 

 

2  Split and Shuffle

 

X_train, X_test, y_train, y_test = train_test_split(X,y,test_size=0.2, random_state=42)

 

3  모델생성

 

dTree = DecisionTreeClassifier()
dTree.fit(X_train,y_train)
# --- 결과 

DecisionTreeClassifier()

 

3.1 예측 

 

pred = dTree.predict(X_test)
pred
# ---- 결과

array([1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1,
       0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1,
       1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1,
       0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0,
       1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1,
       0, 1, 1, 0])

 

 

4  성능평가

 

from sklearn.metrics import accuracy_score
score = accuracy_score(pred, y_test, normalize=False) # 정확히 예측한 데이터의 건수
score = accuracy_score(pred, y_test, normalize=True) # 정확히 예측한 확률값
score
# ---- 결과 

0.9385964912280702

 

 

5  특성중요도

 

print("특성중요도 : \n{}".format(dTree.feature_importances_))
# --- 결과 

특성중요도 : 
[0.         0.02766931 0.         0.         0.         0.
 0.         0.69141955 0.         0.         0.01198257 0.00627578
 0.         0.         0.00123678 0.         0.         0.01593081
 0.         0.01855447 0.05229927 0.04018466 0.05149396 0.
 0.00923319 0.         0.         0.07371964 0.         0.        ]

 

import matplotlib.pyplot as plt

def plot_feature_importances(model):
    n_feature = cancer.data.shape[1]
    plt.barh(range(n_feature), model.feature_importances_, align='center')
    plt.yticks(np.arange(n_feature), cancer.feature_names)
    plt.xlabel('Feature Importances')
    plt.ylabel("Feature")
 
plot_feature_importances(dTree)

 

 

6  시각화

 

import graphviz
from sklearn.tree import export_graphviz
export_graphviz(dTree, out_file="cancer_tree.dot",
                class_names = cancer.target_names,
                feature_names = cancer.feature_names,
                impurity = True, 
                filled = True 
               )

with open('cancer_tree.dot', encoding='utf-8') as f:
    dot_graph = f.read()
    
dot = graphviz.Source(dot_graph)
display(dot)

dot.render(filename="cancer_tree.png")


 

Ensemble 

Random Forest

 

* Random Forest is a Ensemble 

 

 

 

 

앙상블 알고리즘 

  : Bagging, Boosting 기법이 있다, 둘 다 모델을 구성하는 기본 요소로 Decisiont Tree를 사용한다. 

 

   즉,  Feature 중 랜덤으로 일부의 Feature 만 선택해서 하나의 결정트리를 만들고 또 랜덤으로 일부의 Feature을 선택해서 또 다른 결정트리를 만들고 ...  이렇게 계속 반복하여 여러 개의 결정트리를 만든다.

  결정 트리 하나마다 예측값을 출력하게 되고, 그 예측 값들 중 가장 많이 나온 값을 최종 예측값으로 정한다. (다수결)

 

이렇게 의견을 통합하거나 여러가지 결과를 합치는 방식 "앙상블(Ensemble)" 이라 한다.

 

 

* Bagging(Bootstrap Aggregation)이 방법으로 학습한 모델이 Random Forest 

 

   : 각각의 Tree는 예측을 비교적 잘 할 수도 있지만 일부 데이터에 오버피팅 되는 경향을 보인다. 

     오버 피팅된 Tree를 많이 만들고 각각 Tree들의 결과를 평균 냄으로 써 Tree 성능은 높이고 과대 적합되는 양상은 줄일 수 있다. (다수결의 결과를 따름, 정확도는 약간 떨어지는 경향이 있음)

 

 

1) 여러개의 머신러닝 모델을 연결하여 강력한 모델을 만드는 기법

2) 조금씩 다른 Decision Tree 여러개를 많이 만들어야 효과가 있다.

3) Tree 생성시 데이터를 랜덤하게 부분, 중복 추출해서 만든다.

4) 일반적으로 N개의 데이터가 있다면 root n개의 데이터를 부분적으로 만든다.

 

※ 여러개의 Training Data를 생성해서 각 데이터마다 의사결정나무 모델을 구축

    → Bagging 기법 사용됨

 

 

 

Random Forest 는 여러개의 Decision Tree로 이뤄진 숲

Bagging 알고리즘은 학습 데이터 셋에서 무작위로 추출된 중복된 데이터를 꺼내어 각각의 DecisionTree를 생성.

이를 학습 시키는 방법이다.

이때 Scikit-learn에서 제공하는 RandomForest API는 bootstrap원리가 적용된다.

Underfitting 을 낮출 수 있다 = Bias 높은 문제를 해결한다

 

 

※ Boostrap : Random Sampling 적용하는방법 

※ Aggregation 

   : 각각의 Sampling (Decision Tree)에서 나온 결과들을 다수결의 원칙 혹은 평균에 의해서 집계하는 방법 

 

 

 

✔ Random Forest Parameter 

 

- n_estimators

   : 랜덤 포레스트 안의 결정 트리 갯수 

     n_estimators는 클수록 좋음. 결정 트리가 많을 수록 더 깔끔한 Decision Boundary 생성

     하지만 메모리와 훈련 시간이 증가 

 

 

- max_features

   : 무작위로 선택할 Feature의 개수

     max_features = n_features 이면 30개의 feature 중 30개의  feature 모두를 선택해 결정 트리 생성

     max_features 값이 크면 랜덤 포레스트의 트리들이 매우 비슷해지고 가장 두드러진 특성에 맞게 예측

     max_features 값이 작으면 랜덤 포레스트의 트리들이 서로 매우 달라질 것이고 오버피팅이 줄어들 것임

 

 

 

 

* 주의할점 

 

랜덤 포레스트는 랜덤하기 때문에 Random_state를 다르게 지정하면 전혀 다른 모델이 만들어짐

당연히 랜덤 포레스트의 트리가 많을수록 random_state 값의 변화에 따른 변동이 적음 

랜덤 포레스트는 텍스트 데이터와 같이 매우차원(feature의 갯수가)이 높고 희소한 데이터(colums수에 비해 row가 적은)에는 잘 작동하지 않음 

이러한 데이터에는 선형 모델이 더 적합

메모리를 많이 사용하기에 훈련과 예측이 느림

 

 

 

* Boosting 이 방법으로 학습한 모델이 Gradient Boosting 

 

 

 

Confusion Matrix 

 

 

뒤쪽의 PN(Positive, Negative)  : 모델이 예측한 값이 True(P)인지 False(N)인지 의미 -> 먼저 해석

앞쪽의 TF : 모델이 예측한 값이 맞는지(T) 맞지않는지(F) 의미 

 

 

 

 

  • True Positive(TP) : 실제 True인 정답을 True라고 예측 (정답)
  • False Positive(FP) : 실제 False인 정답을 True라고 예측 (오답)
  • False Negative(FN) : 실제 True인 정답을 False라고 예측 (오답)
  • True Negative(TN) : 실제 False인 정답을 False라고 예측 (정답)

 

 

- Precision : 모델이 True 라고 예측한 것 중에서 실제 True인 것의 비율 

                 c / c+b

- Recall : 실제 True인 것중에서 모델이 True라고 예측한 것의 비율 (일반적으로 더 중요하게 생각함)

              c / a + c

 

 

Class가 ImBalance 할 때

그 떄 사용되는 성능지표가 Precision, Recall 


 

07_ML_RF_iris

 

1  머신러닝단계 Pipe Line

 

데이터 로드 → 모델학습 → 예측과 평가하기
크게 세가지 프로세스로 나뉜다.
분류모델에서 평가부분은 정확도(Accuracy)와 오차행렬(Confusion Matrix)을 살펴보자

 

 

2  Bagging 알고리즘

RandomForest 모델에서 사용하는 대표적인 알고리즘
Sample 추출하는 방법을 Bootstrap 에서 가져오고
최종적으로 결과를 예측하는 방법을 Aggregation으로 한다.

사이킷런은 RandomForestClassifier 클래스를 통해서 해당 알고리즘 모델을 생성하도록 지원한다.

 

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn import datasets
from sklearn.model_selection import train_test_split
iris = datasets.load_iris()
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],
        [4.9, 3.1, 1.5, 0.1],
        [5.4, 3.7, 1.5, 0.2],
        [4.8, 3.4, 1.6, 0.2],])}
iris = datasets.load_iris()
iris

X_train, X_test, y_train, y_test = train_test_split(iris.data, iris.target, test_size=0.2)

 

 

3  RandomForest Model Generator

 

from sklearn.ensemble import RandomForestClassifier

# n_estimators=100은 디시즌트리 100 개로 만들겠다는 뜻
model = RandomForestClassifier(n_estimators=100, random_state=42)
# model = RandomForestClassifier(random_state=42)

model.fit(X_train, y_train)
RandomForestClassifier(random_state=42)

 

 

pred = model.predict(X_test)
from sklearn.metrics import accuracy_score
accuracy = accuracy_score(pred,y_test)
accuracy
# --- 결과

0.9666666666666667

 

 

from sklearn.metrics import accuracy_score, precision_score, recall_score
from sklearn.metrics import classification_report

pricision = precision_score(pred, y_test, average='weighted')#예측값, 정답값
# weighted : 각 클래스에 속하는 표본의 갯수로 가중평균을 냄
recall = recall_score(pred, y_test, average='weighted')

print(pricision)
print(recall)

print('*'*100)
print(classification_report(pred,y_test))
# ---- 결과 

0.9703703703703703
0.9666666666666667
****************************************************************************************************
              precision    recall  f1-score   support

           0       1.00      1.00      1.00        10
           1       1.00      0.92      0.96        12
           2       0.89      1.00      0.94         8

    accuracy                           0.97        30
   macro avg       0.96      0.97      0.97        30
weighted avg       0.97      0.97      0.97        30

 

 

4  Confusion Matrix

성능 지표에서 잘 활용하고 있는 오차행렬은
학습을 끝낸 모델이 예측을 수행하면서
얼마나 혼란스러워 하는지, 헷갈리고 있는 지를 잘 보여주는 지표

 

 : 대각선이 정답이다

 

 

from sklearn.metrics import confusion_matrix
y_true = [2,0,2,2,0,1] # 실제정답
y_pred = [0,0,2,2,0,2]

confusion_matrix(y_true,y_pred)
# ---- 결과

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

 

 

a = ['cherry','apple','apple','banana','cherry'] #label
b = ['banana','banana','apple','banana','cherry'] # prediction

confusion_matrix(a,b)
# --- 결과

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

 

a = ['cherry','apple','apple','banana','cherry'] #label
b = ['banana','banana','apple','banana','cherry'] # prediction

confusion_matrix(a,b,labels=['cherry','banana','apple'])
# --- 결과

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

 

cm = pd.DataFrame(confusion_matrix(y_test, pred),
                  columns=iris.target_names,
                  index=iris.target_names)
cm

 

sns.heatmap(cm, annot=True, cmap=plt.cm.Blues)

댓글