본문 바로가기

데이터 사이언스/머신러닝

[NIPA AI 교육/응용] 03. 회귀 분석 알고리즘

1. 회귀 분석이란?

- 데이터를 가장 잘 설명하는 모델을 찾아 입력값에 따른 미래 결과값을 예측하는 알고리즘

$$ Y \approx \beta_0 + \beta_1 X $$

- 위 수식에서 적절한 \( \beta_0, \beta_1 \) 값을 찾는 것이 이 알고리즘의 핵심

- 완벽한 예측은 불가능하기에 최대한 잘 근사해야함

 


2. 단순 선형 회귀

- 데이터를 설명하는 모델을 직선 형태로 가정한 것

- 가장 기초적이나 여전히 많이 사용되는 알고리즘

$$ Y \approx \beta_0 + \beta_1 X $$

- 직선을 구성하는 \( \beta_0 \)(=y절편)과 \( \beta_1 \)(=기울기)을 구하는 것

- 입력값이 1개인 경우에만 적용이 가능함

- 입력값과 결과값의 관계를 알아보는 데 용이함

- 입력값이 결과값에 얼마나 영향을 미치는지 알 수 있음

- 두 변수 간의 관계를 직관적으로 해적하고자 하는 경우 활용

from sklearn.linear_model import LinearRegression

- 기계학습 라이브러리 scikit-learn을 사용하면 Loss 함수를 최솟값으로 만드는 \( \beta_0, \beta_1 \)을 쉽게 구할 수 있음

- LinearRegression 모델의 입력값으로 Pandas의 dataframe의 feature(=x) 데이터와 Series 형태의 label(=y) 데이터를 입력받을 수 있으며, X, Y의 샘플 개수는 같아야 함

import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from sklearn.linear_model import LinearRegression

train_X = pd.DataFrame(X, columns=['X'])
train_Y = pd.Series(Y)

model = LinearRegression()    # 모델 초기화

model.fit(train_X, train_Y)   # train_X, train_Y 데이터 학습하기

predict_model = model.predict(X)   # train_X에 대해 예측하기

# 학습한 결과 시각화하기
plt.scatter(X, Y)
plt.plot([0, 10], [model.intercept_, 10*model.coef_[0] + model.intercept_], c='r')
plt.xlim(0, 10)
plt.ylim(0, 10)
plt.title('Training Result')
plt.savefig('test.png')

Loss 함수

- 실제값과 예측값 차이의 제곱의 합을 Loss 함수로 정의하며, loss 함수의 값이 작을수록 좋은 모델

$$ \frac{1}{N} \sum_{i}^{N}{(y^{(i)} - (\beta_0 + \beta_1 x^{(i)}))^2} $$

- \( i \)번째 데이터 \( (x^{(i)}, y^{(i)}) \)에 대해서

    - 입력값은 \( x^{(i)} \)

    - 실제값은 \( y^{(i)} \)

    - 예측값은 \( \beta_0 x^{(i)} +\beta_1 \)

 

 - Loss 함수의 크기를 작게 하는 \( \beta_0, \beta_1 \) 를 찾는 방법은 다음과 같음

$$ argmin \frac{1}{N} \sum_{i}^{N}{(y^{(i)} - (\beta_0 + \beta_1 x^{(i)}))^2} $$

- 초기값에서 점진적으로 구하는 방식 = 경사 하강법


경사하강법

\( \beta_0, \beta_1 \)값을 Loss 함수 값이 작아지게 계속 업데이트하는 방법

 

1. \( \beta_0, \beta_1 \)값을 랜덤하게 초기화

2. 현재 \( \beta_0, \beta_1 \) 값으로 Loss값 계산

3. 현재 \( \beta_0, \beta_1 \)값을 어떻게 변화해야 Loss 값을 줄일 수 있는지 알 수 있는 Gradient값 계산

4. Gradient 값을 활용하여 \( \beta_0, \beta_1 \) 값 업데이트

5. Loss 값의 차이가 거의 없어질 때 까지 2~4번 과정을 반복하면

    -> Loss 값과 차이가 줄어들면 Gradient 값도 작아짐


3. 다중 선형 회귀

- 여러 개의 입력값(\(X\))으로 결과값(\(Y\))을 예측하고자 하는 경우 사용

- 입력값 \(X\)가 여러 개(2개 이상)인 경우 활용할 수 있는 회귀 알고리즘

- 각 개별 \(X_i\)에 해당하는 최적의 \(\beta_i\)를 찾아야 함

$$ Y \approx \beta_0 + \beta_1X_1 + \beta_2X_2 + \beta_3X_3 + ... + \beta_MX_M $$

- 어떤 입력값이 결과값에 어떠한 영향을 미치는지 알 수 있음

- 여러 개의 입력값 사이 간의 상관 관계가 높을 경우 결과에 대한 신뢰성을 잃을 가능성 있음

from sklearn.linear_model import LinearRegression
from sklearn.metrics import r2_score
from sklearn.model_selection import train_test_split

# X : dataframe, Y : Series

train_X, test_X, train_Y, test_Y = train_test_split(X, Y, test_size=0.2, random_state=42)

model = LinearRegression()
model.fit(train_X, train_Y)

beta_0 = model.intercept_  # y 절편
beta_1 = model.coef_[0]    # 1번째 변수에 대한 계수
beta_2 = model.coef_[1]    # 2번째 변수에 대한 계수
beta_3 = model.coef_[2]    # 3번째 변수에 대한 계수


pred_X = lrmodel.predict(test_X)    # test_X에 대해서 예측하기

Loss 함수

- 단순 선형 회귀와 마찬가지로 입력값과 실제값 차이의 제곱의 합으로 정의함

- 마찬가지로 \(\beta_0, \beta_1, \beta_2, ... , \beta_M\)값을 조절하여 Loss 함수의 크기를 작게 함

$$ \frac{1}{N} \sum_{i}^{N}{(y^{(i)} - (\beta_0 + \beta_1 x_1^{(i)} + \beta_2 x_2^{(i)} + ... + \beta_M x_M^{(i)}))^2} $$'

- \(y^{(i)}\) : 실제값

- \( \beta_0 + \beta_1 x_1^{(i)} + \beta_2 x_2^{(i)} + ... + \beta_M x_M^{(i)}\) : 예측값


다중 선형 회귀 모델의 경사 하강법

1) \(\beta_0, \beta_1, \beta_2, ... , \beta_M\)값을 랜덤하게 초기화

2) 현재 \(\beta_0, \beta_1, \beta_2, ... , \beta_M\)값으로 Loss 값 계산

3) 현재 \(\beta_0, \beta_1, \beta_2, ... , \beta_M\)값을 어떻게 변화해야 Loss값을 줄일 수 있는지 알 수 있는 Gradient 값 계산

4) Gradient 값을 활용하여 \(\beta_0, \beta_1, \beta_2, ... , \beta_M\)값 업데이트

5) Loss값의 차이가 거의 없어질 때 까지 2~4번 과정을 반복(Loss값과 차이가 줄어들면 Gradient 값도 작아짐)


4. 회귀 평가 지표

- 어떤 모델이 좋은 모델인지, 목표를 얼마나 잘 달성했는지 정도를 평가해야 함

- 실제 값과 모델이 예측하는 값의 차이에 기반한 평가 방법 사용

- Loss는 모델에서 줄여야하는 값(대상)이며, MSE 등등은 지표

 

 

RSS(단순 오차;Residual Sum of Squares)

- 실제값과 예측값의 단순 오차 제곱의 합

- 값이 작을수록 모델의 성능이 높음

- 전체 데이터에 대한 실제값과 예측하는 값의 오차 제곱의 총합

$$ RSS = \sum_{i}^{N}{(y^{(i)} - (\beta_0 + \beta_1 x^{(i)}))^2} $$

- 가장 간단한 평가 방법으로 직관적인 해석이 가능함

- 그러나 오차를 그대로 이용하기 때문에 입력값의 크기에 의존적임

- 절대적인 값과 비교가 불가능함


MSE(Mean Square Error)

- 평균 제곱 오차

$$ MSE = \frac{1}{N}\sum_{i}^{N}{(y^{(i)} - (\beta_0 + \beta_1 x^{(i)}))^2} $$

- RSS에서 데이터 수 만큼 나눈 값

- 작을수록 모델의 성능이 높다고 할 수 있음

- 이상치(Outlier), 즉 데이터들 중 크게 떨어진 값에 민감함

from sklearn.metrics import mean_squared_error

mean_squared_error(y_true, y_pred)

MAE(Mean Absolute Error)

- 평균 절대값 오차

$$ MAE = \frac{1}{N} \sum_{i}^{N}{|y^{(i)} - (\beta_0 + \beta_1 x^{(i)})|} $$

- 실제값과 예측값의 오차의 절대값의 평균

- 작을수록 모델의 성능이 높다고 할 수 있음

- 변동성이 큰 지표와 낮은 지표를 같이 예측할 시 유용

- 가장 간단한 평가 방법들로 직관적인 해석이 가능

- 평균을 그대로 이용해 입력값의 크기에 의존적임

- 절대적인 값과 비교가 불가능함

from sklearn.metrics import mean_absolute_error

mean_absolute_error(y_true, y_pred)
train_X, test_X, train_Y, test_Y = train_test_split(X, Y, test_size=0.2, random_state=42)

model = LinearRegression()
model.fit(train_X, train_Y)

# train_X의 예측값 계산
pred_train = model.predict(train_X)

MSE_train = mean_squared_error(train_Y, pred_train)
MAE_train = mean_absolute_error(train_Y, pred_train)

\(R^2\) (결정계수)

- 회귀 모델의 설명력을 표현하는 지표

- 1에 가까울수록 높은 성능의 모델이라고 해석할 수 있음

$$ R^2 = 1 - \frac{RSS}{TSS} $$

- TSS : 데이터 평균값(\(\bar{y}\))과 실제값(\(y^{(i)}\)) 차이의 제곱

$$ TSS =\sum_{i}^{N}{(y^{(i)} - \bar{y})^2} $$

$$ \bar{y} = \frac{1}{N}\sum_{i}^{N}{y^{(i)}} $$

 

# test_X의 예측값 계산
pred_test = model.predict(test_X)

# test_X의 R2값 계산
r2_score(test_Y, pred_test)

 

- 오차가 없을수록 1에 가까운 값을 가짐

- 값이 0인 경우, 데이터의 평균값을 출력하는 직선 모델을 의미함

- 음수값이 나온 경우, 평균값 예측보다 성능이 좋지 않음