머신러닝 - 로지스틱 회귀

dumbbelldore·2024년 12월 31일
0

zero-base 33기

목록 보기
53/97

1. 로지스틱 회귀(Logistic Regression)

  • 종속변수가 범주형(통상적으로 이진 구성)일 때 분류를 목적으로 사용하는 회귀 분석
  • '선형 회귀(Linear Regression)'과 달리 종속변수의 정규성을 가정하지 않는 '일반화 선형 모델(Generalized Linear Model; GLM)'의 한 종류
  • 독립변수와 종속변수가 비선형 관계에 있음을 가정하므로, 잔차의 정규성/등분산성 가정이 없어 훨씬 유연함

2. 수학적 접근

  • 회귀분석을 이용해 출력값이 확률(0~1 사이)로 주어지는 분류를 수행할 수는 없을까?

    y=β0+β1X1+β2X2++βnXny=\beta_0 + \beta_1X_1 + \beta_2X_2 + \dots + \beta_nX_n

  • 우선, '로짓 변환(Logit Function)'을 활용하면, '확률(PP)'의 개념을 들이면서도 좌변과 우변의 범위를 동일하게 [,+][-\infin,+\infin] 구간으로 맞출 수 있겠구나!

    logit(P)=ln(P1P)=β0+β1X1+β2X2++βnXn\text{logit}(P) = \ln\left(\frac{P}{1-P}\right) = \beta_0 + \beta_1X_1 + \beta_2X_2 + \dots + \beta_nX_n

# 로짓 변환 실습
import numpy as np

def logit(prob):
	return np.log(prob / (1-prob))

prob = np.linspace(0, 1, 10)
z = logit(prob)
print(z) 

## 출력 결과
# [-inf -2.07944154 -1.25276297 -0.69314718 -0.22314355  0.22314355 0.69314718  1.25276297  2.07944154 inf]
  • 그리고, 회귀분석식에 대응되는 확률(PP)을 구해내려면 '시그모이드 함수(Sigmoid Function)'도 함께 활용하면 되겠구나!

    P(y=1X)=11+e(β0+β1X1+β2X2++βnXn)P(y=1|X) = \frac{1}{1 + e^{-(\beta_0 + \beta_1X_1 + \beta_2X_2 + \dots + \beta_nX_n)}}

# 시그모이드 함수 실습

def sigmoid(z):
	return 1 / (1 + np.exp(-z))

prob_recovered = sigmoid(z)
print(prob_recovered)

## 출력 결과
# [0. 0.11111111 0.22222222 0.33333333 0.44444444 0.55555556 0.66666667 0.77777778 0.88888889 1.]

3. 계수 최적화 과정

  • 손실함수인 '음의 로그-우도 함수(Negative Log-Likelihood; NLL)'를 최소화하는 β\beta를 효율적으로 찾기위해 경사하강법을 사용함

    L(β)=i=1N(yilog(y^i)+(1yi)log(1y^i))L(\beta) = -\sum_{i=1}^{N} \left( y_i \log(\hat{y}_i) + (1 - y_i) \log(1 - \hat{y}_i) \right)

    • 초기화: β0,β1,,βn\beta_0, \beta_1, \dots, \beta_n을 임의의 값으로 초기화(통상적으로 0)

    • 편미분 계산: 손실 함수 L(β)L(\beta)의 각 계수에 대한 편미분 계산

      Lβj=i=1N(y^iyi)xij\frac{\partial L}{\partial \beta_j} = \sum_{i=1}^N \left( \hat{y}_i - y_i \right) x_{ij}

    • β\beta 업데이트: 각 계수를 업데이트하며 손실함수가 충분히 작아질 때까지'편미분 계산-업데이트' 과정 반복

      βjβjηLβj\beta_j \leftarrow \beta_j - \eta \frac{\partial L}{\partial \beta_j}, (η\eta=학습률)

import numpy as np

# 시그모이드 함수
def sigmoid(z):
    return 1 / (1 + np.exp(-z))

# 손실 함수
def loss_function(y, y_pred):
    return -np.mean(y * np.log(y_pred) + (1 - y) * np.log(1 - y_pred))

# 경사하강법 구현
def logistic_regression(X, y, lr=0.01, epochs=1000):
    
    # 최초 초기화(0으로 초기화)
    m, n = X.shape
    beta = np.zeros(n)
    
    for _ in range(epochs):
    
        # 예측
        z = np.dot(X, beta)
        y_pred = sigmoid(z)
        
        # 편미분
        gradient = np.dot(X.T, (y_pred - y)) / m
        
        # 계수 업데이트
        beta -= lr * gradient
        
        # 100 단위마다 손실함수 값 출력
        if _ % 100 == 0:
            print(f"Epoch {_}: Loss = {loss_function(y, y_pred):.4f}")
    
    return beta

# 독립변수(첫 열은 절편)
X = np.array([[1, 2], [1, 3], [1, 4], [1, 5]])

# 종속변수
y = np.array([0, 0, 1, 1])

# 로지스틱 회귀 분석 실시
coefficients = logistic_regression(X, y)
print("회귀 계수:", coefficients)

## 출력 결과
# Epoch 0: Loss = 0.6931
# Epoch 100: Loss = 0.6445
# Epoch 200: Loss = 0.6294
# Epoch 300: Loss = 0.6150
# Epoch 400: Loss = 0.6011
# Epoch 500: Loss = 0.5878
# Epoch 600: Loss = 0.5750
# Epoch 700: Loss = 0.5627
# Epoch 800: Loss = 0.5509
# Epoch 900: Loss = 0.5396
# 회귀 계수: [-1.07106719  0.42792742]

4. 라이브러리 활용

4-1. scikit-learn

  • 간단하고 빠르게 모델을 생성할 수 있지만, 모델에 대한 상세내용 확인 기능은 상당히 한정되어 있음
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report

# 가상 데이터 생성
df = pd.DataFrame({
    "X1": [2.5, 0.5, 2.2, 1.9, 3.1, 2.3, 2.7, 1.6],
    "X2": [1, 0, 1, 0, 1, 1, 0, 1],
    "y": [1, 0, 1, 0, 1, 1, 0, 0]
})

X = df[["X1", "X2"]]
y = df["y"]

# 데이터 분할
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# 모델 생성 및 학습
model = LogisticRegression()
model.fit(X_train, y_train)

# 계수 정보 확인 (기능 한정)
print(model.intercept_)
print(model.coef_)

4-2. Statsmodels

  • 통계에 최적화된 라이브러리인 만큼 p-value, AIC 등 상세한 통계량과 고급 분석 기능을 제공함
import statsmodels.api as sm

# 데이터 재생성
X = df[["X1", "X2"]]
X = sm.add_constant(X)  # Statsmodels는 절편 추가작업 필요
y = df["y"]

# 모델 생성 및 학습
model = sm.Logit(y, X)
result = model.fit()

# 상세 결과 확인
print(result.summary())

*이 글은 제로베이스 데이터 취업 스쿨의 강의 자료 일부를 발췌하여 작성되었습니다.

profile
데이터 분석, 데이터 사이언스 학습 저장소

0개의 댓글