로지스틱 회귀(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()

사이킷런을 통한 로지스틱 회귀 모델 구현하기
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
'📙 Fundamentals > ML&DL' 카테고리의 다른 글
| 🏨 호텔 예약 정보 데이터셋 분석 | 3️⃣ 파일 업로드 (0) | 2025.04.21 |
|---|---|
| 딥러닝의 성능 향상을 위한 하이퍼파라미터 종류 (1) | 2025.04.14 |
| 회귀 모델 | 단순 선형 회귀_Simple Linear Regression (0) | 2025.04.12 |
| 퍼셉트론(Perceptron) (0) | 2025.04.10 |
| 차원 축소 기법 : 주성분 분석(PCA) VS 요인 분석 (0) | 2025.04.07 |