실제 데이터와 예측 데이터가 얼마나 같은가를 평가하는 지표다.
이진분류의 경우에는 데이터의 구성에 따라 모델의 성능을 왜곡할 수 있기 때문에 지표 하나만을 가지고 성능을 평가하지 않는다.
다음은 조건 하나만을 가지고 결정하는 별거 아닌 알고리즘의 높은 정확도를 나타내는 원인이 대해서 알아보겠다. BaseEstimator 클래스를 활용하면 학습을 하지 않은 모델을 통해 예측을 수행하기 때문에 아주 단순한 분류기이다.
from sklearn.base import BaseEstimator
class MyDummyClassifier(BaseEstimator):
# fit() 메서드는 아무것도 학습하지 않는다.
def fit(self,X,y=None):
pass
# predict() 메서드는 단순히 Sex 피처가 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
Python
복사
위의 모델을 사용해서 예측을 수행해보자.
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
from sklearn import preprocessing
import numpy as np
# 원본 데이터를 재로딩, 데이터 가공, 학습 데이터/테스트 데이터 분할
titanic_df = pd.read_csv('titanic_train.csv')
y_titanic_df = titanic_df['Survived']
X_titanic_df = titanic_df.drop('Survived',axis=1)
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 = MyDummyClassifier()
myclf.fit(X_train,y_train)
mypredictions = myclf.predict(X_test)
print('Dummy Classifier의 정확도는: {0:.4f}'.format(accuracy_score(y_test,mypredictions)))
'''
Dummy Classifier의 정확도는: 0.7877
'''
Python
복사
이런 단순한 알고리즘으로 예측해도 그 정확도가 78% 로 큰 차이가 나지 않는 것을 확인할 수 있다. 따라서 정확도를 평가 지표로 사용할 때는 매우 신중해야 한다.
정확도는 불균형한 레이블 값 분포를 가진 데이터에서 사용하기에는 적절하지 않다.
다음은, MNIST 데이터 세트를 불균형하게 변형하고 정확도 지표를 사용해서 어떤 문제가 발생하는지 확인해보겠다.
먼저, 사이킷런에서 MNIST 데이터는 load_digits() API를 통해 제공한다. MNIST는 분류 중에도 멀티 분류를 위한 데이터셋이다. 우리는 이진분류를 볼 것이기 때문에 레이블 값이 7인 경우에 True, 그 외에는 False로 변환시키겠다. —> 이런 변환은 레이블 값 분포를 불균형하게 만들 것이다.
만약, 이런 데이터셋에서 모든 데이터를 False로 예측하는 모델이 있다면 그 정확도는 90%나 될 것이다. 이런 부분이 문제가 될 것이다.
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
from sklearn import preprocessing
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()
# 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) # test_size 의 default는 0.2
# y_test의 분포도 확인
print('레이블 테스트 세트 크기:', y_test.shape)
print('테스트 세트 레이블 0 과 1의 분포도')
print(pd.Series(y_test).value_counts())
'''
레이블 테스트 세트 크기: (450,)
테스트 세트 레이블 0 과 1의 분포도
0 405
1 45
dtype: int64
'''
# Dummy Classifier로 학습/예측/평가
fakeclf = MyFakeClassifier()
fakeclf.fit(X_train,y_train)
fakepred = fakeclf.predict(X_test)
print('모든 예측을 0으로 하여도 정확도는: {:.3f}'.format(accuracy_score(y_test,fakepred)))
'''
모든 예측을 0으로 하여도 정확도는: 0.900
'''
Python
복사
결론은 불균형한 레이블 데이터 세트에는 정확도를 평가 지표로 사용하면 안된다.