호기심 많은 분석가

[ML] 다중 회귀 VS 다항 회귀 (Multiple VS Polynomial regression) 본문

Coding/Machine Learning & Python

[ML] 다중 회귀 VS 다항 회귀 (Multiple VS Polynomial regression)

DA Hun 2021. 6. 7. 20:48

목차

     

     우리는 머신러닝 기법을 사용할 때 회귀 관련 모델을 사용하긴 한다. 가장 기본적인 선형 회귀(Linear Regression) 모델을 많이 사용할 텐데, 데이터의 분포가 직선이 아니라 곡선 형태를 띠고 있을 경우 오차가 크게 나타날 수 있다. 그럴 때 사용할 수 있는 다항 회귀를 헷갈릴 수 있는 다중 회귀와 비교하며 알아보자.

    회귀 분석 (Regression Analysis)

     그게 앞서 회귀 분석부터 알아보자

    • 정의
      • 회귀 분석이란, 관찰된 연속형 변수들에 대해 두 변수 사이의 모형을 구한 뒤 적합도를 측정해내는 분석 방법
      • 회귀 분석은 시간에 따라 변화하는 데이터나, 어떤 영향, 가설적 실험, 인과 관계의 모델링등의 통계적 예측에 사용
    • 회귀 분석은 하나의 종속변수와 하나의 독립변수 사이의 관계를 분석하는 단순 회귀 분석과 하나의 종복변수와 여러 독립변수 사이의 관계를 분석하는 다중 회귀 분석으로 나뉜다.
      • 독립변수와 종속변수는 실험으로 획득한 데이터를 통해 수학적 모델을 세우거나 통계적 모델을 세울 때 사용되는 변수의 두 종류
        • 독립변수(independent varibale) - 입력값이나 원인
        • 종속변수(dependent variable) - 독립변수에 의해 영향을 받는, 결과물이나 효과를 나타낸다
        • Ex) y=3x+5라는 함수가 있을 때 y는 x에 따라 변하므로 종속변수, x는 독립변수
    • 정리
      • 회귀 문제는 연속된 값을 가진 결과를 예측하는 것, 예측하는 함수를 찾는 것이 회귀 분석의 목적
        • Ex) 부동산 평수에 따른 집값 가격 예측을 선형 회귀로 진행

    회귀 함수 이미지

    • 가설함수와 비용함수
      • 회귀 모델이 학습으로 찾은 함수를 가설 함수(hypothesis function)라고 하며, 예측 결과의 정확도를 판단하는 함수를 비용 함수(cost function)이라고 한다.
      • 회귀 모델의 비용 함수는 여러 가지가 있지만 평균 제곱 오차(Mean Squared Error, MSE)가 사용되며, 가설 함수의 결과(예측값)과 실측값(정답)의 오차 제곱의 합이 MSE이다.
      • 좌표계에서 MSE의 의미는 아래의 그림으로 설명된다. 거리는 예측값과 실측값의 차이이며, 모든 데이터에 대해 이 값이 가장 작은 함수가 바로 가설 함수이다.

    좌표계에서 함수와 데이터의 오차 표현 이미지

    다중 회귀 (Multivariate Linear Regression) 

    • 변수(feature)가 2개 이상인 데이터의 결과를 예측하는 것
    • 가설 함수는 다음과 같은 형태이며, n은 (feature의 개수+1)이다. +1은 bias인 첫 번째 파라미터를 포함 $$ h_\theta(x) = \theta_0 + \theta_1x_1 +\theta_2x_2 + \dots + \theta_nx_n $$
    • 다중 회귀 분석시 독립변수간 상관관계가 높아 발생하는 다중공선성(multicollinearity) 문제 처리가 필요
      • 다중공선성 확인은 분산팽창지수 (Variation Inflation Factor, VIF)로 확인 가능
    • Feature Scaling : 서로 다른 변수들은 범위가 달라서 비용함수의 그래프에서 파라미터를 임의 값으로 했을 때, 극소점하고 멀리 떨어져 있을 확률이 높다. 비용 함수의 그래프가 3차원일 때 매우 넓게 퍼져 있음. 변수의 범위가 많이 차이날 경우 경사 하강법에 시간이 오래 걸리는 단점이 있다. 따라서, 학습 속도를 높이기 위해 변수의 범위가 모두 동일하도록 스케일링 해줘야 한다.
      • 보통 모든 변수의 범위를 -1 ~ 1 사이로 스케일링함
      • 단, 어떤 변수의 범위 차이가 많이 나면 안된다. -100 ~ 100 인 거랑 -0.0001 ~ 0.0001 인 경우 두 feature에 대한 전처리는 필수
      • 너무 정확할 필요는 없다. 경사 하강법을 빠르게 하기 위한 것
      • Mean normalization : 각 데이터에 일반적으로 적용되는 방식으로, feature 내 평균값을 뺀 다음 feature의 범위로 나눠준다. $$ \acute{x} = \frac{x - average(x)}{max(x) - min(x)} $$
      • 경사 하강법이 올바르게 작동하는 경우 매 반복마다 비용 함수가 줄어들어야하기 때문에, 그래프의 형태가 그렇지 않다면 코드를 고쳐줘야 한다.
      • 학습률이 너무 작으면 시간이 오래걸리고, 너무 크면 비용 함수가 적절히 수렴하지 않을 수 있다. 따라서 0.001부터 3배씩 학습률을 늘려보면서 적절한 값을 찾는 것이 좋음

    다항 회귀 (Polynomial Regression)

    $$ y=w_0 + w_1x + w_2x^2 + \dots + w_dx^d $$

    • 독립변수의 차수를 높이는 형태
    • 다차원의 회귀식인 다항 회귀 분석으로 단순 선형 모델의 한계를 어느정도 극복할 수 있음.
      • 함수가 비선형, 데이터가 곡선 형태일 경우 예측에 유리
      • 데이터에 각 특성의 제곱을 추가해주어서 특성이 추가된 비선형 데이터를 선형 회귀 모델로 훈련시키는 방법
    • 보통 2차함수는 중간에 하강하므로 3차(cubic) 함수부터 아니면 단조증가하는 제곱근이나 로그 함수를 많이 쓴다.
    • 다항 회귀도 결국 $ x^d=X_d $로 뒀을 때 다중 회귀식의 일종이라고 볼 수 있다.

    다항회귀 이미지 예시


    Code를 통한 이해

    Import Library

    %matplotlib inline
    import numpy as np
    import pandas as pd
    import matplotlib
    import matplotlib.pyplot as plt
    from matplotlib import style
    from sklearn.linear_model import LinearRegression
    from sklearn.metrics import mean_squared_error
    from sklearn.metrics import r2_score
    from sklearn.preprocessing import PolynomialFeatures
    
    style.use('seaborn-talk')
    import matplotlib
    import matplotlib.font_manager as fm
    import os
    
    # 한글 폰트 사용
    def change_matplotlib_font(font_download_url):
        FONT_PATH = 'MY_FONT'
        
        font_download_cmd = f"wget {font_download_url} -O {FONT_PATH}.zip"
        unzip_cmd = f"unzip -o {FONT_PATH}.zip -d {FONT_PATH}"
        os.system(font_download_cmd)
        os.system(unzip_cmd)
        
        font_files = fm.findSystemFonts(fontpaths=FONT_PATH)
        for font_file in font_files:
            fm.fontManager.addfont(font_file)
    
        font_name = fm.FontProperties(fname=font_files[0]).get_name()
        matplotlib.rc('font', family=font_name)
        print("font family: ", plt.rcParams['font.family'])
    
    font_download_url = "https://fonts.google.com/download?family=Noto%20Sans%20KR"
    change_matplotlib_font(font_download_url)
    # np.newaxis란 차원을 늘려줌 (10,)을 (10, 1)로
    X = np.array([258, 270, 294, 320, 342,
                  368, 396, 446, 480, 586])[:, np.newaxis]
    y = np.array([236.4, 234.4, 252.8, 298.6, 314.2,
                  342.2, 360.8, 368.0, 391.2, 390.8])
    lr = LinearRegression()
    pr = LinearRegression()
    
    # 기본 다항식 형태 생성
    # include_bias=True로 할 경우 0차항(1)도 함께 만든다. defualt값 True
    quadratic = PolynomialFeatures(degree=2, include_bias=True)
    # 정의된 numpy 배열은 행별로 각 데이터를 다항 형태로 변형해준다
    # 1과 주어진 값과 주어진 값을 제곱한 항을 추가하여 반환
    X_quad = quadratic.fit_transform(X)
    
    display(X[0], X_quad[0]) # array([258]), array([1.0000e+00, 2.5800e+02, 6.6564e+04])
    
    # 비교를 위해 단순 회귀 계산
    lr.fit(X, y)
    X_fit = np.arange(250, 600, 10)[:, np.newaxis]
    y_lin_fit = lr.predict(X_fit)
    
    # 다항 회귀를 위해 변형된 모델에 다중 회귀 모델 계산
    pr.fit(X_quad, y)
    y_quad_fit = pr.predict(quadratic.fit_transform(X_fit))
    
    # 단순 회귀 및 다항 회귀 모델의 예측값 계산
    y_lin_pred = lr.predict(X)
    y_quad_pred = pr.predict(X_quad)
    
    mse_lin = mean_squared_error(y, y_lin_pred)
    mse_quad = mean_squared_error(y, y_quad_pred)
    
    r2_lin = r2_score(y, y_lin_pred)
    r2_quad = r2_score(y, y_quad_pred)
    
    print(f'MSE\tLinear : {mse_lin:.2f},\tQuadratic: {mse_quad:.2f}')
    print(f'R2\tLinear : {r2_lin:.2f},\tQuadratic: {r2_quad:.2f}')
    
    plt.scatter(X, y, label='트레이닝 데이터')
    plt.plot(X_fit, y_lin_fit, label='linear fit', linestyle='--')
    plt.plot(X_fit, y_quad_fit, label='quadratic fit')
    plt.legend(loc=2)
    plt.show()

    비선형 데이터에는 다항 회귀가 적합함을 보여주는 예시 이미지

     위의 그래프를 통해서 비선형의 데이터에는 다항 회귀를 사용하여 예측하는 것이 조금 더 높은 효율을 보임을 확인할 수 있다. 

    Pipeline 응용

     위의 과정을 make_pipeline을 통해 PolynomialFeatures와 LinearRegression 과정이 한번에 통합된 모델을 생성

    # 데이터 변환 과정과 머신러닝을 연결해주는 파이프라인
    from sklearn.pipeline import make_pipeline
    
    model_lr = make_pipeline(PolynomialFeatures(degree=2, include_bias=True),
    						LinearRegression())
    model_lr.fit(X, y)
    print(model_lr.steps[1][1].coef_) # [ 0.00000000e+00  2.39893018e+00 -2.25020109e-03]

     

    • make_pipeline으로 생성된 모델은 step에 따라 과정이 나누어진다. (steps함수도 존재하여 파이프라인에 포함된 모델의 형태를 확인할 수도 있다.
      steps 함수를 통해 파이프라인에 포함된 모델 형태 확인
    • 그렇게 생성된 모델이 X와 y를 fit시키고, 최종적으로 steps를 통해 학습된 모델의 형태를 확인할 수 있다.

    Feature selection (변수 선택법)

    1. All possible regressions

    • 변수들의 가능한 모든 조합들로부터 최적의 모형을 찾아냄
    • 유의한 변수가 누락되지 않는 안전한 방법
    • 변수가 많을수록 탐색 시간이 급증함

    2. Forward stepwise selection (Forward selection)

    • 기여도가 높은 유의한 변수부터 하나씩 추가하는 기법
    • 빠른 계산이 장점
    • 이미 선택된 변수는 다시 제거되지 않음

    3. Backward stepwise selection (Backward elimination)

    • 모든 변수를 포함한 상태에서 불필요한 변수를 제거해나가는 방법
    • 중요한 변수가 제외될 가능성이 매우 적음
    • 이미 제외된 변수는 다시 선택되지 않음

    Forward stepwise 변수 선택법과 Backward stepwise 변수 선택법 시각화 예시