[머신러닝 완벽 가이드] 5장_회귀 - 개요

이경민·2023년 1월 12일
0

📌 회귀 (Regression)

✅ 소개

  • 데이터 값이 평균과 같은 일정한 값으로 돌아가려는 경향을 이용한 통계학 기법

  • 여러 개의 독립변수와 한 개의 종속변수 간의 상관관계를 모델링하는 기법을 통칭

  • 머신러닝 관점에서 보면 독립변수는 피처에 해당되며 종속변수는 결정값이다.

  • 머신러닝 회귀 예측의 핵심은 주어진 피처와 결정값 데이터 기반에서 학습을 통해 최적의 회귀계수를 찾아내는 것이다.

  • 회귀는 회귀 계수의 선형/비선형 여부, 독립변수의 개수, 종속변수의 개수에 따라 여러 가지 유형으로 나눌 수 있다.

    • 독립변수 개수

      • 1개: 단일 회귀
      • 여러 개: 다중 회귀
    • 회귀 계수의 결합

      • 선형: 선형 회귀
      • 비선형: 비선형 회귀
  • 지도학습은 분류와 회귀로 나뉘며, 이 두 가지 기법의 가장 큰 차이는 분류는 예측값이 카테고리와 같은 이산형 클래스 값이고 회귀는 연속형 숫자 값이라는 것이다.

✅ 선형 회귀 모델

  • 여러 가지 회귀 중에서 선형 회귀가 가장 많이 사용된다.

    • 선형 회귀는 실제 값과 예측값의 차이(오류의 제곱 값)를 최소화하는 직선형 회귀선을 최적화하는 방식이다.
  • 선형 회귀 모델은 규제 방법에 따라 다시 별도의 유형으로 나뉠 수 있다.

    • 규제는 일반적인 선형 회귀의 과적합 문제를 해결하기 위해서 회귀 계수에 페널티 값을 적용하는 것을 말한다.

(1) 일반 선형 회귀

  • 예측값과 실제 값의 RSS(Residual Sum of Squares)를 최소화할 수 있도록 회귀 계수를 최적화하며, 규제를 적용하지 않은 모델

(2) 릿지(Ridge)

  • 선형 회귀에 L2 규제를 추가한 회귀 모델

  • L2 규제는 상대적으로 큰 회귀 계수 값의 예측 영향도를 감소시키기 위해서 회귀 계수값을 더 작게 만드는 규제 모델

(3) 라쏘(Lasso)

  • 선형 회귀에 L1 규제를 적용한 방식

  • L2 규제가 회귀 계수 값의 크기를 줄이는 데 반해, L1 규제는 예측 영향력이 작은 피처의 회귀 계수를 0으로 만들어 회귀 예측 시 피처가 선택되지 않게 하는 것으로 L1 규제는 피처 선택 기능으로도 불린다.

(4) 엘라스틱넷(ElasticNet)

  • L2, L1 규제를 함께 결합한 모델

  • 주로 피처가 많은 데이터 세트에서 적용되며, L1 규제로 피처의 개수를 줄임과 동시에 L2 규제로 계수 값의 크기를 조정

(5) 로지스틱 회귀(Logistic Regression)

  • 분류에 사용되는 선형 모델

  • 일반적으로 이진 분류뿐만 아니라 희소 영역의 분류, 예를 들어 텍스트 분류와 같은 영역에서 뛰어난 예측 성능을 보인다.

✅ 단순 선형 회귀

  • 독립변수도 하나, 종속변수도 하나인 선형 회귀

Y^=w0+w1X\hat{Y}=w_0+w_1*X

  • Y^\hat{Y}: 예측값
  • w0w_0: 절편
  • w1w_1: 기울기
  • 잔차: 실제 값과 회귀 모델의 예측값의 차이에 따른 오류 값

  • 최적의 회귀 모델을 만든다는 것은 바로 전체 데이터의 잔차(오류 값) 합이 최소가 되는 모델을 만든다는 의미이다. 즉, 오류 값 합이 최소가 될 수 있는 최적의 회귀 계수를 찾는다는 의미도 된다.

  • 오류 값은 +나 -가 될 수 있다. 그래서 전체 데이터의 오류 합을 구하기 위해 단순히 더했다가는 뜻하지 않게 오류 합이 크게 줄어들 수 있다. 따라서 보통 오류 합을 계산할 때는 절댓값을 취해서 더하거나(Mean Absolute Error), 오류 값의 제곱을 구해서 더하는 방식(RSS, Residual Sum of Squares)을 취한다.

  • 일반적으로 미분 등의 계산을 편리하게 하기 위해서 RSS 방식으로 오류 합을 구한다.

  • 비용(Cost): RSS
  • 비용 함수(손실 함수, loss function): w 변수(회귀 계수)로 구성되는 RSS

RSS(w0,w1)=1Ni=1N(yi(w0+w1xi))2RSS(w_0, w_1) = \frac{1}{N}\sum_{i=1}^{N}(y_i-(w_0+w_1*x_i))^2

( ii는 1부터 학습 데이터의 총 건수 N까지 )

  • 머신러닝 회귀 알고리즘은 데이터를 계속 학습하면서 이 비용 함수가 반환하는 값을 지속해서 감소시키고 최종적으로는 더 이상 감소하지 않는 최소의 오류 값을 구하는 것이다.

✅ 경사하강법 (Gradient Descent)

  • 점진적으로 반복적인 계산을 통해 W 파라미터 값을 업데이트하면서 오류 값이 최소가 되는 W 파라미터를 구하는 방식

  • 반복적으로 비용 함수의 반환 값, 즉 예측값과 실제 값의 차이가 작아지는 방향성을 가지고 W 파라미터를 지속해서 보정해 나간다. 그리고 오류 값이 더 이상 작아지지 않으면 그 오류 값을 최소 비용으로 판단하고 그때의 W 값을 최적 파라미터로 반환한다.

  • 비용 함수가 포물선 형태의 2차 함수라면 경사 하강법은 최초 w에서부터 미분을 적용한 뒤 이 미분 값이 계속 감소하는 방향으로 순차적으로 w를 업데이트하고, 마침내 더 이상 미분된 1차 함수의 기울기가 감소하지 않는 지점을 비용 함수가 최소인 지점으로 간주하고 그때의 w를 반환한다.

    • 포물선 형태의 2차 함수의 최저점은 해당 2차 함수의 미분 값인 1차 함수의 기울기가 가장 최소일 때이다.

  • 비용 함수

R(w)=1Ni=1N(yi(w0+w1xi))2R(w) = \frac{1}{N}\sum_{i=1}^{N}(y_i-(w_0+w_1*x_i))^2

def get_cost(y, y_pred):
    N = len(y) 
    cost = np.sum(np.square(y - y_pred))/N
    return cost
  • w0,w1w_0, w_1 각 변수에 편미분 적용
  1. R(w)w1=2Ni=1Nxi(yi(w0+w1xi))\frac{\partial R(w)}{\partial w_1}=\frac{2}{N}\sum_{i=1}^{N}-x_i * (y_i-(w_0+w_1x_i))

=2Ni=1Nxi(실제i예측i)=-\frac{2}{N}\sum_{i=1}^{N}x_i * (실제값_i-예측값_i)

  1. R(w)w0=2Ni=1N(yi(w0+w1xi))\frac{\partial R(w)}{\partial w_0}=\frac{2}{N}\sum_{i=1}^{N}- (y_i-(w_0+w_1x_i))

=2Ni=1N(실제i예측i)=-\frac{2}{N}\sum_{i=1}^{N}(실제값_i-예측값_i)

  • 새로운 w 업데이트는 이전 w에서 편미분 결괏값을 마이너스(-)하면서 적용한다.

    • 단, 편미분 값이 너무 클 수 있기 때문에 편미분 값에 보정 계수 η\eta를 곱하는데 이를 '학습률'이라고 한다.
# w1과 w0를 업데이트 할 w1_update, w0_update를 반환
def get_weight_updates(w1, w0, X, y, learning_rate=0.01):
    N = len(y)
    # 먼저 w1_update, w0_update를 각각 w1, w0의 shape와 동일한 크기를 가진 0 값으로 초기화
    w1_update = np.zeros_like(w1)
    w0_update = np.zeros_like(w0)
    # 예측 배열 계산하고 예측과 실제 값의 차이 계산
    y_pred = np.dot(X, w1.T) + w0
    diff = y-y_pred
        
    # w0_update를 dot 행렬 연산으로 구하기 위해 모두 1값을 가진 행렬 생성 
    w0_factors = np.ones((N,1))

    # w1과 w0을 업데이트할 w1_update와 w0_update 계산
    w1_update = -(2/N)*learning_rate*(np.dot(X.T, diff))
    w0_update = -(2/N)*learning_rate*(np.dot(w0_factors.T, diff))    
   
    return w1_update, w0_update


# 입력 인자 iters로 주어진 횟수만큼 반복적으로 w1과 w0를 업데이트 적용
def gradient_descent_steps(X, y, iters=10000):
    # w0와 w1을 모두 0으로 초기화. 
    w0 = np.zeros((1,1))
    w1 = np.zeros((1,1))
   
    # 인자로 주어진 iters 만큼 반복적으로 get_weight_updates() 호출하여 w1, w0 업데이트 수행 
    for ind in range(iters):
        w1_update, w0_update = get_weight_updates(w1, w0, X, y, learning_rate=0.01)
        w1 = w1 - w1_update
        w0 = w0 - w0_update
             
    return w1, w0


# 최종 w1, w0 값
w1, w0 = gradient_descent_steps(X, y, iters=1000)
print("w1:{0:.3f} w0:{1:.3f}".format(w1[0,0], w0[0,0]))

# RSS 계산 
y_pred = w1[0,0] * X + w0
print('Gradient Descent Total Cost:{0:.4f}'.format(get_cost(y, y_pred))) # 0.9935

📝 경사 하강법의 일반적인 프로세스 정리

STEP1

w1,w0w_1, w_0를 임의의 값으로 설정하고 첫 비용 함수의 값을 계산한다.

STEP2

w1w_1w1+η2Ni=1Nxi(실제i예측i)w_1+\eta \frac{2}{N}\sum_{i=1}^{N}x_i * (실제값_i-예측값_i),

w0w_0w0+η2Ni=1N(실제i예측i)w_0+\eta \frac{2}{N}\sum_{i=1}^{N}(실제값_i-예측값_i)

업데이트한 후 다시 비용 함수의 값을 계산한다.

STEP3

비용 함수의 값이 감소했으면 다시 STEP2를 반복한다.

더 이상 비용 함수의 값이 감소하지 않으면 그때의 w1,w0w_1, w_0를 구하고 반복을 중지한다.


  • 일반적으로 경사 하강법은 모든 학습 데이터에 대해 반복적으로 비용 함수 최소화를 위한 값을 업데이트하기 때문에 수행 시간이 매우 오래 걸린다는 단점이 있다.

  • 따라서 실전에서는 대부분 확률적 경사 하강법을 이용한다.

  • 확률적 경사 하강법 (Stochastic Gradient Descent)

    • 전체 데이터가 아닌 일부 데이터만 이용해 w가 업데이트되는 값을 계산하므로 경사 하강법에 비해서 빠른 속도를 보장한다.

    • 대용량 데이터의 경우 대부분 확률적 경사 하강법(batch_size=1)이나 미니 배치 확률적 경사 하강법(batch_size=지정)을 이용해 최적 비용 함수를 도출한다.

def stochastic_gradient_descent_steps(X, y, batch_size=10, iters=1000):
    w0 = np.zeros((1,1))
    w1 = np.zeros((1,1))
   
    for ind in range(iters):
        np.random.seed(ind)
        # 전체 X, y 데이터에서 랜덤하게 batch_size만큼 데이터 추출하여 sample_X, sample_y로 저장
        stochastic_random_index = np.random.permutation(X.shape[0])
        sample_X = X[stochastic_random_index[0:batch_size]]
        sample_y = y[stochastic_random_index[0:batch_size]]
        # 랜덤하게 batch_size만큼 추출된 데이터 기반으로 w1_update, w0_update 계산 후 업데이트
        w1_update, w0_update = get_weight_updates(w1, w0, sample_X, sample_y, learning_rate=0.01)
        w1 = w1 - w1_update
        w0 = w0 - w0_update


# 최종 w1, w0 값
w1, w0 = stochastic_gradient_descent_steps(X, y, iters=1000)
print("w1:",round(w1[0,0],3),"w0:",round(w0[0,0],3))

# RSS 계산 
y_pred = w1[0,0] * X + w0
print('Stochastic Gradient Descent Total Cost:{0:.4f}'.format(get_cost(y, y_pred))) # 0.9937
  • 경사 하강법과 예측 성능상의 차이가 크게 없다.

✅ 평가 지표

  • MAE: Mean Absolute Error, 실제 값과 예측값의 차이를 절댓값으로 변환해 평균한 것

  • MSE: Mean Squared Error, 실제 값과 예측값의 차이를 제곱해 평균한 것

    • MSE 값은 오류의 제곱을 구하므로 실제 오류 평균보다 더 커지는 특성이 있다.
  • RMSE: Root Mean Squared Error, MSE에 루트를 씌운 것

  • : 분산 기반으로 예측 성능을 평가한다. 실제 값의 분산 대비 예측값들의 분산 비율을 지표로 하며, 1에 가까울수록 예측 정확도가 높다.

  • 이 밖에 MSE나 RMSE에 로그를 적용한 MSLE(Mean Squared Log Error), RMSLE(Root Mean Squared Log Error)도 사용한다.

profile
열정 가득한 공간

0개의 댓글