[STUDY] 5월 3주차 - 이진분류, 성능분석, 오차행렬, 정밀도, 재현율

STUDY_05_3.ipynb

---------------------------------------------------------------------------------------------------------------------------

from sklearn.datasets import fetch_mldata


# 데이터 추가


# 이상하게 책에 있는 대로 fetch_openml 함수를 쓰니까 없는 함수라고 뜸

# 알아보니까 책 예전 버전에는 fetch_mldata를 썼는데 이 부분이 무슨 일인지 fetch_openml로 바뀜

# 일단 안 되니까 fetch_mldata 이걸로 데이터 불러봄

mnist = fetch_mldata('MNIST original')


print(mnist)

# - DESCR : 이 데이터가 무엇인지 설명함

# - data : 이미지의 픽셀마다 특성(0~255 사이의 픽셀이 gray값, 0이면 완전 검은색/255면 완전 흰색)

# - target : 레이블, 이미지가 어떤 숫자인지 나타내는 값(이것은 1이다, 이것은 4다.. 이렇게)

#  {

#       'DESCR': 'mldata.org dataset: mnist-original', 

#       'COL_NAMES': ['label', 'data'],

#       'target': array([0., 0., 0., ..., 9., 9., 9.]),

#       'data': 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]], dtype=uint8)

#  }


# 데이터 셋을 변수에 저장

# X : 이미지의 픽셀 데이터들

# y : 이미지가 어떤 숫자인지 나타내는 데이터들

X, y = mnist["data"], mnist["target"]

print(X.shape)

print(y.shape)


import matplotlib

import matplotlib.pyplot as plt


# 36000번째 픽셀 이미지를 보여준다

#  - 이미지 크기를 28X28 크기로 shape 지정

#  - binary 컬러 맵을 사용해서 그린다

#  - 각 픽셀은 nearest 보간 방식으로 사용해서 결정한다

#    > nearest 보간 방식 : 새로운 지점 또는 한 지점 값을 결정할 때 주변 분포한 값을 사용해 결정하는 것

some_digit = X[36000]

some_digit_image = some_digit.reshape(28, 28)

plt.imshow(some_digit_image,

           cmap = matplotlib.cm.binary,

           interpolation="nearest")


# 36000번째 값 레이블 확인

print(y[36000])


# 훈련-테스트 데이터 셋 분리

# - X_train : 0부터 59999 인덱스의 이미지 픽셀 데이터 (모델 훈련시킬 때 사용함)

# - X_test : 60000부터 69999 인덱스의 이미지 픽셀 데이터 (모델 테스트할 때 사용함)

# - Y_train : 0부터 59999 인덱스의 이미지가 무슨 숫자인지 나타내는 데이터 (모델 훈련시킬 때 사용함)

# - Y_test : 60000부터 69999 인덱스의 이미지가 무슨 숫자인지 나타내는 데이터 (모델 테스트할 때 사용함)

X_train = X[:60000]

X_test = X[60000:]

y_train = y[:60000]

y_test = y[60000:]


import numpy as np


# 훈련 데이터를 랜덤으로 섞음

# [numpy.random.permutation(x)]

#     <Parameters>

#         - x : int 값 혹은 배열

#               int 값이면 범위로 지장한 숫자를 랜덤하게 배열해서 반환함

#               배열 값이면 배열 인덱스를 랜덤하게 섞어서 반환함

#     <Example>

#       >>> np.random.permutation(10)  ----------->  array([1, 7, 4, 3, 0, 9, 2, 5, 8, 6])

#       >>> np.random.permutation([1, 4, 9, 12, 15])   ------------>  array([15,  1,  9,  4, 12])


shuffle_index = np.random.permutation(60000)

X_train, y_train = X_train[shuffle_index], y_train[shuffle_index]


# 이진 분류기 훈련 ---------> 이것은 5인가 아닌가

y_train_5 = (y_train == 5)

y_test_5 = (y_test == 5)


# 확률적 경사 하강법 분류기 만들기

# [경사하강법]

#     y = wx + b라는 함수 식이 있으면 가장 오차가 적게되는 w와 b를 구하는 방법이다.

#     특히 함수가 어렵고 복잡하여 수학적 접근 방법으로 풀기 어려운 문제에도 잘 동작.

#     2차원 cost 함수 위에서 경사도 0에 근접하도록 쭉쭉 내려갈때 쓰는 그거

# [확률적 경사하강법은 그냥 경사하강법이랑 뭐가 다르나]

#     경사 하강법은 모든 훈련 데이터에서 대해서 값을 평가하고 매개변수 업데이트를 진행 --> 속도 드림

#     확률적 경사하강법은 확률적으로 선택한 데이터에 대해서 값을 평가하고 매개변수를 업데이트 --> 속도 더 빠름

#     확률적 경사하강법은 일반 경사하강법이랑 방식은 같긴 한데

#     데이터 다 하는게 아니고 랜덤하게 하나 찝어서 cost 함수 위에서 올라갈지 말지를 정하니까 속도 빠름


from sklearn.linear_model import SGDClassifier


# [SGDClassifier]

#     <Parameter>

#        - max_iter : 최대로 통과할 수 있는 데이터의 수

#        - random_state : 데이터를 셔플 할 때 사용할 의사 난수 생성 프로그램의 시드

sgd_clf = SGDClassifier(max_iter=5, random_state=42)


# [fit]

#   <Parameter>

#        - X : 학습할 데이터

#        - y : 목표 값

sgd_clf.fit(X_train, y_train_5)


# 만든 확률적 경사하강법 분류기로 예측해보기

#     - 예측 실패하면 이렇게 나온다 -------> array([False])

#     - 예측 성공하면 이렇게 나온다 -------> array([ True])

sgd_clf.predict([some_digit])


# 교차검증을 써서 모델 성능 평가하기

# [k-fold 교차검증]

#    학습 데이터를  K개의 폴드로 나눠서 교차검증하는 방식이다.

from sklearn.model_selection import cross_val_score


# [cross_val_score]

#    - 첫번째 인자(sgd_clf) : 검증 할 모델

#    - 두번째 인자(X_train) : 검증 할 훈련 데이터

#    - 세번째 인자(y_train_5) : 예측하려고하는 대상 변수

#    - cv : 검증 fold 수(디폴트로는 3개)

#    - scoring : 모델 평가 지표(디폴트로는 "accuracy", 정확도)

# 호출 결과 이런 값이 나온다. 각 폴드 당 계산 된 모델 성능을 의미한다/ (매번 조금씩 다르다)

#    > array([0.9618 , 0.9629 , 0.96545])

cross_val_score(sgd_clf, X_train, y_train_5, cv=3, scoring="accuracy")


# 오차행렬 만들기

# [오차행렬]

#    클래스 A의 샘플이 B로 분류 된 횟수를 세어서 행렬로 나타낸 것

#       ex> 숫자 1 이미지가 2로 분류 된 횟수를 알고싶다 ----> 오차행렬의 1행 2열을 본다

#    오차 행렬을 만드려면 실제 타깃(여기서는 y_train_5)과 비교할 수 있도록 예측값을 만들어야 한다.

from sklearn.model_selection import cross_val_predict


# [cross_val_predict]

#    - 첫번째 인자(sgd_clf) : 대상 모델

#    - 두번째 인자(X_train) : 적용할 데이터

#    - 세번째 인자(y_train_5) : 예측하려고 하는 대상 변수

#    - cv : 폴드 수

#[cross_val_predict와 cross_val_score의 다른 점]

#    > cross_val_score함수는 평가 결과 점수를 반영하지만, corss_val_predict는 각 테스트 케이스의 결과를 반영한다

#    > cross_val_score 

#        -> 폴드 1의 첫번째 데이터 검증

#        -> 폴드 1의 두번째 데이터 검증

#        -> 폴드 안에 데이터 모두 검증 해서 폴드 1의 성능을 확률(0.0~1.0사이) 값으로 나타냄

#          > array([0.9618 , 0.9629 , 0.96545])    --->   3개 폴드 적용한 평가치

#    > cross_val_predict

#        -> 폴드 1의 첫번째 데이터 검증

#        -> 폴드 1의 두번째 데이터 검증 

#        -> 폴드 안에 데이터 각각 검증 한 값을 배열 안에다 저장함

#          > [False False False ... False False False]

y_train_pred = cross_val_predict(sgd_clf, X_train, y_train_5, cv=3)


# confusion_matrix 만들어서 오차행렬 만들기

from sklearn.metrics import confusion_matrix


# [confusion_matrix]

#    분류의 정확성을 평가하기위한 오차 행렬을 반환함

#    - 첫번째 인자(y_train_5) : 원래 정답

#    - 두번째 인자(y_train_pred) : 모델이 분류 한 정답

#    호출하면 이렇게 나온다

#        array([[54020,   559],

#               [ 1708,  3713]])

#    각 위치에 값들이 뜻하는 것

#        array([[5아닌데 5아니라고 잘 분류한 횟수,   5아닌데 5라고 잘못 분류한 수],

#                5맞는데 5아니라고 잘못 분류한 횟수, 5맞는데 5라고 잘 분류한 횟수])

confusion_matrix(y_train_5, y_train_pred)


# [정밀도]

# 정밀도 = TP/(TP+FP)

#        > TP : 진짜 양성의 수(5 맞는데 5라고 잘 분류한 횟수)

#        > FP : 거짓 양성의 수(5 아닌데 5라고 잘못 분류한 횟수)

#        ----> FP가 0 에 가까울 수록 정확도가 높다


# [재현율]

# 분류기가 정확하게 감지한 양성 샘플의 비율

# 재현율 = TP / (TP+FN)

#        > TP : 진짜 양성의 수(5 맞는데 5라고 잘 분류한 횟수)

#        > FN : 거짓 음성의 수(5인데 5 아니라고 잘못 분류한 횟수)

#        ----> 역시 FN가 0 에 가까울 수록 정확도가 높다


from sklearn.metrics import precision_score, recall_score


# 정밀도 출력

print(precision_score(y_train_5, y_train_pred))


# 재현율 출력

print(recall_score(y_train_5, y_train_pred))


# [F1 점수]

#    정밀도와 재현율의 조화평균

#    F1 점수 = TP * ( TP + ( (FN + FP) / 2 ) )

from sklearn.metrics import f1_score

print(f1_score(y_train_5, y_train_pred))


# [왜 굳이 정밀도와 재현도를 나눠가면서 계산하나]

#    도둑 방범 시스템

#       ---> 정확도는 낮더라도 재현률이 높으면

#            도둑 안들었을 때 도둑 들었다고 경비원이 귀찮게 호출 될 지언정(낮은 정밀도)

#           도둑 들었을 때 도둑 안들었다고 잘못 판별하는것은 막을 수 있다.(높은 재현율)


# [정밀도/재현율 트레이드오프]            

#    정밀도를 올리면 재현율이 줄고 재현율을 올리면 정밀도가 내려가는 현상



  Comments,     Trackbacks
최근 작성 글
최근 작성 댓글
최근 작성 트랙백
프로필
공지사항
글 보관함
캘린더
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
TODAY TOTAL