공부

BDA X 이지스퍼블리싱 서평단 이벤트 [Do it! 데이터 과학자를 위한 실전 머신러닝]/ 3장: 로지스틱 회귀 모델

무른2 2023. 12. 11. 19:45

 

 

BDA X 이지스퍼블리싱 서평단 이벤트 [Do it! 데이터 과학자를 위한 실전 머신러닝]/ 2장: 최소 제곱

2장 : 최소 제곱 모델 최소 제곱 모델(=OLS) 정의 1) 개념: 목표값과 본 모델에서 도출되는 예측값을 이용해 정의한 비용 함수가 평균 제곱 오차 (MSE)인 모델 → 예측값과 목표값의 차이인 잔차 제곱

sol-butter1472.tistory.com

2장: 최소 제곱 모델 설명 

 


3장 : 로지스틱 회귀 모델

 

경사 하강법

 

- 모델의 비용 함수를 최적화하는 과정 중 하나

 

 

최대 하강법

 

- 매 반복마다 해당 점에서의 gradient(기울기)를 계산 -> 이 역방향의 상수 배만큼 좌표 이동해 지역 최적값 탐색

 

https://blog.naver.com/dnamaker/222321995166

 

 

사전 지식 - Convex Function(볼록 함수)

 

- 함수 f : R^n -> R이 모든 x,y ∈ R^n 과 0과 1 사이의 t에 대해  아래를 만족하면 함수 f를 convex function이라 칭한다.

 

https://blog.naver.com/sw4r/221148661854

 

 

- 함수 f, g가 convex 함수면 (f + g) 또한 convex 함수인 특징을 가지고 있다.

 

 

Logistic Regression Model

 

분류 문제를 해결하는 가장 기본적인 machine learning 모델(이름은 회귀지만 분류 문제에 사용함)

ex. 스팸 메일 필터링, 고양이 사진 분류

- 이진 목푯값 y의 label 값이 1이 나올 확률과 feature vector x 사이의 관계를 모델링

 

 

 

생성 과정(가정)

 

각 샘플 i(1, 2, …, n)에 대해 목푯값 가 아래와 같이 독립으로 생성된다.

1. feature vector 는 외부에서 결정

2. yi 는  xi와 w에 조건부로 정해진다.

yi가 1일 확률은 p(yi |xi, w) 이고 0일 확률은 1 - p(yi | xi,w)인 베르누이 분포를 따르고, w는 상수로 이미 주어진다.

3. p(yi |xi, w)에 따라 yi 가 결정
이 모델에서도 절편을 포함한다고 가정(xi,0 = 1)
과정 2에서는  p(yi |xi, w)와 xi사이의 관계를 아래와 같이 모델링

 

 

우변의 선형 결합 커짐

→ 좌변의 p(yi |xi, w)  또한 커지지만, 이 값이 0에서 1 사이의 값이 유지되도록 모델링

이를 벡터 곱으로 표현(xi : row vecotr, w: parameter vector & column vector))

 

 

 p(yi |xi, w)에 대해 풀면 두 개의 식을 얻을 수 있다. 

-> 새로운 가설 함수 획득

 


손실 함수(샘플 1개에 대한 model 오차 크기를 나타내는 함수)는 아래와 같의 정의

 

따라서 비용 함수(Binary Cross Entropy)는 아래와 같이 정의

 

log(1 + e^xi*w)와 yi*xi*w 모두 convex function이기 때문에

위의 비용 함수는 경사 하강법을 통해 전역 최솟값을 찾을 수 있다.


단변수 logistic regression일 경우 최적화

 

이 말은 즉 feature 수가 1개 → 여기서는 xi 는 scalar 값이라 가정

 

비용 함수는 아래와 같다.

 

이를 w0, w1에 대해 각각 편미분 값을 구한 후 경사 하강법 적용해서 최적 값 획득 가능

 


다중 logistic regression일 경우 최적화

 

먼저 feature 행렬 X를 아래와 같이 정의

 

 

이 때는 뉴턴법을 사용하고 이 방법에서는 학습률을 비용 함수의 2계 도함수로 지정

 

 

W는 2계 도함수을 계산하기 위해 정의한 대각 행렬

진동 폭이 커서 발산할 수 있기 때문에 실질적으로는 학습률 감쇄하는 hyper-parameter(ν ) 사용하는 수정 뉴턴법 사용

 


심화 이론 - 규제

 

Logistic regression 모델에는 L1 규제, L2 규제, Elastic Net을 규제 항으로 포함시킬 수 있다.

규제 강도의 역수 hyper-parameter(C)를 도입

 

 

심화 이론 - 다중 class 분류

 

이는 그 동안의 이진 분류가 아닌 3개 이상의 클래스로 분류하는 문제를 의미

 

OVR 방법: 각각의 i(1, 2, …, K)에 대해 입력 sample이 레이블Ci 에 포함될지 나머지 중 하나일지에 대한 확률만 제시하는 이진 분류 모델을 학습

 

결과를 종합해 최종 판별 OVO 방법: OVR과 비슷,  n(n-1)/2 개의 class 쌍에 대한 이진 분류 모델 학습 후 결과 종합

 

 

 

SVM 다중분류(OvR, OvO)

Suppor vector machine(SVM)은 대표적인 이진분류(binary classification)모델이다. SVM으로 다중분...

blog.naver.com

 

 

- Sigmoid 함수 → Softmax 함수

 

  • 파라미터는 벡터가 아닌 행렬(각 클래스에 대한 파라미터 column vector를 합한 행렬)
  • 출력: 각 클래스일 확률, 하지만 이들의 합은 1이 아님
  • 기존에 사용하고 있던 sigmoid 함수 대신 softmax 함수를 사용해 해결

 

zi는 i번째 클래스에 속할 확률
ex) z = [0.8,0.1,0.5], softmax 함수 거치면 [0.447,0.222,0.331]이 되고 이들의 합은 1이 되어

확률과 같이 해석할 수 있게 된다.

 

 

 

- 비용 함수: Cross Entropy

 

 

 



yj는 j번째 클래스 목표값, y^의 j는 j번째 클래스 포함 여부 예측 값

ex) y = [1,0,0] , y^ = [0.447,0.222,0.331]이었다고 하면 

 

 

 

 


Logistic Regression 구현

 

from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
import numpy as np
# 데이터 준비
x, y = load_breast_cancer(return_X_y=True, as_frame=False)
train_x, test_x, train_y, test_y = train_test_split(x, y, test_size=0.33, random_state=1234)
train_x, test_x = train_x[:, :3], test_x[:, :3] # 간단한 상황 가정을 위해 앞의 3개의 feature들만 사용
train_y, test_y = train_y.reshape(-1, 1), test_y.reshape(-1, 1)
# 스케일링
train_mean, train_std = train_x.mean(axis=0), train_x.std(axis=0)
train_x = (train_x - train_mean) / train_std
test_x = (test_x - train_mean) / train_std
# 절편 추가
n, n_test = train_x.shape[0], test_x.shape[0]
train_x = np.append(np.ones((n, 1)), train_x, axis=1)
test_x = np.append(np.ones((n_test, 1)), test_x, axis=1)
max_iter = 10000
tolerance = 0.0001 # 조기 종료 조건
old_beta = np.ones((4, 1)) # 학습할 파라미터들
for cnt in range(1, max_iter):
matrix_w = np.zeros((n, n))
vector_p = np.zeros((n, 1))
for i in range(n):
e = np.exp((train_x[i].reshape(1, -1) @ old_beta)[0][0])
sigmoid = e / (1 + e)
matrix_w[i][i] = sigmoid * (1 - sigmoid)
vector_p[i] = sigmoid
step_size = np.linalg.inv(train_x.T @ matrix_w @ train_x)
partial = train_x.T @ (train_y - vector_p)
update = 0.0001 * (step_size @ partial)
new_beta = old_beta + update
if np.linalg.norm(update) < tolerance:
print(f"Break Accepted at epoch {cnt}")
break
if cnt % 1000 == 0:
print(f"{cnt}번째 반복, 업데이트 크기: {np.linalg.norm(update)}")
old_beta = new_beta
# 평가
correct = 0
for i in range(train_x.shape[0]):
e = np.exp((train_x[i].reshape(1, -1) @ old_beta)[0][0])
sigmoid = e / (1 + e)
if (sigmoid >= 0.5 and train_y[i] == 1) or (sigmoid < 0.5 and train_y[i] == 0):
correct += 1
print(f"Test Dataset 정확도: {correct / train_x.shape[0] * 100: .2f}")
correct = 0
for i in range(test_x.shape[0]):
e = np.exp((test_x[i].reshape(1, -1) @ old_beta)[0][0])
sigmoid = e / (1 + e)
if (sigmoid >= 0.5 and test_y[i] == 1) or (sigmoid < 0.5 and test_y[i] == 0):
correct += 1
print(f"Test Dataset 정확도: {correct / test_x.shape[0] * 100: .2f}")

 

sklearn으로 표현

 

주요 hyper-parameters

penalty 규제 패널티 선택(L1,L2,Elastic Net, None) L2가 기본
tol 학습 종료에 대한 허용 오차 0.0001이 기본
C 규제 패널티 크기(계산시 역수로 들어감) 1.0이 기본
fit_intercept 절편 포함 여부 True가 기본
max_iter 최대 반복 횟수  100이 기본
solver 최적화 알고리즘 lbfgs가 기본

 

특히 solver로 여러가지를 제공한다.

newton-cg 켤레 기울기법  
lbfgs L-BFGS-B 알고리즘 강건성을 고려해 이 방식이 기본 설정
liblinear 최적화된 좌표 하강법  
sag 확률적 평균 기울기 하강 알고리즘  
saga  SAG 변형 알고리즘  

 

from sklearn.datasets import load_breast_cancer
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
x, y = load_breast_cancer(return_X_y=True, as_frame=False)
train_x, test_x, train_y, test_y = train_test_split(x, y, test_size=0.33, random_state=1234)
train_x, test_x = train_x[:, :3], test_x[:, :3]
clf = LogisticRegression(random_state=1234, C=10e5).fit(train_x, train_y)
train_pred = clf.predict(train_x)
prediction = clf.predict(test_x)
print(f"Train dataset 정확도: {(train_y == train_pred).sum() / len(train_y) * 100: .2f}")
print(f"Test dataset 정확도: {(test_y == prediction).sum() / len(test_y) * 100: .2f}")

 


보충 - pipeline

sklearn.pipeline에서 제공하는 Pipeline 클래스를 사용하면 정형화된 과정들을 함수로 정의해서 사용할 수 있다.

 

from sklearn.pipeline import Pipeline
from sklearn.linear_model import LogisticRegression
from sklearn.preprocessing import StandardScaler
pipe = PipeLine(steps=[("scaler", StandardScaler()), ("clf", LogisticRegression(solver='sag', random_state=1234))])
pipe.fit(train_x, train_y)

 

pipe 객체의 predict() 함수를 사용할 때 train dataset 기준으로 얻은 scaling 값과 parameter가 적용됨에 유의해야 한다.

 

보충 - 통계 모델로서의 logistic regression

 

지금까지의 머신러닝 관점이 아닌 통계학의 관점으로 logistic 모델의 MLE를 통해 해를 구할 수 있고

이는 머신러닝 기법으로 얻은 해와 완전히 동일