📙 Fundamentals/ML&DL

회귀 모델 | 로지스틱 회귀_Logistic Regression

Lento_ 2025. 4. 12. 20:11

 

로지스틱 회귀(Logistic Regression)

: 이름은 ‘회귀’지만 실제로는 이진 분류(Binary Classification)를 위한 모델

 

로지스틱 회귀는 입력값의 선형 조합을 통해 두 클래스 중 하나를 예측하는 분류 모델이다.

선형 회귀와 비슷하게 가중치와 편향을 학습하지만, 출력값을 확률로 변환하기 위해 시그모이드 함수(sigmoid function)를 사용한다.

결과적으로 예측값은 0과 1 사이의 확률로 나타나며, 일반적으로 0.5를 기준으로 클래스 0 또는 1로 분류한다.

 

그렇다면 로지스틱 회귀는 왜 선형 모델일까?

: 로지스틱 회귀는 시그모이드를 쓰지만, 결정 경계((w^T)*x+b=0)는 여전히 선형이기에 선형 모델로 분류되고, 해석이 직관적이고 설명하기 쉬운 장점을 가지고 있다.

 

언제 사용할까?

 

- 이진 분류 문제일 때 (ex. 이메일이 스팸인가 아닌가, 고객이 이탈할 것인가 아닌가)

- 모델의 해석력이 중요할 때 (피처가 어떤 영향을 주는지 설명 필요)

- 빠르고 안정적인 결과가 필요할 때 (모델이 단순해서 학습이 빠름)

 

Numpy를 통한 로지스틱 회귀 모델 구현하기

 

class LogisticRegression:
    def __init__(self, learning_rate=0.01, epochs=100):

        self.history = []
        self.epochs = epochs
        self.learning_rate = learning_rate

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

    def fit(self, X, y):
        n_samples = X.shape[0]
        self.w = np.random.randn()    # 가중치: 랜덤으로 초기화
        self.b = 0

        for i in range(self.epochs):
            hypothesis_model = self.w * X + self.b
            y_pred = self.sigmoid(hypothesis_model)

            loss = -np.mean(y * np.log(y_pred + 1e-8) + (1-y) * np.log(1-y_pred+1e-8))    # 손실함수 : Binary Cross-Entropy # 1e-8은 로그의 0 나눗셈 방지를 위한 작은 값
            self.history.append(loss)

            # 파라미터 업데이트
            dw = np.mean((y_pred - y) * X.squeeze())
            db = np.mean(y_pred-y)
            self.w = self.w - self.learning_rate * dw
            self.b = self.b - self.learning_rate * db

    def predict_proba(self, X):
        hypothesis_model = self.w * X + self.b
        y_pred = self.sigmoid(hypothesis_model)
        return y_pred

    def predict(self, X):
        hypothesis_model = self.w * X + self.b
        y_pred = self.sigmoid(hypothesis_model)
        y_pred = (y_pred >= 0.5).astype(int)

        return y_pred
X = np.random.rand(100, 1) * 10    # X: 0~10 사이의 랜덤 숫자 100개 생성 (형태: (100, 1))
y = (X.squeeze() > 5).astype(int)  # y: X 값이 5보다 크면 1, 아니면 0 (이진 분류 타겟 생성)
X.shape, y.shape

# 모델 생성 및 학습 
LR_model = LogisticRegression()
LR_model.fit(X, y)

# 예측
y_pred = LR_model.predict(X)

# 평가(정확도)
accuracy = np.mean(y_pred == y)
print(accuracy)
# 정확도 출력
0.5688
# 시각화
# 학습이 잘 되고 있는지 확인 가능
plt.figure(figsize = (12, 4))
plt.subplot(1,2,1)
plt.plot(LR_model.history)
plt.xlabel("epochs")
plt.ylabel("binary cross-entrophy loss")
plt.title("Loss")

# 시그모이드 곡선으로 분류 경계 시각화
# X값의 범위를 0~10으로 만들어서 예측 확률 곡선을 그림
plt.subplot(1,2,2)
plt.scatter(X, y, label="Data")
x_vals = np.linspace(0, 10, 100).reshape(-1, 1)    # 0~10 범위의 새로운 X값 100개 생성
y_vals = LR_model.predict_proba(x_vals)    # predict_proba(): 해당 X값에 대한 예측 확률을 구함.

plt.plot(x_vals, y_vals, color="red", label = "Sigmoid curve")    # 로지스틱 회귀 모델이 학습한 '결정 경계'를 나타내는 선

# 데이터를 만들 때 기준으로 쓴 진짜 경계선 --> 모델이 이 선에 가까운 위치에서 급격히 확률이 바뀌면 학습이 잘 된 것.
plt.axvline(x=5, color="black", linestyle="--", label="True decision boundary")

plt.xlabel("X")
plt.ylabel("P(y=1)")
plt.legend()
plt.title("Bin classification")

plt.show()

Numpy를 통한 로지스틱 회귀 모델로 예측

사이킷런을 통한 로지스틱 회귀 모델 구현하기

from sklearn.linear_model import LogisticRegression

X = np.random.rand(100, 1) * 10    # X: 0~10 사이의 랜덤 숫자 100개 생성 (형태: (100, 1))
y = (X.squeeze() > 5).astype(int)  # y: X 값이 5보다 크면 1, 아니면 0 (이진 분류 타겟 생성)
X.shape, y.shape

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

# 예측
y_pred = model.predict(X)

# 시그모이드 곡선으로 분류 경계 시각화
# X값의 범위를 0~10으로 만들어서 예측 확률 곡선을 그림
plt.figure(figsize = (12, 4))
plt.scatter(X, y, label="Data")
x_vals = np.linspace(0, 10, 100).reshape(-1, 1)    # 0~10 범위의 새로운 X값 100개 생성

# predict_proba(): 해당 X값에 대한 예측 확률을 구함.
# y=1인 클래스 확률만 선택하여 시각화
y_vals = model.predict_proba(x_vals)[:,1]   

plt.plot(x_vals, y_vals, color="red", label = "Sigmoid curve")    # 로지스틱 회귀 모델이 학습한 '결정 경계'를 나타내는 선

# 데이터를 만들 때 기준으로 쓴 진짜 경계선 --> 모델이 이 선에 가까운 위치에서 급격히 확률이 바뀌면 학습이 잘 된 것.
plt.axvline(x=5, color="black", linestyle="--", label="True decision boundary")

plt.xlabel("X")
plt.ylabel("P(y=1)")
plt.legend()
plt.title("Bin classification")

plt.show()

사이킷런를 통한 로지스틱 회귀 모델로 예측

# 정확도
0.99