본문 바로가기
Studying/Machine Learning

[머신러닝] Logistic Regression

by giem 2022. 7. 7.
반응형

 

이전의 두 포스트에서는 데이터와 잘 맞는 직선을 찾는 linear regression을 했는데

예측 값이 떨어져 있다면 이 모델로는 예측이 어려울 것이다.

 

가장 대표적인 것이 binary classification인데 예측값이 0 또는 1이다.

이때 이 예측값을 확률로 표현한 다음 특정 값 이상이면 1 아니면 0으로 분류한다.

 

이러한 문제에 적용하는 방법이 Logistic Regression이다.

 

 


이론

 

logistic regression을 진행하기 위해서는 출력 값을 0과 1로 맞춰주어야 한다.

이를 위해 다음과 같은 logistic function을 사용한다.

$$\sigma(z) = \frac{1}{1 + e^{-z}}$$

 

입력 데이터를 x, 실제 class 값을 y, 예측된 출력 값을 y_hat이라 하면 x는 다음의 두 가지 변환을 거쳐 y_hat이 된다.

$$z = wx + b$$

$$\hat{y} = \sigma(z)$$

여기서 목표는 y와 y_hat을 가깝게 하는 w와 b를 찾는 것이다.


Logistic Function

 

logistic function을 그래프로 보면 다음과 같다.

 

 

z=0일 때 출력 값이 0.5이고, 양수일 때 1, 음수일 때 0으로 가까워지게 된다.

이렇게 z값을 0과 1 사이로 표현할 수 있게 되었다.

 


Data Making

 

이제 직접 데이터를 만들어서 진행해 보겠다.

 

x_data = numpy.linspace(-5, 5, 100)
w = 2
b = 1

#y = 2*x_data+1
numpy.random.seed(0) #시드를 고정하여 매번 같은 결과를 내도록

z_data = w * x_data + b + numpy.random.normal(size=len(x_data))#데이터에 noise 추가

y_data = 1 / (1+ numpy.exp(-z_data))

pyplot.scatter(x_data, y_data, alpha=0.4);

 

이제 실제 class 값을 정해주기 위해 where함수로 0.5보다 큰 값을 1, 작은 값을 0으로 변환하겠다.

y_data = numpy.where(y_data >= 0.5, 1, 0)
pyplot.scatter(x_data, y_data, alpha=0.4);


Cost Function

 

이제 y_hat과 실제 y가 가깝게 되도록 하는 w와 b를 찾으려면 cost function을 정의해야 한다.

 

전의 linear regression에는 MSE를 사용했지만 해당 함수는 convex(볼록함)한 형태기 때문에

$$\frac{1}{n} \sum_{i=1}^n (y_i - (wx_i + b))^2$$

 

아래와 같이 sigmoid function을 사용해서 convex하지 않게 만들어 준다.

$$\frac{1}{n} \sum_{i=1}^n (y_i - \sigma(wx_i + b))^2$$

 

하지만 이 함수의 최솟값을 gradient descent를 이용해 구하면 기울기가 0인 지점에서 멈추고

local minimum에 도달하게 된다.

 

그럼 cost function을 다시 생각해보아야 한다.

 

y=1인 경우 예측값이 1에 가깝길 바라지만 0에 가깝게 나왔다면 cost function의 값이 매우 커야 한다.

 

이를 만족시킬 수 있는 함수는 log를 이용해 만들 수 있다.

 

$$L = \begin{cases} -log(\sigma(wx+b)),\;if\;y=1\\ -log(1-\sigma(wx+b)),\;if\;y=0 \end{cases}$$

 

y값이 0 또는 1이기 때문에 다음과 같이 정리할 수 있다.

$$L = -y \log(\sigma(wx+b)) - (1-y)\log(1-\sigma(wx+b))$$

 

이 식이 logistic function에서 cost function이 된다.

 


Code

 

이제 이 전체 프로세스를 코드로 구현해보겠다.

 

우선 cost function을 정의하겠다.

 

w, b, x, y = sympy.symbols('w b x y')
logistic = 1/(1+ sympy.exp(-w*x-b)) # x를 0에서 1사이로 표현

Loss = -y*sympy.log(logistic) - (1-y)*sympy.log(1-logistic) # cost function

 

x변환, logistic 모델, cost function을 정의해보겠다.

from autograd import numpy
from autograd import grad 


def logistic(z):
    return 1 / (1 + numpy.exp(-z))
    
def logistic_model(params, x):
    w = params[0]
    b = params[1]
    z = w * x + b
    y = logistic(z)
    return y

def log_loss(params, model, x, y):
    y_pred = model(params, x)
    return -numpy.mean(y * numpy.log(y_pred) + (1-y) * numpy.log(1 - y_pred))

 

기울기 계산을 위해서는 autograd를 통해서 gradient값을 구해보겠다.

numpy.random.seed(0)
params = numpy.random.rand(2) #parameter 초기화
gradient = grad(log_loss) # logistic loss 기울기를 계산하는 함수 정의
gradient(params, logistic_model, x_data, y_data) # 기울기 계산
# array([-0.42734877,  0.08274066])

 

w와 b에 대해 기울기를 구한다.

 

새로운 조건을 추가해서 5000번의 반복 수 외에 기울기 값이 0.001보다 작아지면 멈추도록 설정하겠다.

max_iter = 5000
i = 0
descent = numpy.ones(len(params))

while numpy.linalg.norm(descent) > 0.001 and i < max_iter:
    descent = gradient(params, logistic_model, x_data, y_data)
    params = params - descent * 0.01
    i += 1

print('Optimized value of w is {} vs. true value: 2'.format(params[0]))
print('Optimized value of b is {} vs. true value: 1'.format(params[1]))
#evaluation metrics used in real world dataset
print('Exited after {} iterations'.format(i))

 

예측된 값을 plot 해보면 다음과 같다.

여기서 기준값을 0.5로 정하고 이것보다 크면 1, 작으면 0으로 분류를 하는 함수를 만들겠다.

def decision_boundary(y):
    return 1 if y >= .5 else 0

 

모든 점을 함수에 넣어서 판단해야 하는데 오래 걸리기 때문에 numpy의 vectorize함수를 사용하겠다.

decision_boundary = numpy.vectorize(decision_boundary)

 

그래프로 데이터를 확인해보겠다.

def classify(predictions):
    return decision_boundary(predictions)

final_predictions = classify(logistic_model(params, x_data))

pyplot.scatter(x_data, y_data, alpha=0.4,
               label='true value')
pyplot.scatter(x_data, final_predictions, alpha=0.4, 
               label='prediciton')

pyplot.title('Score: [{}] / [{}]'.format(sum(final_predictions == y_data), len(y_data)))
pyplot.legend()
pyplot.show()

98퍼센트의 정확도로 예측을 했다.

 

다음 포스트에서는 실제의 데이터로 logistic regression을 해보겠다.

 

반응형

댓글