728x90
1. Classification 성능 평가 지표
Parameter 넣을 때 (y_test, y_pred) 순서대로 넣어야 함!!
Classification (분류) 성능 평가 지표
- 정확도(Accuracy)
- 오차행렬(Confusion Matrix)
- 정밀도(Precision)
- 재현율(Recall)
- F1 Score
- ROC AUC : Binary Classification에서 많이 사용
정확도(Accuracy)
- $정확도(Accuracy) = \frac {예측 \: 결과가\: 동일한\: 데이터\: 건수} {전체\: 예측\: 데이터\: 건수}$
- 정확도는 직관적으로 모델 예측 성능을 나타내는 평가지표
- 하지만 Binary Classification의 경우 데이터의 구성에 따라 ML 모델의 성능을 왜곡할 수 있기 때문에 정확도 수치 하나만 가지고 성능을 평가하지 않음
- 정확도는 이진분류의 불균형한(imbalanced) Label 값(Target 값) 분포에서 ML 모델의 성능을 판단할 경우 적합한 평가지표가 아님
** Q & A 답변 발췌 **
분류 학습을 위해서는 개별 레이블(타겟값) 별로 어느정도 데이터 셋이 필요한데, 그렇지 못한 경우를 얘기합니다. 위암 판정 모델을 만들어야 하는데, 정상인 상태와 암인 상태의 데이터가 모두 필요합니다.
정상인 경우는 데이터가 10,000개 정도 있는데, 암인 경우는 100건 밖에 없다고 할때 정확도를 모델을 판단하는 중요 지표로 설정하면 모두 정상이라고 찍어도(?) 정확도는 10000/10100 도 99% 이상 나옵니다. 따라서 정확도는 이런 불균일한 데이터 셋에서 모델 성능 지표로 사용할 수 없습니다.
더구나 암 진단 모델이라면 암을 정확히 진단했는지가 훨씬 더 중요합니다. 암을 정상이라고 판단하면 큰 문제가 생기기 때문입니다. 정상을 정상이라고 판단하는것의 중요성 보다, 암을 암이라고 판단하는 중요성이 훨씬 크기 때문에 이를 감안할 수 있는 재현율 같은 지표를 이런 불균일한 데이터 세트에서는 성능 지표로 더 잘 활용합니다.
Ex) 적은 수의 결괏값에 Positive(1)를 설정하고 그렇지 않은 경우 Negative(0)
- 사기 행위 예측 모델 ( 사기행위 = Positive(1) , 정상행위 = Negative(0) )
- 암 검진 예측 모델 ( 암일 경우 = Positive(1), 암이 아닐 경우 = Negative(0) )
그 결과
- Positive 데이터 건수가 매우 작기 때문에 데이터에 기반한 머신러닝 알고리즘은 Positive보다는 Negative로 예측정확도가 높아지는 경향이 발생함
- TN은 매우 커지고, TP는 매우 작아짐
- FN와 FP 역시 매우 작아짐
결과적으로 정확도 지표는 비대칭한 데이터 세트에서 Positive에 대한 예측 정확도를 판단하지 못한 채 Nagative에 대한 예측 정확도만으로 분류의 정확도가 매우 높게 나타나는 수치적 판단 오류를 일으킨다.
- titanic에서 여자는 살리고, 남자는 죽는 것으로 예측하면 정확도가 약 78%가 나옴
import numpy as np
from sklearn.base import BaseEstimator
class MyDummyClass(BaseEstimator):
# fit() method는 아무것도 학습하지 않음
def fit(self, X, y=None):
pass
# predict() method는 단순히 Sex Feature가 1이면 0, 그렇지 않으면 1로 예측함
def predict(self, X):
pred = np.zeros((X.shape[0], 1))
for i in range(X.shape[0]):
if X["Sex"].iloc[i] == 1:
pred[i] = 0
else:
pred[i] = 1
return pred
import pandas as pd
from sklearn.preprocessing import LabelEncoder
# Null 처리 함수
def fillna(df):
df["Age"].fillna(df["Age"].mean(), inplace=True)
df["Cabin"].fillna("N", inplace=True)
df["Embarked"].fillna("N", inplace=True)
return df
# ML Algorithm에 불필요한 Feature 제거
def drop_features(df):
df.drop(["PassengerId", "Name", "Ticket"], axis=1, inplace=True)
return df
# Label Encoding 수행
def format_features(df):
df["Cabin"] = df["Cabin"].str[0]
features = ["Cabin", "Sex", "Embarked"]
for feature in features:
le = LabelEncoder()
le.fit(df[feature])
df[feature] = le.transform(df[feature])
return df
# 앞에서 설정한 DataPreprocessing 함수 호출
def transform_features(df):
df = fillna(df)
df = drop_features(df)
df = format_features(df)
return df
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
# 원본 데이터를 재로딩, 데이터 가공, 학습 데이터/테스트 데이터 분할
titanic_df = pd.read_csv("./titanic_train.csv")
X_titanic_df = titanic_df.drop(["Survived"], axis=1)
y_titanic_df = titanic_df["Survived"]
# Data Preprocessing 수행
X_titanic_df = transform_features(X_titanic_df)
X_train, X_test, y_train, y_test = train_test_split(
X_titanic_df, y_titanic_df, test_size=0.2, random_state=0
)
# 위에서 생성한 Dummy Classifier를 이용하여 학습/예측/평가 수행
myclf = MyDummyClass()
myclf.fit(X_train, y_train)
mypredictions = myclf.predict(X_test)
print(f"Dummy Classifier의 정확도는 {accuracy_score(mypredictions, y_test):.4f}")
# Dummy Classifier의 정확도는 0.7877
- MNIST 데이터 세트
- 2차원 Data의 경우 len(X)와 X.shape[0]는 동일
from sklearn.datasets import load_digits
from sklearn.model_selection import train_test_split
from sklearn.base import BaseEstimator
from sklearn.metrics import accuracy_score
import numpy as np
import pandas as pd
class MyFakeClassifier(BaseEstimator):
def fit(self, X, y):
pass
# 입력값으로 들어오는 X 데이터 셋의 크기만큼 모두 0값으로 만들어서 반환
def predict(self, X):
return np.zeros((len(X), 1), dtype=bool)
# 사이킷런의 내장 데이터 셋인 load_digits( )를 이용하여 MNIST 데이터 로딩
digits = load_digits()
print(digits.data)
print("### digits.data.shape:", digits.data.shape)
print(digits.target)
print("### digits.target.shape:", digits.target.shape)
- Binary Classification으로 변경
digits.target == 7
# array([False, False, False, ..., False, False, False])
# digits번호가 7번이면 True이고 이를 astype(int)로 1로 변환, 7번이 아니면 False이고 0으로 변환.
y = (digits.target == 7).astype(int)
X_train, X_test, y_train, y_test = train_test_split( digits.data, y, random_state=11)
# 불균형한 레이블 데이터 분포도 확인.
print("레이블 테스트 세트 크기 :", y_test.shape)
print("테스트 세트 레이블 0 과 1의 분포도")
print(pd.Series(y_test).value_counts())
# Dummy Classifier로 학습/예측/정확도 평가
fakeclf = MyFakeClassifier()
fakeclf.fit(X_train, y_train)
fakepred = fakeclf.predict(X_test)
print("모든 예측을 0으로 하여도 정확도는:{:.3f}".format(accuracy_score(y_test, fakepred)))
# 레이블 테스트 세트 크기 : (450,)
# 테스트 세트 레이블 0 과 1의 분포도
# 0 405
# 1 45
# dtype: int64
# 모든 예측을 0으로 하여도 정확도는:0.900
2. accuracy_score(y_pred, y_test)
- y_pred = model.predict(X_test)
score 속성 사용시 Paramter 순서 지키기: (X_test, y_test)
- Regression Model: model.score(X_test, y_test)로 $R^{2}$ 구현 가능
- Classification Model: model.score(X_test, y_test)로 $Accuracy$ 구현 가능
728x90