안녕하세요.

오늘은 선형회귀 및 polynomial Regression을 이해하고 행렬을 프로그램으로 변환하는 방법에 대해서 이해해보도록 해보겠습니다.
특히 모델링이라는 말의 의미를 이 포스팅을 보시고 이해해주시면 감사하겠습니다.

이해가 안가실 것같으니 아래와 같이 python으로 그래프를 그리면서 이야기를 해보면 쉽게 이해하실수 있습니다. 


%matplotlib inline
#문서내에 그래프 출력

import numpy as np
import pylab as pl


def f(size):
    '''
    사인곡선을 적용하여 원데이터를 발생
    Returns a sample with 'size' instances without noise.
    '''
    x = np.linspace(0, 4.5, size)
    y = 2 * np.sin(x * 1.5)
    return (x,y)

def sample(size):
    '''
    원데이터에 random함수를 적용해서 사인곡선을 적용하고
    여기에 노이즈를 추가로 더하여 size수량만큼 무작위로 뽑는 함수를 만듬
    Returns a sample with 'size' instances.
    '''
    x = np.linspace(0, 4.5, size)
    y = 2 * np.sin(x * 1.5) + pl.randn(x.size)
    return (x,y)

pl.clf()
f_x, f_y = f(50)
pl.plot(f_x, f_y)
x, y = sample(50)
pl.plot(x, y, 'k.')



위와같이 파란색으로  Sin곡선을 만들어봅니다. 가로는 0~4.5, 세로는 플러스 마이너스 2 범위내에서 한 주기가 되는 sin곡선을 만들었습니다.
여기에 50개의 샘플링을 한 점을 위와같이 무작위로 찍어봅니다.
이때 이 점은 원래는 파란색 선을 따라서 나와야 하지만 error 가 각각의 점마다 더하고 빼져서 파란색선을 따르지만 거리의 편차가 있는 점을 만들었다고 생각하시면 됩니다.

이러한 곡선은 현실세계에서는 존재하지 않지만 그래도 억지로 인위적으로 만들어 본다면,
계절마다 에어콘 가격 트랜드라고 예를 들어볼수 있습니다. 즉 파란선은 에어콘 가격의 절대적인 트랜트 이며,
실제 가격은 이 트랜드를 따른다고 생각하시면 됩니다.

X가 1일때 여름이라고 가정하고 그때가 가장 높게 가격이 책정되어 팔린다고 생각하시고,
X가 3일때 겨울이라고 생각하시고 그때가 가장 낮게 가격이 책정되어 팔린다고 생각하시면 됩니다.

하지만 이 절대적인 트랜드를 각 판매처에서 따른다고 하더라도, 실제 판매처에서는 이윤을 더 붙이든 , 아니면 낮게 붙일수 있습니다.
이렇게 절대적인 트랜드 보다 높거나 낮은 실제 가격에는 각각의 가격마다 error가 들어갔다고 보시면 됩니다.


pl.clf()
x, y = sample(50)
pl.plot(x, y, 'k.')



그래서 지금부터 설명하고자 하는 variance와 bias는 위와같이 각각의 판매처가 임의로 정한 가격들(검은색점)을 보고
에어콘의 가격트랜드(위에 사라진 파란색 선)를 파악하고자 할때 고민해야하는 상황으로 가정하고, 설명하도록 하겠습니다.

그렇습니다. 위의 데이터들만 보았을때는 X축은 오른쪽으로 갈수록 시간이 지나간다고 가정하고,
Y축은 기준 가격으로부터 상대적 차이를 표현한다고 가정하더라도,
어떠한 패턴을 나타내는지 눈으로 아니면 직감적으로 파악한다는 것은 어려운 일이 아닐수가 없습니다.

패턴을 파악한다는 것은 각각의 데이터를 보고 거리에 대해서 평균을 내서 그 데이터들을 대표하는 하나의 선으로 표현하는 것을 의미하는데,
여기서 선은 직선이 될수 있고 곡선이 될수도 있습니다. 


from sklearn.linear_model import LinearRegression

def fit_polynomial(x, y, degree):
    '''
    Fits a polynomial to the input sample.
    (x,y): input sample
    degree: polynomial degree
    '''
    model = LinearRegression()
    model.fit(np.vander(x, degree + 1), y)
    return model

def apply_polynomial(model, x):
    '''
    Evaluates a linear regression model in an input sample
    model: linear regression model
    x: input sample
    '''
    degree = model.coef_.size - 1
    y = model.predict(np.vander(x, degree + 1))
    return y

model = fit_polynomial(x, y, 1)
p_y = apply_polynomial(model, x)

pl.plot(x, y, 'k.')
pl.plot(x, p_y,'g')


직선이 된다면 위와같이 그릴수 있습니다. 
위와같이 직선으로만 트랜드선을 긋는것을 1차 선형 회귀라고 합니다. 

여기서는 데이터 트랜드가 직선임을 가정하고 모델을 Y=AX+B라고 지정한후에 

원 데이터들의 각 X를 입력했을때 나오는 Y의 값과 원 데이터 값의 차이를 평균을 내서 A와 B를 정한후

가장 공평한 선을 위와 같이 긋고 ,
이것이 데이터들의 패턴을 대표한다고 이야기 할수 있습니다.

하지만 눈으로 보아도 알수 있듯이 직선은 원 데이터가 가지고 있는 패턴을 너무나 많이 생략하여서
저 선만으로 판단할경우에는 시간이 갈수록 가격은 떨어져간다고 파악하게 됩니다.

하지만 원래 의도한 가격 그래프는 sin데이터 이므로 시간에 따라 가격이 떨어지는 것을 표현한 것이 아니라 
계절에 따라 가격은 변화하지 가격이 떨어짐을 표현한 것은 아닙니다. 

따라서 직선으로만 데이터의 패턴을 파악하면, 간단하여서 좋긴 하지만, 자칫 데이터의 가지고 있는 실제 패턴을 
오해해서 이해할수 있습니다.
'
그렇다면 좀 더 구체적인 선형 회귀를 하기 위해서는 데이터의 트랜드를 직선이 아닌 곡선이라고 가정할 필요가 있습니다.
즉 1차식이 아닌 다항식이라고 규정하고 선을 그어보는 것입니다.


그전에 필수적으로 알아야 할  파이썬의  함수 np.vander로 예제를 먼저 알아보도록 하겠습니다. 

np는 numpy의 줄임말로 
윗부분에서 import numpy as np 라고 줄임말을 지정해서 np라고 사용할수 있습니다. 
import numpy as num 이라고 하면 , 우리는 num.vander라고 사용해야합니다.
우선 예제를 보도록 하겠습니다.


# This illustrates how vander function works:
x = np.array([1,2,3])
print np.vander(x, 4)

결과 : 
[[ 1 1 1 1]
 [ 8 4 2 1]
 [27 9 3 1]]

x=np.array([1,2,3])은 x1을 가로 행렬 [1,2,3]을 제작한 것이고 , 

np.vander(x, 4)는 실제로는 아래와 같이 4개의 다항식을 만들어서 x를 차례대로 입력하라는 지시를 내린 것입니다.


즉 첫번째로 x^0(X의 영 승)은 1이고 , 이것을 처음 만들고

두번째로 x^1은  두번째 만들고 기존의 1은 오른쪽으로 이동시킵니다. 

세번째 x^2은 세번째 만들고 기존 결과를 오른쪽으로 이동시키고 왼쪽에 x^2를 위치시킵니다. 

네번째 x^3은 네번째 만들고 기존 결과는 오른쪽 이동, 왼쪽에 배치 시킵니다.

그리서 아래와 같은 행렬을 만들게 되고 


결과적으로 아래와 같은 결과를 만들게되었습니다.

결과 : 
[[ 1 1 1 1]
 [ 8 4 2 1]
 [27 9 3 1]]

이것은 머신러닝이나 수치해석을 할때 굉장히 중요한 개념입니다. 

즉 여러가지 다항식을 행렬로 계산하면 계산이 깔끔할뿐만 아니라 시간도 적게 걸리는 경우가 많습니다. 

행렬로 구하지 않을 경우 for문으로 1부터 N까지 x가 변할때마다 x의 값을 세제곱, 네제곱 하는 등의 계산을 해야하는데,
이것은 프로그래밍에서 굉장히 비효율적으로 바라보는 경향이 많습니다 

따라서 데이터를 분석할때는 다항식의 계산을 행렬로 변환하여 기억하고 프로그램까지 작성할수 있다면 잘하고 있다고 스스로를 칭찬하셔도 됩니다.

다시 데이터 포인트가 4개 즉 


 일경우 다항식의 계산은 아래와같이  표현할수 있습니다. 


 

.여기서 n은 몇차 다항식 지정할 것인가 의 질문에 차수에 해당되는 숫자입니다.
즉 ,  n=2면 2차 다항식, n=3이면 3차 다항식으로 표현하여 선을 그어 볼수 있겠지요.


그럼 polynomial 다항식을 사용하는 방법을 아래와 같이 작성예제를 확인해봅니다.

# polynomial 다항식을 정의하는 함수를 작성합니다.

def fit_polynomial(x, y, degree):
    model = LinearRegression()
    model.fit(np.vander(x, degree + 1), y)
    return model

좀 상세하게 본다면 아래는 사용자가 직접 함수를 만들때 쓰는 명령어입니다. 

def fit_polynomial(x, y, degree):

def는 definition의 줄임말이고 fit_polynmial은 사용자가 지정한 함수 명입니다.
(x,y,degree)는 함수를 사용할때 필히 입력해야하는 변수를 지정해놓았습니다.

    model = LinearRegression()


위의 명령어는 model이라는 사용자 정의명에 LinearRegression()의 함수를 지정하였습니다. 
LinearRegression()은 sklearn 라는 라이브러리에 저장되어 있고

from sklearn.linear_model import LinearRegression

라고 초반에 작성하여 라이브러리를 불러냈다면 이후 사용은 언제든지 저렇게 간단하게 사용할수 있습니다.

    model.fit(np.vander(x, degree + 1), y)

마찬가지로 LinearRegression함수 안에 fit이라는 메서드 를 이미 지정되어있기 때문에 그냥 가져다 쓰기만 하면됩니다.
여기서 np.vander(x, degree + 1) 은 지정된 X를 1부터 시작해서 X의 N승까지 행렬로 표현해서 입력한 것입니다.

  return model

그리고 사용자가 지정한 모델을 반환하시면 향후 fit_polynomial(x, y, degree) 명령어만으로도 x와 y의 데이터 포인트 그리고 degree만 입력하면 

python이 알아서 polynomial regression으로 모델링을 해줍니다. 

여기서 모델링을 한다는 것은 다항식의 각각의 계수를 지정해준다는 말로 아래의 B 베타값을 계산하여 정한다는 이야기라고 생각하시면 됩니다.


def apply_polynomial(model, x):
     degree = model.coef_.size - 1
    y = model.predict(np.vander(x, degree + 1))
    return y

위의 함수는 모델링된 함수를 그래프로 그리기 편하게
X가 입력되면 모델에 의해서 
Y의 값이 자동적으로 출력되도록 함수를 작성하였습니다.

그래서 아래와 같이 8차 다항식의 모델을 만든후에 모델링후 
각각의 x값을 적용해준다면 아래와같이 모델링된 데이터패턴을 확인할수 있습니다.

model = fit_polynomial(x, y, 8)
p_y = apply_polynomial(model, x)
pl.plot(x, y, 'k.')
pl.plot(x, p_y,'g')



위와 같이 각각의 데이터를 이용해서 8차 다항식의 선형회귀 모델을 모델링 하였습니다.

여기서는 기존의 원 트랜드와 같이 sin 곡선과 유사한 패턴을 그려서 먼저번의 직선보다 좀더 정확한 데이터 패턴을 구했다고 생각하시면 됩니다.

그럼 여기까지 하고 추가적으로 다음시간에는 좀 더 자세히 분산과 bias에 대해서 알아보도록 하겠습니다.
감사합니다.

참조 사이트



+ Recent posts