7 minute read

7 Model Evaluation(모델 평가)

#

7.1 Overfitting / Underfitting

Overfitting: 특정 데이터 셋에 과도하게 fit된 상태를 의미한다. training set은 정확도가 높지만, test set에 대해서는 정확도가 현저히 낮은 경우.

Underfitting: 더이터 셋에 fit이 잘되지 않은 상태. training set 과 test set 모두에 대한 정확도가 낮다.

좋은 ML 모델은 데이터의 종류와 상관없이 일반화된 모델이다. 고로, 오버피팅 및 언더피팅 현상을 피해야한다.

#

7.2 Cross-validation

오버피팅과 언더피팅을 방지하기위한 해결책으로 ‘cross-validation’이 있다.

주어진 데이터 셋에 대해서 Train set / Validation set / Test set 으로 분할하여 다양한 조합으로 학습을 진행하는 것을 ‘cross-validation’이라고 한다.

1. 전체 데이터 셋을 Train set 과 Test set으로 분할

2. Train set의 일부를 Validation set으로 분할

3. Train set으로 학습시켜 만들 모델에 validation set을 이용해서 hyperparameter를 정함

4. 그렇게 정해진 최종 모델로 Test set을 이용해 성능평가

#

7.3 Pipeline

Pipeline을 사용하면 데이터 전처리와 학습모델을 연결시켜 코드를 간결화할 수 있다.

- Pipeline 적용 전 학습과정

##standard Scaler
# 표준화 스케일러 설정
std_scale = StandardScaler()
# train set에 대한 scaling
X_tn_std = std_scale.fit_transform(X_tn)
# test set에 대한 scaling
X_te_std = std_sccale.transform(X_te)

##학습
# 선형 회귀 모델을 설정
clf_linear = LinearRegression()
# train data set을 이용하여 선형 회귀 모델을 적합시킨다. 
# X_tn 과 y_tn은 각각 데이터와 타깃데이터 pair이다. 
cls_linear.fit(X_tn_std, y_tn)

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

NameError                                 Traceback (most recent call last)

<ipython-input-2-f637e28dd414> in <module>
      1 ##standard Scaler
      2 # 표준화 스케일러 설정
----> 3 std_scale = StandardScaler()
      4 # train set에 대한 scaling
      5 X_tn_std = std_scale.fit_transform(X_tn)


NameError: name 'StandardScaler' is not defined

- Pipeline 적용 후 학습과정

from sklearn import datasets
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error 

raw_boston = datasets.load_boston()

X = raw_boston.data
y = raw_boston.target

X_tn, X_te, y_tn, y_te = train_test_split(X,y,random_state=7)
linear_pipeline = Pipeline([('scaler', StandardScaler()), ('linear_regression', LinearRegression())])

# 학습
linear_pipeline.fit(X_tn, y_tn)

# 예측
pred_linear = linear_pipeline.predict(X_te)

# 평가
mean_squared_error(y_te, pred_linear)
/usr/local/lib/python3.7/dist-packages/sklearn/utils/deprecation.py:87: FutureWarning: Function load_boston is deprecated; `load_boston` is deprecated in 1.0 and will be removed in 1.2.

    The Boston housing prices dataset has an ethical problem. You can refer to
    the documentation of this function for further details.

    The scikit-learn maintainers therefore strongly discourage the use of this
    dataset unless the purpose of the code is to study and educate about
    ethical issues in data science and machine learning.

    In this special case, you can fetch the dataset from the original
    source::

        import pandas as pd
        import numpy as np


        data_url = "http://lib.stat.cmu.edu/datasets/boston"
        raw_df = pd.read_csv(data_url, sep="\s+", skiprows=22, header=None)
        data = np.hstack([raw_df.values[::2, :], raw_df.values[1::2, :2]])
        target = raw_df.values[1::2, 2]

    Alternative datasets include the California housing dataset (i.e.
    :func:`~sklearn.datasets.fetch_california_housing`) and the Ames housing
    dataset. You can load the datasets as follows::

        from sklearn.datasets import fetch_california_housing
        housing = fetch_california_housing()

    for the California housing dataset and::

        from sklearn.datasets import fetch_openml
        housing = fetch_openml(name="house_prices", as_frame=True)

    for the Ames housing dataset.
    
  warnings.warn(msg, category=FutureWarning)





29.515137790197567

#

7.4 그리드 서치

ML 과정에서 관심 있는 매개변수들을 대상으로 학습을 가능하도록 만드는 방식을 의미한다

예로, K-nearestNeighbors 알고리즘으로 ML을 학습시키기 전에, 관심있는 K의 후보군을 정해 놓고 학습시킨 후 모형 성능을 비교한 후 최적의 K를 선정하는 방식.

- 그리드 서치 전체 코드

from sklearn import datasets
from sklearn.preprocessing import StandardScaler
from sklearn.neighbors import KNeighborsClassifier
from sklearn.model_selection import train_test_split

from sklearn.metrics import accuracy_score
from sklearn.metrics import confusion_matrix
from sklearn.metrics import classification_report

# 꽃 데이터 불러오기 
raw_iris = datasets.load_iris()

# feature / target
X = raw_iris.data
y = raw_iris.target

# spliting train / test set
X_tn, X_te, y_tn, y_te = train_test_split(X, y, random_state = 0)

# 표준화 스케일
std_scale = StandardScaler()
std_scale.fit(X_tn)
X_tn_std = std_scale.transform(X_tn)
X_te_std = std_scale.transform(X_te)

best_accuracy = 0

for k in [1,2,3,4,5,6,7,8,9,10]:
  clf_knn = KNeighborsClassifier(n_neighbors=k)
  clf_knn.fit(X_tn_std, y_tn)
  knn_pred = clf_knn.predict(X_te_std)
  accuracy = accuracy_score(y_te, knn_pred)
  if(accuracy > best_accuracy):
    best_accuracy = accuracy
    final_k = {'k': k}

print(final_k)
print(accuracy)

{'k': 3}
0.9736842105263158

#

7.5 손실 함수와 비용함수

7.5.1 손실함수와 비용함수의 개념

‘손실함수’는 ML을 통해 생성된 모델이 실제값(ground truth)와 얼마나 차이가 나는지 즉, 손실 정도를 수치로 나타내는 함수이다. 각 데이터 포인트마다의 예측값과 실젯값의 차이를 의미한다.

‘비용함수’는 데이터 셋 전체를 대상으로 하는 손실을 의미한다.

* 그러나 실제로는 loss function과 cost function을 구분 없이 사용하기도 함

7.5.2 L1 손실함수

L1 loss는 실젯값과 예측값의 차이에 기댓값을 취한 것이다.

L1 loss를 사용한 cost function으로 MAE(Mean Absolute Error)가 있다.

MAE는 L1 loss의 평균값(기댓값)이다.

7.5.3 L2 손실함수

L2 loss란 실젯값과 예측값 사이에 제곱을 취한 것이다

L2 loss를 사용한 cost function으로 MSE(Mean Squared Error), RMSE(Root Mean Squared Error)가 있다.

MSE는 L2 loss의 평균값(기댓값)이다.

RMSE는 MSE에 root를 씌워준 값이다.

MAE와 RMSE는 이상치(outliers)들에 민감하지 않지만, MSE는 제곱을 취해준 cost function이라 이에 민감한 편이다.

고로, 이상치에 중점을 두고 싶다면 MSE, 그렇지 않고 안정된 loss를 얻고 싶다면 MAE, RMSE를 쓰면 된다.

##7.5.4 엔트로피

* 엔트로피

엔트로피(entropy)란 정보 이론에서 사용하는 개념으로 확률 변수의 불확실성 정도를 측정하기 위해 사용, 하나의 확률분포가 대상이다.

엔트로피는 주로 의사결정나무에서 사용된다.(Decision Tree)

- Entropy(P) = -sigma{P(x)logP(x)} = -E(logP(x))

——————————————————————————–

* 크로스-엔트로피

크로스-엔트로피(cross-entropy)는 두 분포 P(x)와 Q(x)를 대상으로 엔트로피를 측정해 두 분포의 ‘차이’를 계산한다.

ML에서 cross-entropy를 사용할 때 P(x)는 실제 모델의 분포, Q(x)는 추정된 모델의 분포라고 설정.

- CrossEntropy(P,Q) = -sigma{P(x)logQ(x)} = -E(logQ(x))


* KLD(Kullback-Leibler Diverence)

머신러닝에서 자주 사용되는 손실 함수

상대적 엔트로피(relative entropy)라고도 불림

D-KL(P||Q) = sigma{P(x)log(P(x)/Q(x))}

= -sigma{P(x)logQ(x)} + sigma{P(x)logP(x)}

= -Ep(log(P(x)/Q(x)))


* NLL(Negative Log Likelihood)

- NLL = -log{f(xi|theta)}, (*theta is parameter to probability variable f(xi))

손실함수는 최소화 되야하므로 로그 가능도 함수는 최대화되어야한다.

고로, theta(MLE) = argmax-theta[sigma(1~n){log(f(xi|theta)}]

= argmax-theta[E{log(f(xi|theta)}]

인 theta를 찾아야한다.

손실함수 = 실제 모델 - 추정 모델 = log(f-true(xi|theta) - log(f(xi|theta))

비용함수는 위 손실함수에 기댓값 E를 씌우면 된다.

고로, cost function = log(f-true(x|theta) - E(log(f(x|theta))

~ -E(log(f(x|theta))

!!결국!! 여기서 -E(log(f(x|theta))가 크로스-엔트로피에 해당하기에, 내부의 로그 가능도 함수를 최대화시키는 것이 cross-entropy를 최소화하는 것이다!

즉, 로그 가능도 함수를 최대화시키는 파리미터 theta를 찾는 문제는 크로스-엔트로피를 최소화하는 theta를 찾는 문제와 동일하므로 NLL 또한 비용함수(손실함수)로 사용할 수 있는 것이다!

#

7.6 모형 성능평가

7.6.1 모형 성능 평가에 필요한 개념

1) TP(True Positive): 양성 예측, 실젯값도 양성

2) FN(False Negative): 음성 예측, 실젯값은 양성(오답)

3) FP(False Positive): 양성 예측, 실젯값은 음성(오답)

4) TN(True Negative): 음성 예측, 실젯값도 음성


* 정밀도(Precision)

양성으로 예측했을 때, 실제로 양성으로 나타나는 비율

= TP / TP + FP

* Recall, Sensitivity

실제로 양성인 사람이 양성으로 예측되는 비율

= TP / TP + FN

* Specificity

실제로 음성인 사람이 음성으로 예측되는 비율

= TN / FP + TN

* False Positive Rate(FPR)

실제로 음성인 사람이 양성으로 예측되는 비율

= 1 - (TN / FP + TN) = FP / FP + TN

* 정확도 (Accuracy)

전체 데이터 중 정답으로 분류되는 비율

= TP + TN / TP + TN + FP + FN

* Error rate

전체 데이터 중 오답으로 분류되는 비율

= FP + FN / FP + FN + TP + TN


7.6.1 분류 문제에서의 성능평가 (Classification)

*정확도(Accuracy)

= 1/n ( sigma{I(y^i = yi) )

I는 indicator function을 의미, y^i와 yi값이 동일하면 1, 아니면 0을 출력함

from sklearn.metrics import accuracy_score
y_pred = [0,2,1,3]
y_true = [0,1,2,3]

# 정확도(0~1) 출력
print(accuracy_score(y_true, y_pred))

# normalize 하지 않으면 예측값과 실젯값이 일치하는(정답인) 횟수 자체를 출력
print(accuracy_score(y_true,y_pred,normalize=False))

0.5
2

*F1 score

Precision과 recall의 조화평균값. 0부터 1사이 값으로 1에 가까울수록 좋은 성능

= 2 X (precision X recall) / (precision + recall)

*Confusion Matrix

예측값과 실젯값의 빈도를 행렬 형태로 확인 가능

Confusion Matrix A의 원소 aij는 i가 실젯값인데 j라고 예측한 횟수를 의미

즉, 대각원소는 예측값과 실젯값이 일치하는 경우들에 해당

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]])

*Classification report

여러가지 성능 점수를 분류 리포트를 통해 확인 가능

macro avg 는 라벨별로 가중치를 부여하지 않은 평균

weighted avg는 실젯값(y_true)의 클래스별 데이터 갯수

from sklearn.metrics import classification_report
y_true = [0,1,2,2,0]
y_pred = [0,0,2,1,0]
target_names = ['class 0', 'class 1', 'class 2']
print(classification_report(y_true, y_pred, target_names = target_names))
              precision    recall  f1-score   support

     class 0       0.67      1.00      0.80         2
     class 1       0.00      0.00      0.00         1
     class 2       1.00      0.50      0.67         2

    accuracy                           0.60         5
   macro avg       0.56      0.50      0.49         5
weighted avg       0.67      0.60      0.59         5

7.6.3 회귀 문제에서의 성능평가 (Classification)

*MAE

from sklearn.metrics import mean_absolute_error
y_true = [3,-0.5,2,7]
y_pred = [2.5,0.0,2,8]
print(mean_absolute_error(y_true,y_pred))
0.5

*MSE

from sklearn.metrics import mean_squared_error
y_true = [3,-0.5,2,7]
y_pred = [2.5,0.0,2,8]
print(mean_squared_error(y_true,y_pred))
0.375

*R2 score

R의 제곱값. 전체 모형에서 설명 가능한 분산의 비율.

0과 1사이 값을 가지며 1에 가까울수록 성능이 좋음

from sklearn.metrics import r2_score
y_true = [3,-0.5,2,7]
y_pred = [2.5,0.0,2,8]
print(r2_score(y_true,y_pred))
0.9486081370449679

7.6.4 군집 문제에서의 성능평가 (Clustering) - unsupervised

*Silhouette Score

서로 다른 군집이 얼마나 잘 분리되는지 나타내는 지표

같은 군집은 가까이, 다른 군집끼리는 멀리 떨어져 있을수록 높은 점수를 나타냄

-1 부터 1까지의 값을 가짐

높을수록 좋은 성능

from sklearn.metrics import silhouette_score

# feature 2개로 이루어진 데이터 5개 생성
X = [[1,2],[4,5],[2,1],[6,7],[2,3]]

# 해당 데이터마다 클래스를 설정 
labels = [0, 1, 0, 1, 0]
sil_score = silhouette_score(X, labels)
print(sil_score)
0.5789497702625118