: 여러 개의 독립 변수와 한 개의 종속 변수 간의 상관관계를 모델링 하는 기법
: 주어진 피처와 결정 값 데이터 기반에서 학습을 통해 최적의 회귀계수(Regression coefficients)를 찾아내는 것
독립변수 갯수 | 회귀 계수의 결합 |
---|---|
1개 : 단일 회귀 | 선형 : 선형 회귀 |
1개(n) ⁍ : 다항 회귀 | 선형 : 선형 회귀 |
여러개 : 다중 회귀 | 비선형 : 비선형 회귀 |
선형 회귀 : 실제 값과 예측 값의 차이(오류의 제곱 값)를 최소화하는 직선형 회귀선을 최적화하는 방식
단순 선형 회귀로 이해해보기
RSS(Residual Sum of Square) : 오류에 제곱을 해서 더하는 방식
회귀에서 이 RSS 값은 비용(Cost)이며, w변수(회귀계수) 구성되는 RSS를 비용 함수라고 함
경사하강법: 점진적으로 반복적인 계산을 통해 W를 업데이트하면서 오류값이 최소가 되는 W를 구하는 방식
2차함수의 최저점은 미분 값인 1차 함수의 기울기가 가장 최소일 때
를 각 로 편미분
의 편미분 결괏값인 , 을 반복적으로 보정하면서, 값을 업데이트 하면서 비용 함수 를 최소가 되는 을 구할 수 있음
경사 하강법의 일반적인 프로세스
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
### --- 실제값을 Y=4X+6 시뮬레이션하는 데이터 값 생성 ----------------------------
np.random.seed(0)
# y = 4X + 6 식을 근사(w1=4, w0=6). random 값은 Noise를 위해 만듬
X = 2 * np.random.rand(100,1)
y = 6 +4 * X+ np.random.randn(100,1)
print(type(X))
### --- w0과 w1의 값을 최소화 할 수 있도록 업데이트 수행하는 함수 생성 ---------------------
# 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 # 실제값 - 예측값
# diff == error
# 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)) # w1의 편미분 값
w0_update = -(2/N)*learning_rate*(np.dot(w0_factors.T, diff)) # w0의 편미분 값
return w1_update, w0_update
### --- 반복적으로 경사 하강법을 이용하여 get_weigth_updates()를 호출하여 w1과 w0를 업데이트 하는 함수 생성 ---
# 입력 인자 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, w0 편미분값 return
w1 = w1 - w1_update # 새로운 w1
w0 = w0 - w0_update # 새로운 w0
return w1, w0
### --- 예측 오차 비용을 계산을 수행하는 함수 생성 및 경사 하강법 수행 ---------------------
def get_cost(y, y_pred):
N = len(y)
cost = np.sum(np.square(y - y_pred))/N # 평균( (실제값 - 예측값)^2 ) = RMSE
return cost
w1, w0 = gradient_descent_steps(X, y, iters=1000)
print("w1:{0:.3f} w0:{1:.3f}".format(w1[0,0], w0[0,0]))
y_pred = w1[0,0] * X + w0
print('Gradient Descent Total Cost:{0:.4f}'.format(get_cost(y, y_pred)))
전반적으로 경사하강법과 비슷하지만, 전체 X, y 데이터에서 랜덤하게 batch_size만큼 데이터를 추출해서 w1, w0을 업데이트 함
def stochastic_gradient_descent_steps(X, y, batch_size=10, iters=1000):
w0 = np.zeros((1,1))
w1 = np.zeros((1,1))
prev_cost = 100000
iter_index =0
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]) # permutation : array를 복사해서 shuffle
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
return 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))
y_pred = w1[0,0] * X + w0
print('Stochastic Gradient Descent Total Cost:{0:.4f}'.format(get_cost(y, y_pred)))
보스턴 주택 가격 예측 예시
fit()
메서드로 X, y 배열 받으면, 회귀 계수(Coefficients)인 W를 coef_
속성에 저장MAE(Mean Absolute Error)
metrics.mean_absolute_error
MSE(Mean Squared Error)
metrics.mean_squared_error
RMSE(Root MSE)
metrics.r2_score
: 예측값과 실제값의 RSS를 최소화해 OLS(Ordinary Least Squares) 추정방식으로 구현한 클래스
입력 파라미터
파라미터 | 디폴트 | 설명 |
---|---|---|
fit_intercept | Ture | Boolean, intercept(절편)값을 계산할 것인지 결정 |
normalize | False | Boolean, True면 회귀를 수행하기 전에 입력 데이터 세트 정규화, fit_intercept=False 인 경우 이 파라미터는 무시됨 |
속성
: 회귀가 독립변수의 단항식이 아닌 2차, 3차 방정식과 같은 다항식으로 표현되는 것(하지만 선형회귀다!)
예)
from sklearn.preprocessing import PolynomialFeatures
import numpy as np
# 다항식으로 변환한 단항식 생성, [[0,1],[2,3]]의 2X2 행렬 생성
X = np.arange(4).reshape(2,2)
print('일차 단항식 계수 feature:\n',X )
# degree = 2 인 2차 다항식으로 변환하기 위해 PolynomialFeatures를 이용하여 변환
poly = PolynomialFeatures(degree=2) # 2차 다항값을 만들겠다는 것
poly.fit(X)
poly_ftr = poly.transform(X)
print('변환된 2차 다항식 계수 feature:\n', poly_ftr)
------------------------------------------
> 일차 단항식 계수 feature:
> [[0 1]
> [2 3]]
> 변환된 2차 다항식 계수 feature:
> [[1. 0. 1. 0. 0. 1.]
> [1. 2. 3. 4. 6. 9.]]
# 3 차 다항식 변환
poly_ftr = PolynomialFeatures(degree=3).fit_transform(X)
print('3차 다항식 계수 feature: \n',poly_ftr)
# Linear Regression에 3차 다항식 계수 feature와 3차 다항식 결정값으로 학습 후 회귀 계수 확인
model = LinearRegression()
model.fit(poly_ftr,y)
print('Polynomial 회귀 계수\n' , np.round(model.coef_, 2))
print('Polynomial 회귀 Shape :', model.coef_.shape)
------------------------------------------------
> 3차 다항식 계수 feature:
> [[ 1. 0. 1. 0. 0. 1. 0. 0. 0. 1.]
> [ 1. 2. 3. 4. 6. 9. 8. 12. 18. 27.]]
> Polynomial 회귀 계수
> [0. 0.18 0.18 0.36 0.54 0.72 0.72 1.08 1.62 2.34]
> Polynomial 회귀 Shape : (10,)
from sklearn.pipeline import Pipeline
def polynomial_func(X):
y = 1 + 2*X[:,0] + 3*X[:,0]**2 + 4*X[:,1]**3
return y
# Pipeline 객체로 Streamline 하게 Polynomial Feature변환과 Linear Regression을 연결
model = Pipeline([('poly', PolynomialFeatures(degree=3)),
('linear', LinearRegression())])
X = np.arange(4).reshape(2,2)
y = polynomial_func(X)
model = model.fit(X, y)
print('Polynomial 회귀 계수\n', np.round(model.named_steps['linear'].coef_, 2))
------------------------------------------------
> Polynomial 회귀 계수
> [0. 0.18 0.18 0.36 0.54 0.72 0.72 1.08 1.62 2.34]