머신러닝의 이해와 라이브러리 활용 기초 (2)

Suhyeon Lee·2024년 11월 19일

3. 분류분석: 로지스틱회귀

ML(Machine Learning)
┌───┴───┐
숫자    범주/카테고리
(회귀)    (분류)
↓      ↓
사전적 의미   카테고리 맞추는 것
:평균으로 다시
돌아간다 == 회귀
머신러닝에서는
숫자 맞추는 것

🡆 예측이라는 건 동일한데 종속변수가 다를 뿐
🡆 로지스틱회귀의 경우 원래 있던 선형회귀의 '식'을 차용해 가지고 와서 로지스틱+(선형)회귀 → 로지스틱회귀라는 이름이 붙은 것이지 숫자 맞추는 알고리즘인 건 아님!

학습목표

  • 범주형 데이터를 맞추는 분류 분석에 대해 알아보기

로지스틱회귀

  • 선형회귀 이론을 바탕으로 로지스틱회귀에 대해 알아보기

타이타닉 생존 분류 문제

머신이는 이제 숫자를 맞추는 회귀분석에 대해서 어느 정도 감을 잡았습니다. 그러던 중 타이타닉 탑승객과 사망에 대한 데이터를 입수했습니다. 0,1을 맞추는 것도 그리 어렵지 않아 보입니다. 일단 데이터를 한번 확인해보아요.

  • Kaggle 타이타닉 예측 대회
    • 주제: 탑승한 승객의 정보를 바탕으로 생존 유무를 예측하는 분류 문제
    • Y(종속변수): 사망(0), 생존(1)
    • X(독립변수): 티켓등급, 성별, 요금 등

Kaggle

  • 머신러닝, AI를 위한 대회나 데이터셋 보관하는 커뮤니티 사이트
import pandas as pd
titanic_df = pd.read_csv('train.csv', encoding='utf-8')
titanic_df.head(3)
  • titaninc_df.head()
    • 변수 설명

      • PassengerId: 승객. 식별자(Primary Key)암.
      • Survival: 사망(0) 또는 생존(1)
      • Pclass: 티켓 등급(1,2,3 등급)
      • Name: 이름
      • Sex: 성별
      • Age: 나이
      • SibSp: 승객의 형제와 배우자 수
      • Parch: 승객의 부모님과 자식 수

      *컬럼명에 오류가 있습니다만, 추후에 위 2가지 변수는 Family로 더하여 사용할 예정입니다.

      • Ticket: 티켓 번호
      • Fare: 요금
      • Cabin: 객실 이름
      • Embarked: 승선한 항구 → C(Cherbourg), Q(Queenstown), S(Southampton)

머신이는 승객의 정보로 생존을 예측하는 문제를 보니 매우 재밌는 사실을 발견했어요. 여성은 생존 확률이 높고 남성은 생존 확률이 낮다는 것이에요. 이 부분만 적용해도 기본적인 예측은 할 수 있을 것 같아요.

# 가설: 비상 상황 특성상 여성을 배려해서 여성이 많이 생존

# Pivot table을 만들어 확인
pd.pivot_table(titanic_df, index='Sex', columns='Survived', aggfunc='size')

# 그래프를 통해서 확인
import seaborn as sns
sns.countplot(titanic_df, x='Sex', hue='Survived')

  • 정확도(Accuracy)

    • 맞춘 개수 / 전체 데이터
  • 생존을 맞춤

    • 여성은 다 살았을 것이고, 남성은 모두 죽었을 것이다.
(233+468)/891*100

→ 78.67564534231201

  • 여성은 모두 생존, 남성은 모두 사망으로 판별한다면?
    • 정확도: 78.6%
      (여성 생존 233 + 남성 사망 468) / 전체 인원 891

모델을 만들지 않고도 무려 80%에 가까운 정확도를 만들다니 엄청난 인사이트입니다. 하지만 이건 Data Scientific하지 않았어요.
→ Data Algorithm으로 적용한 것이 아니라 규칙(Rule-based) 기준으로 맞춘 것이기 때문
이를 위해 좀 더 쓸만한 도구가 필요할 것 같네요!

로지스틱회귀 이론

P(Y=1(생존))P(Y=1(생존)) → 0≤P≤1

범주형 Y에서 선형함수의 한계

  • Y가 0, 1 범주형인 경우 함수 적합

X가 연속형 변수이고, Y가 특정 값이 될 확률이라고 설정한다면, 왼쪽 그림과 같이 선형으로 설명하긴 쉽지 않아 보입니다. 확률은 0과 1 사이인데, 예측 값이 확률 범위를 넘어갈 수 있는 문제가 있죠.
하지만 오른쪽 그림처럼 S자 형태의 함수를 적용하면 잘 설명한다고 할 수 있을 것 같아요!

로짓 개념의 등장

  • S 형태의 함수를 만들기 위해 오즈비(Odds ratio) 개념을 적용
오즈비(odds ratio)=P1P오즈비(odds\ ratio) = \frac{P}{1-P}

갑자기 왠 생소한 개념이라 생각하겠지만, 승산비라 불리는 오즈비는 실패확률 대비 성공확률로, 도박사들이 자주 쓰는 개념입니다.
예를 들어 도박이 성공할 확률이 80%라면, 오즈비는 80%/20% = 4예요. 다시 해석해보면 1번 실패하면 4번은 딴다는 소리입니다.

  • 하지만 오즈비를 곧바로 적용할 수는 없음 → 약간의 변형이 필요: 로그
    • P는 확률 값으로 0,1사이 값인데, P가 증가할수록 오즈비가 급격하게 증가하기 때문에 너무 확률이 급격하게 증가하고 선형성을 따르지 않음
    • 따라서 로그를 씌워 해당 부분을 완화함
Logit=log(P1P)Logit = \log(\frac{P}{1-P})
  • 오즈비와 확률의 관계 / 로짓과 확률의 관계
    • 로짓의 그래프가 더 선형적인 그림을 나타내므로 선형회귀의 기본식을 활용할 수 있음
      • 로지스틱"회귀"라고 불리는 이유가 바로 이것: 선형회귀의 기본식 활용

  • 위 그래프의 확률-로짓 그래프 X-Y축을 교체 → 로지스틱 함수

로지스틱 함수는 시그모이드 함수 중 하나!
딥러닝에서 다시 활용되니 '값을 계산하면 확률이 도출된다'는 걸 기억해 주세요.
로짓의 장점은 어떤 값을 가져오더라도 반드시 특정 사건이 일어날 확률(Y값이 특정 값일 확률)이 0과 1 안으로 들어오게 하는 특징을 가지고 있다는 것입니다.

  • 로지스틱 함수
    • Logit=log(P1P)Logit = \log(\frac{P}{1-P}) 식을 P에 대해서 정리하여 다음과 같이 표현할 수 있음
      P=11+eLogitP = \frac{1}{1+e^{-Logit}}
    • 로짓과 기존 선형회귀의 우변을 합쳐 다음과 식을 도출
      log(P1P)=w0+w1Xlog(\frac{P}{1-P}) = w_0+w_1X
      • 양변에 자연지수 e를 취하면
        P1P=ew0+w1X\frac{P}{1-P} = e^{w_{0} + w_{1}X}
      • 해석: X값이 w1w_1만큼 증가하면 오즈비는 ew1e^{w_1}만큼 증가

로지스틱함수는 가중치 값을 안다면 X값이 주어졌을 때 해당 사건이 일어날 수 있는 P의 확률을 계산할 수 있게 됩니다.
이때, 확률 0.5를 기준으로 그보다 높으면 사건이 일어남(P(Y) = 1), 그렇지 않으면 사건이 일어나지 않음(P(Y) = 0)으로 판단하여 분류 예측에 사용합니다.
→ 0.5를 '임계값'이라고 함!

x = 연속형, 성별(0, 1)
y = 이진분류(0, 1) / 다중분류(Softmax)

분류 평가 지표

  • 분류 평가 지표 알아보기

정확도와 F1-Score

회귀분석이 숫자를 예측하고 실제 값과 평가했던 것처럼, 분류라는 문제를 평가하는 것도 쉽게 보입니다.
예를 들어 맞춘 정답을 전체 데이터의 개수로 나누면 될 것처럼 보여요. 하지만 과연 그럴까요?

정확도의 한계

러닝이는 끝내주는 데이터 분석가라고 소문나있어요. 이 친구는 병원에 암을 예측하는 진단 소프트웨어를 개발 해달라는 요청을 받고 납품하는 상황이에요. 그런데 너무 귀찮은 나머지 모든 환자를 정상이라고 판정하는 “암 예측 모델”을 만들었어요.

  • 암 예측 모델: 무조건 환자가 음성(정상인)이라고 판정
    • 100명의 환자 입실, 95명은 음성(정상), 5명은 양성(암 환자)
    • 위에 따르면 암 예측 모델의 정확도는 95%

정확도는 매우 높은 것 같지만 실제로 양성(암 환자)는 하나도 못 맞췄어요. 이런 사기를 잘 걸러내기 위한 지표를 만들어봅시다.

혼동 행렬(confusion Matrix)


실제 값과 예측 값에 대한 모든 경우의 수를 표현하기 위한 2x2 행렬

  • 표기법

    • 실제와 예측이 같으면 True / 다르면 False
    • 예측을 양성으로 했으면 Positive / 음성으로 했으면 Negative
  • 해석

    • TP: 실제로 양성(암 환자)이면서 양성(암 환자) 올바르게 분류된 수
    • FP: 실제로 음성(정상인)이지만 양성(암 환자)로 잘못 분류된 수
    • FN: 실제로 양성(암 환자)이지만 음성(정상인)로 잘못 분류된 수
    • TN: 실제로 음성(정상인)이면서 음성(정상인)로 올바르게 분류된 수
  • 지표

    1. 정밀도(Precision): 모델이 양성 1로 예측한 결과 중 실제 양성의 비율(모델의 관점)

      정밀도(precision)=TPTP+FP정밀도(precision) = \frac{TP}{TP+FP}

    2. 재현율(Recall): 실제 값이 양성인 데이터 중 모델이 양성으로 예측한 비율(데이터의 관점)

      재현율(Recall)=TPTP+FN재현율(Recall) = \frac{TP}{TP+FN}

    3. f1-Score: 정밀도와 재현율의 조화 평균

      f1score=2정밀도재현율정밀도+재현율f1-score = 2*\frac{정밀도*재현율}{정밀도+재현율}
    4. 정확도(Accuracy)

      정확도(Accuracy)=TP+TNTP+TN+FP+FN정확도(Accuracy) = \frac{TP+TN}{TP+TN+FP+FN}
  • 실제 적용

    • TP: 실제로 양성(암 환자)이면서 양성(암 환자) 올바르게 분류된 수 → 0명
    • FP: 실제로 음성(정상인)이지만 양성(암 환자)로 잘못 분류된 수 → 0명
    • FN: 실제로 양성(암 환자)이지만 음성(정상인)이라고 분류된 수 → 5명
    • TN: 실제로 음성(정상인)이면서 음성(정상인)이라고 분류된 수 → 95명
      • 정밀도는 정의되지 않음(divsion by zero), 재현율은 0
      • 결과적으로 f1-score는 0

위처럼 정확도가 제 기능을 못하는 때는 분류에서 특히 Y값이 unbalance하지 못할 때 일어나요. 따라서 이를 위해서 Y 범주의 비율을 맞춰주거나 평가 지표를 f1 score을 사용함으로써 이를 보완한답니다.

실습

자주 쓰는 함수

  • sklearn.linear_model.LogisticRegression : 로지스틱회귀 모델 클래스
    • 속성
      • classes_: 클래스(Y)의 종류
      • n_features_in_ : 들어간 독립변수(X) 개수
      • feature_names_in_: 들어간 독립변수(X)의 이름
      • coef_: 가중치
      • intercept_: 바이어스
    • 메소드
      • fit: 데이터 학습
      • predict: 데이터 예측
      • predict_proba: 데이터가 Y = 1일 확률을 예측
  • sklearn.metrics.accuracy: 정확도
  • sklearn.metrics.f1_socre: f1_score

타이타닉 실습

  • 테이블 데이터 확인
    • 숫자
      • Age, SibSp, Parch, Fare
    • 범주형
      • Pclass, Sex, Cabin, Embarked
    • .info()
      • 데이터에 대한 결측치, 데이터 전체 개수 등을 확인

→ x 변수 1개, Y 변수(Survived) 골라서 분석

sns.scatterplot(titanic_df, x='Fare', y='Survived')

sns.histplot(titanic_df, x='Fare')

# 데이터 기술 통계를 보는 법(수치형): describe()
titanic_df.describe()

  1. 로지스틱회귀 모델 불러오고 훈련하기
  2. 변수
    1. 1차 모델: Fare
    2. 2차 모델: Pclass, Sex, Fare
  3. 평가하기
    1. accuracy
    2. f1_score
from sklearn.linear_model import LogisticRegression

# X 변수: Fare, Y 변수: Survived
X_1 = titanic_df[['Fare']]
y_true = titanic_df[['Survived']]

model_lor = LogisticRegression()
model_lor.fit(X_1, y_true)
def get_att(x):
    # x 모델을 넣기
    print("클래스 종류", x.classes_)
    print("독립변수 개수", x.n_features_in_)
    print("들어간 독립변수(x)의 이름", x.feature_names_in_)
    print("가중치", x.coef_)
    print("바이어스", x.intercept_)

get_att(model_lor)

→ 실행 결과:
클래스 종류 [0 1]
독립변수 개수 1
들어간 독립변수(x)의 이름 ['Fare']
가중치 [[0.01519617]]
바이어스 [-0.94129222]

from sklearn.metrics import accuracy_score, f1_score
def get_metrics(true, pred):
    print("정확도", accuracy_score(true, pred))
    print("f1-score", f1_score(true, pred))

y_pred_1 = model_lor.predict(X_1)

get_metrics(y_true, y_pred_1)

→ 실행 결과:
정확도 0.6655443322109988
f1-score 0.354978354978355

# 다중로지스틱회귀

# Y: Survived(사망)
# X(수치형): Fare
# X(범주형): Pclass(좌석 등급), Sex

def get_sex(x):
    if x == 'female':
        return 0
    else:
        return 1

titanic_df['Sex_en'] = titanic_df['Sex'].apply(get_sex)

X_2 = titanic_df[['Pclass', 'Sex_en', 'Fare']]
y_true = titanic_df[['Survived']]

model_lor_2 = LogisticRegression()
model_lor_2.fit(X_2, y_true)

get_att(model_lor_2)

→ 실행 결과:
클래스 종류 [0 1]
독립변수 개수 3
들어간 독립변수(x)의 이름 ['Pclass' 'Sex_en' 'Fare']
가중치 [[-8.88331324e-01 -2.53993425e+00 1.64019087e-03]]
바이어스 [3.02004403]

y_pred_2 = model_lor_2.predict(X_2)

# X 변수가 Fare
get_metrics(y_true, y_pred_1)

# X 변수가 Fare, Pclass, Sex
get_metrics(y_true, y_pred_2)

→ 실행 결과:
# X 변수가 Fare
정확도 0.6655443322109988
f1-score 0.354978354978355
# X 변수가 Fare, Pclass, Sex
정확도 0.7867564534231201
f1-score 0.7121212121212122

🡆 rule-based와 비교했을 때 정확도는 비슷하지만 f1-score에서 큰 차이가 있음!

추가: 각 데이터별 Y=1인 확률 뽑아내기(생존할 확률)

model_lor_2.predict_proba(X_2)

로지스틱회귀 정리

  • 장점: 역시 직관적이며 이해하기 쉽다.
  • 단점: 복잡한 비선형 관계를 모델링 하기 어려울 수 있음
  • Python 패키지
    • sklearn.linear_model.LogisticRegresson

사실상 로지스틱회귀는 선형회귀의 아이디어에서 종속 변수(Y)만 가공한 것이기 때문에 장,단점을 똑같이 가져가요.

숙제

  • titanic 데이터를 이용하여 다양한 변수를 넣고 빼면서, 가장 높은 f1 score를 만들어봅시다.

모델링 기본 마무리

회귀/분류 정리해보기

숨 가쁘게 머신러닝의 방법론 중 회귀와 분류에 대해서 알아보았어요. 한번 정리하는 시간을 가져볼까요?

  • 선형회귀와 로지스틱회귀의 공통점

    1. 모델 생성이 쉬움
    2. 가중치(혹은 회귀계수)를 통한 해석이 쉬운 장점이 있음
    3. X변수에 범주형, 수치형 변수 둘 다 사용 가능
  • 선형회귀와 로지스틱 분류 차이점

선형회귀(회귀)로지스틱회귀(분류)
Y(종속변수)수치형범주형
평가척도Mean Square ErrorAccuracy
R Square(선형 회귀만)F1 - score
sklearn 모델 클래스sklearn.linear_model.linearRegressionsklearn.linear_model.LogistricRegression
sklearn 평가 클래스sklearn.metrics.mean_squared_errorsklearn.metrics.accuracy_score
skelarn.metrics.r2_scoreskelearn.metrics.f1_score

숫자를 예측하는 회귀분석, 범주를 맞추는 분류분석에 대해서 배워보았어요. 그럼 이제 세상에 있는 모든 문제를 다 해결해 볼 수 있을까요?
대답은 No. 실제로 데이터의 모델링은 데이터 사이언스 업무의 아주 일부분이며, 대부분 데이터의 수집과 전처리에 아주 많은 시간을 쏟게 된답니다.

  • Data science의 기대와 현실

  • 전체 데이터 분석 프로세스

이제 머신러닝의 대표적인 예측과 분류를 배웠으니 데이터 분석 프로세스와 더 많은 알고리즘에 대해서 배워 볼게요.

profile
2 B R 0 2 B

0개의 댓글