본문 바로가기

Codestates AI 부트캠프/2. Machine Learning

[머신러닝] 1-4 로지스틱 회귀 (Logistic Regression)

0. 분류 문제

분류 문제는 데이터가 속할 특정 범주(또는 특정 범주에 속할 확률)을 예측한다.

  • 이진 분류 : 타겟값이 두가지 범주인 경우 (Yes or No)
  • 다중 분류 : 타겟값이 세가지 이상의 범주인 경우 (Class1 or Class2 or Class3)



1. 로지스틱 회귀

로지스틱 회귀는 분류 문제에 쓰이는 선형회귀 알고리즘. 선형회귀에 시그모이드 함수를 씌워 확률을 구한다. 이진 분류 문제에 주로 쓰이는 방법으로서 0과 1사이의 값을 출력한다. 임계값(threshold)을 0.5로 지정해둔 경우, 출력값이 0.5 이상인 경우에 class 1을 반환하고, 0.5 미만인 경우 class 0을 반환한다. 

*만약 타겟값이 yes, no 등의 문자형일 경우 0과 1의 수치형으로 바꿔주어야 한다. 

*아래 그림에서 왼쪽은 이진 분류 데이터에 선형회귀를 적용한 것이다. 이 선형회귀에 시그모이드 함수를 씌우면 오른쪽과 같은 형태가 된다.

 


A. 기준모델 생성


통상 최빈 클래스의 값을 기준모델로 설정한다. 

# mode(): 최빈값을 반환한다
# 기준 모델 만들기
base = y_train.mode()
baseline = [base] * len(y_train)



B. 타겟 범주들의 비율 확인


종종 타겟변수가 1:9 등의 편중된 비율일 때가 있다. 이 경우 기준모델의 평가지표 점수가 굉장히 높아질 수 있다. 모든 행을 최빈값으로 예측해도 90%를 맞추기 때문이다. 그렇기에 편중된 타겟을 가진 분류 문제에서는 꼭 정확도에만 집착할 필요는 없다. 다양한 평가지표가 있기 때문이다.


이때 유독 비율이 큰 클래스가 있을 경우, 모델은 해당 클래스만 잘 맞추고 소수 클래스의 예측 지수는 떨어질 때가 있다.  이런 문제를 해결하기 위해서는 추후에 배울 resampling 또는 class weight를 이용할 수 있다. 

 


C. 스케일링, 인코딩

 

sklearn의 로지스틱 회귀모델은 디폴트로 12 penalty가 적용되는 정규화 모델. 따라서 모델을 만들기 전 표준화 작업은 필수다.

또, 문자형 변수를 인코딩해야 한다. 두가지 인코딩 방법을 배웠다. OneHotEncoder는 범주 별로 새 컬럼을 만들어 해당 범주에 해당되는지(1), 또는 해당되지 않는지(0)로 변환한다. OrdinalEncoder는 범주 별로 각각 다른 숫자를 매핑한다. 

 

# scaling
from sklearn.preprocessing import StandardScaler
numeric_feats = X_train.dtypes[X_train.dtypes != "object"].index

scaler = StandardScaler()
X_train[numeric_feats] = scaler.fit_transform(X_train[numeric_feats])
X_val[numeric_feats] = scaler.transform(X_val[numeric_feats])
X_test[numeric_feats] = scaler.transform(X_test[numeric_feats])


# One-Hot encoding
from category_encoders import OneHotEncoder

ohe = OneHotEncoder()

X_train_ohe = ohe.fit_transform(X_train)
X_val_ohe = ohe.transform(X_val)
X_test_ohe = ohe.transform(X_test)



D. 모델 생성 및 학습

 

logistic = LogisticRegression(class_weight='balanced')
logistic.fit(X_train_ohe, y_train)

 


E. 임계값 조정


로지스틱 회귀에서는 특정 범주에 속할 '확률'을 구할 수도 있다. 그리고 확률과 임계값을 비교하여 범주를 나누게 된다. 그러므로 이 임계값을 조정하면 특정 범주에 속할 데이터를 늘릴 수 있는 것이다.

 

# 확률 구하기
y_pred_proba = logistic.predict_proba(X_val_ohe)[:,1]

# 임계값 정하기
threshold = 0.3
y_pred = y_pred_proba > threshold

# 확률이 임계값보다 클 경우 True를, 작거나 같을 경우 False를 반환할 것이다
# True를 1로, False를 0으로 보면 된다



2. 분류 모델의 평가지표

 

A. Accuracy, Recall, Precision, F1 score


모델의 예측을 confusion matrix를 통해 시각적으로 확인할 수 있다. 

 


초록색 영역은 모델의 예측이 맞은 데이터의 갯수,  빨간색 영역은 모델의 예측이 빗나간 데이터의 갯수를 나타낸다.
 

from sklearn.metrics import plot_confusion_matrix
import matplotlib.pyplot as plt

fig, ax = plt.subplots()
pcm = plot_confusion_matrix(logistic, X_val_ohe, y_val,
                            cmap=plt.cm.Blues,
                            ax=ax)
plt.title(f'Confusion matrix of Logistic Regression, n = {len(y_val)}', fontsize=15)
plt.show()

 

 

 

위에서 말했든 정확도가 절대적인 지표가 될 수 없다. 또 케이스에 따라 1의 recall, 0의 precision 등이 중요할 수 있다. 그러므로 문제가 무엇인지 파악하고 가장 중요한 지표가 무엇인지 결정해야 모델을 잘 조율할 수 있다. f1은 recall과 precision을 모두 고려한 지표이기 때문에 대표적으로 쓰는 지표다.

이 모든 지표를 한눈에 보는 코드는 아래와 같다.

from sklearn.metrics import classification_report

print(classification_report(y_train, y_train_pred))

 

 

B. roc_auc score

 

위의 지표들은 모두 모델이 반환하는 '범주'를 기준으로 모델을 평가했다. 하지만 AUC score는 모델이 예측하는 '확률'을 평가한다.  그래서 분류 결과보다 모델의 예측 확률값 자체가 중요한 영화 추천 알고리즘, 의학 등의 분야에서 많이 쓰인다. 

ROC Curve는 여러 임계값에 대해 TPR(True Positive Rate, recall)과 FPR(False Positive Rate)을 그래프로 보여준다. TPR은 전체 positive 중 맞힌 비율이고, FPR은 전체 negative 중 틀린 비율이다. 그러므로 TPR은 최대가 되어야하고 FPR은 최소가 되어야 한다. 

ROC 곡선을 통해 최적의 임계값을 구할 수도 있다. TPR-FPR이 최대가 되는 지점을 찾으면 되기 때문이다.

 

 

 

from sklearn.metrics import roc_curve
fpr, tpr, thresholds = roc_curve(y_val, y_pred_proba)

optimal_idx = np.argmax(tpr - fpr)
optimal_threshold = thresholds[optimal_idx]

print('idx:', optimal_idx, ', threshold:', optimal_threshold)


AUC score는 ROC Curve 아래의 면적을 이용해 구한다. 이 넓이가 넓을 수록 좋은 모델이 된다.

from sklearn.metrics import roc_auc_score

y_pred_proba = logistic.predict_proba(X_val_ohe)[:,1]
auc = roc_auc_score(y_val, y_pred_proba)
print(f"Logistic Regression의 auc score : {auc.round(3)}")

 


* train-test 데이터 분리 시에 이용할 수 있는 stratify 파라미터
클래스 비율을 유지한 채로 데이터를 분리한다. 원래 데이터의 타겟값 비율이 1:9일 때, 하이퍼파라미터로 stratify=Y를 설정하면 train, test셋의 타겟 클래스 비율도 똑같이 유지된다.