반응형
In [64]:
from IPython.core.display import display, HTML
display(HTML("<style>.container { width:100% !important; }</style>"))
회귀¶
- 예측을 해야하는 부분이라서 기업에서 가장많이 활용 됨.
- 데이터 값이 평균과 같은 일정한 값으로 돌아가려는 경향을 이용한 통계학 기법
- 여러개의 독립변수와 한개의 종속변수간의 상관관계를 모델링 하는 기법을 통칭
- 방개수 + 아파트크기 + 주변학군 + 근처 지하철 역 갯수 (독립변수) = 아파트 가격(종속변수)
- feature : 독립변수 , Target : 종속변수
- 회귀계수(Regression coefficients) : 독립변수의 값에 영향을 미치는 회귀 계수
- 머신러닝 회귀예측의 핵심
- 주어진 피처와 결정 값 데이터 기반에서 학습을 통해 최적의 회귀 계수를 찾아내는 것
- 선형회귀가 비선형회귀보다 예측성능이 좋다
선형 회귀의 종류¶
- 일반 선형회귀 : 예측값과 실제값의 RSS(Residual Sum of Squares)를 최소화 하도록 회귀계수 최적화
규제를 적용하지 않은 모델 - 릿지(Ridge) : 선형 회귀에 L2규제를 추가한 회귀 모델
- 라쏘(Lasso) : 선형 회귀에 L1규제를 추가한 회귀 모델
- 엘라스틱넷(ElasticNet) : L1 + L2
- 로지스틱 회귀(Logistic Regression) : 0,1값을 예측하므로 사실 분류에 사용됨
RSS의 편미분¶
w1과 w0에 편미분 w1,w0를 적용하는데 편미분 값이 너무 클 수 있기 때문에 보정계수 n(학습률)을 곱한다.¶
- 계속 w1,w0를 업데이트 해주면서 loss를 계산함.
- loss가 최소가 되면 최적의 w1,w0를 찾은 것.
Gradient Descent¶
실제 값을 Y=4X+6 시뮬레이션하는 데이터 값 생성¶
In [16]:
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
np.random.seed(0)
# y= 4x+6식을 근사(w1 = 4, w0=6) random 값은 Noise를 위해 만듦.
X = 2*np.random.rand(100,1) #100x1 train 행렬 생성
y = 6+4*X +np.random.randn(100,1) #100x1 target 행렬 생성
#X,y 데이터 셋 Scatter plot으로 시각화
plt.scatter(X,y)
Out[16]:
<matplotlib.collections.PathCollection at 0x2b90d89e608>
In [17]:
X.shape, y.shape
Out[17]:
((100, 1), (100, 1))
In [18]:
# 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
In [19]:
w0 = np.zeros((1,1))
w1 = np.zeros((1,1))
y_pred = np.dot(X, w1.T)+w0
diff = y-y_pred
print(diff.shape)
w0_factors = np.ones((100,1))
w1_update = -(2/100)*0.01*(np.dot(X.T, diff))
w0_update = -(2/100)*0.01*(np.dot(w0_factors.T, diff))
print(w1_update.shape, w0_update.shape)
w1, w0
(100, 1) (1, 1) (1, 1)
Out[19]:
(array([[0.]]), array([[0.]]))
반복적으로 경사 하강법을 이용하여 get_weight_updates()를 호출하여 w1과 w0를 업데이트 하는 함수 생성¶
In [20]:
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
예측 오차 비용 계산을 수행하는 함수 생성 및 경사 하강법 수행¶
In [21]:
def get_cost(y, y_pred):
N= len(y)
cost = np.sum(np.square(y-y_pred))/N
return cost
w1, w0 = gradient_descent_steps(X, y, iters = 1000)
print(f'w1 : {w1[0,0]:.3f}, w0 : {w0[0,0]}')
y_pred = w1[0,0] *X + w0
print(f'Gradient Descent Total Cost : {get_cost(y,y_pred):.4f}')
w1 : 4.022, w0 : 6.162031224717461 Gradient Descent Total Cost : 0.9935
In [22]:
plt.scatter(X,y)
plt.plot(X,y_pred)
Out[22]:
[<matplotlib.lines.Line2D at 0x2b90d8fd0c8>]
미니 배치 확률적 경사 하강법을 이용한 최적 비용함수 도출¶
아래처럼 하면 학습 샘플에 중복나지 않나 ??
In [23]:
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])
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
In [24]:
np.random.permutation(X.shape[0])
Out[24]:
array([66, 71, 54, 88, 82, 12, 36, 46, 14, 67, 10, 3, 62, 29, 97, 69, 70, 93, 31, 73, 60, 96, 28, 27, 21, 19, 33, 78, 32, 94, 1, 41, 40, 76, 37, 87, 24, 23, 50, 2, 47, 20, 77, 17, 56, 64, 68, 25, 15, 22, 16, 98, 63, 92, 86, 38, 6, 57, 95, 44, 9, 42, 81, 99, 35, 84, 59, 48, 75, 65, 85, 90, 55, 43, 58, 89, 30, 80, 34, 18, 51, 49, 52, 74, 26, 45, 39, 4, 11, 53, 91, 79, 8, 0, 5, 13, 61, 72, 7, 83])
In [25]:
w1, w0 = stochastic_gradient_descent_steps(X,y, iters = 1000)
print(f'w1:{round(w1[0,0],3)}, w0: {round(w0[0,0],3)}')
y_pred = w1[0,0] * X + w0
print(f'Stochastic Gradient Descent Total Cost : {get_cost(y, y_pred):.4f}')
w1:4.028, w0: 6.156 Stochastic Gradient Descent Total Cost : 0.9937
사이킷 런 LinearRegression 클래스¶
- 예측값과 실제값의 RSS를 최소화하여 OLS(Ordinary Least Squares) 추정방식으로 구현한 클래스.
- fit메서드로 X,y를 입력 받으면 회귀 계수W를 coef_ 속성에 저장한다.
- 입력 파라미터
- fit_intercept: 절편값을 계산할 것인지 말지를 지정. default : True (절편계산)
- normalize : default : false. True이면 입력 데이터 세트를 정규화 함.
- 속성
- coef_: fit() 메서드를 수행했을 때 회귀 계수가 배열 형태로 저장하는 속성.
shape(Target 값 개수, 피처 개수) - intercept_ : intercept값. ### 선형 회귀의 다중 공선성 문제 (multi-collinearity)
- coef_: fit() 메서드를 수행했을 때 회귀 계수가 배열 형태로 저장하는 속성.
- 일반적으로 선형회귀는 입력피처의 독립성에 많은 영향.
- 상관관계가 매우 높은 경우 분산이 매우 커져서 오류에 매우 민감.
- 일반적으로 상관관계가 높은 피처가 많은 경우 독립적인 중요한 피처만 남기고 제거 or 규제
사이킷런에서는 RMSE를 제공하지 않음. RMSE를 구하려면 MSE에 제곱근씌우는 함수 구현해야함¶
Scoring(cross_val_score, GridSearchCV) 함수에 회귀 평가 적용시 유의 사항¶
- negative를 쓰는 이유. classification은 정확도, f1score 등 클수록 좋게끔 셋팅 되어 있는데
회귀에서는 loss값이 작아지는게 좋은거라서 -1곱해서 사용.
특히 RMSE 직접 만들어 쓸 때 주의.
사이킷런 LinearRegression 을 이용한 보스턴 주택 가격 예측¶
In [26]:
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns
from scipy import stats
from sklearn.datasets import load_boston
%matplotlib inline
#boston 데이터셋 로드
boston = load_boston()
#boston dataset을 DataFrame으로 전환
bostonDF = pd.DataFrame(boston.data, columns = boston.feature_names)
#boston dataset의 target array는 주택 가격임. 이를 PRICE 컬럼으로 DataFrame에 추가함.
bostonDF['PRICE'] = boston.target
print(f'Boston 데이터셋 크기 {bostonDF.shape}')
bostonDF.head()
Boston 데이터셋 크기 (506, 14)
Out[26]:
CRIM | ZN | INDUS | CHAS | NOX | RM | AGE | DIS | RAD | TAX | PTRATIO | B | LSTAT | PRICE | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0.00632 | 18.0 | 2.31 | 0.0 | 0.538 | 6.575 | 65.2 | 4.0900 | 1.0 | 296.0 | 15.3 | 396.90 | 4.98 | 24.0 |
1 | 0.02731 | 0.0 | 7.07 | 0.0 | 0.469 | 6.421 | 78.9 | 4.9671 | 2.0 | 242.0 | 17.8 | 396.90 | 9.14 | 21.6 |
2 | 0.02729 | 0.0 | 7.07 | 0.0 | 0.469 | 7.185 | 61.1 | 4.9671 | 2.0 | 242.0 | 17.8 | 392.83 | 4.03 | 34.7 |
3 | 0.03237 | 0.0 | 2.18 | 0.0 | 0.458 | 6.998 | 45.8 | 6.0622 | 3.0 | 222.0 | 18.7 | 394.63 | 2.94 | 33.4 |
4 | 0.06905 | 0.0 | 2.18 | 0.0 | 0.458 | 7.147 | 54.2 | 6.0622 | 3.0 | 222.0 | 18.7 | 396.90 | 5.33 | 36.2 |
- CRIM: 지역별 범죄 발생률
- ZN: 25,000평방피트를 초과하는 거주 지역의 비율
- NDUS: 비상업 지역 넓이 비율
- CHAS: 찰스강에 대한 더미 변수(강의 경계에 위치한 경우는 1, 아니면 0)
- NOX: 일산화질소 농도
- RM: 거주할 수 있는 방 개수
- AGE: 1940년 이전에 건축된 소유 주택의 비율
- DIS: 5개 주요 고용센터까지의 가중 거리
- RAD: 고속도로 접근 용이도
- TAX: 10,000달러당 재산세율
- PTRATIO: 지역의 교사와 학생 수 비율
- B: 지역의 흑인 거주 비율
- LSTAT: 하위 계층의 비율
- MEDV: 본인 소유의 주택 가격(중앙값)
각 컬럼별로 주택 가격에 미치는 영향도를 조사¶
In [27]:
#2개의 행과 4개의 열을 가진 subplots를 이용 axs는 4X2개의 ax를 가짐.
fig, axs = plt.subplots(figsize = (16,8), ncols = 4, nrows =2)
lm_features = ['RM','ZN','INDUS','NOX','AGE','PTRATIO','LSTAT','RAD']
for i , feature in enumerate(lm_features):
row = i//4
col = i%4
#seaborn의 regplot을 이용해 산점도와 선형 회귀 직선을 함께 표현
sns.regplot(x = feature, y = 'PRICE', data=bostonDF, ax=axs[row][col])
In [28]:
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error, r2_score
y_target = bostonDF['PRICE']
X_data = bostonDF.drop(['PRICE'], axis =1, inplace =False)
X_train, X_test, y_train, y_test = train_test_split(X_data, y_target, test_size =0.3, random_state =156)
#Linear Regression OLS로 학습/예측/평가 수행
lr = LinearRegression()
lr.fit(X_train, y_train)
y_preds = lr.predict(X_test)
mse = mean_squared_error(y_test, y_preds)
rmse = np.sqrt(mse)
print(f'MSE : {mse:.3f}, RMSE : {rmse:.3f}')
print(f'Variance score : {r2_score(y_test, y_preds):.4f}')
MSE : 17.297, RMSE : 4.159 Variance score : 0.7572
In [29]:
print(f'절편값 : {lr.intercept_}')
print(f'회귀 계수값 : {np.round(lr.coef_,1)}')
type(np.round(lr.coef_,1))
절편값 : 40.995595172164336 회귀 계수값 : [ -0.1 0.1 0. 3. -19.8 3.4 0. -1.7 0.4 -0. -0.9 0. -0.6]
Out[29]:
numpy.ndarray
In [30]:
#회귀 계수를 큰 값 순으로 정렬하기 위해 Series로 생성. index가 컬럼명에 유의
coeff = pd.Series(data = np.round(lr.coef_, 1), index = X_data.columns)
coeff.sort_values(ascending = False)
Out[30]:
RM 3.4 CHAS 3.0 RAD 0.4 ZN 0.1 B 0.0 TAX -0.0 AGE 0.0 INDUS 0.0 CRIM -0.1 LSTAT -0.6 PTRATIO -0.9 DIS -1.7 NOX -19.8 dtype: float64
In [31]:
from sklearn.model_selection import cross_val_score
y_target = bostonDF['PRICE']
X_data = bostonDF.drop(['PRICE'], axis = 1, inplace = False)
lr = LinearRegression()
#cross_val_score()로 5Fold 셋으로 MSE 를 구한 뒤 이를 기반으로 다시 RMSE 구함.
neg_mse_scores = cross_val_score(lr, X_data , y_target,
scoring = 'neg_mean_squared_error', cv = 5)
rmse_scores = np.sqrt(-1 * neg_mse_scores)
avg_rmse = np.mean(rmse_scores)
# cross_val_score(scoring="neg_mean_squared_error")로 반환된 값은 모두 음수
print(' 5 folds 의 개별 Negative MSE scores: ', np.round(neg_mse_scores, 2))
print(' 5 folds 의 개별 RMSE scores : ', np.round(rmse_scores, 2))
print(' 5 folds 의 평균 RMSE : {0:.3f} '.format(avg_rmse))
5 folds 의 개별 Negative MSE scores: [-12.46 -26.05 -33.07 -80.76 -33.31] 5 folds 의 개별 RMSE scores : [3.53 5.1 5.75 8.99 5.77] 5 folds 의 평균 RMSE : 5.829
반환값이 마이너스임에 유의¶
다항회귀 개요(Polynomial Regression)¶
- 다항회귀 역시 선형회귀임. 회귀에서 선형/ 비선형을 나누는 기준은
회귀 계수가 선형/비선형인지에 따른 것이지 독립변수의 선형/비선형과는 무관하다. - 사이킷런은 다항회귀를 API로 제공하지 않는다. 대신 PolynomialFeatures 클래스로
단항을 다항으로 변환한 데이터 세트에 LinearRegression 객체를 적용하여 다항회귀 기능 제공. - PolynomialFeatures : 원본 피처 데이터 세트를 기반으로 degree 차수에 따른 다항식을 적용
새로운 피처들을 생성하는 클래스. 피처 엔지니어링 기법중의 하나임. 사이킷런에서는 일반적으로 Pipeline 클래스를 이용하여 Poly변환과 선형회귀 학습/예측을 결합하여 다항회귀를 구현.
# Polynomial Regression과 overfitting / underfitting의 이해 ## Polynomial Regression 이해 #### PolynomialFeatures 클래스로 다항식 변환
- 1차 단항 피처들의 값이 [x1,x2] = [0 1]인 경우
2차 다항 피처들의 값은 [1,x1=0, x2=1, x1x2 = 0, x1^2 = 0, x2^2=1] 형태인 [1,0,1,0,0,1]로 변환
In [32]:
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)
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차 다항식 결정값을 구하는 함수 polynomial_func(X) 생성. 즉 회귀식은 결정값 y=1+2x_1+3x_1^2+4x_2^3¶
In [33]:
def polynomial_func(X):
y = 1+ 2*X[:,0] + 3*X[:,0]**2 + 4*X[:,1]**3
return y
X = np.arange(0,4).reshape(2,2)
print('일차 단항식 계수 feature : \n', X)
y = polynomial_func(X)
print('삼차 다항식 결정값:\n', y)
# 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)
일차 단항식 계수 feature : [[0 1] [2 3]] 삼차 다항식 결정값: [ 5 125] 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,)
3차 다항식 계수의 피처값과 3차 다항식 결정값으로 학습¶
사이킷런 파이프라인(Pipeline)을 이용하여 3차 다항회귀 학습¶
사이킷런의 Pipeline 객체는 Feature 엔지니어링 변환과 모델 학습/예측을 순차적으로 결합해줍니다.
In [34]:
from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import LinearRegression
from sklearn.pipeline import Pipeline
import numpy as np
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]
다항 회귀를 이용한 보스턴 주택가격 예측¶
In [35]:
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error , r2_score
from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import LinearRegression
from sklearn.pipeline import Pipeline
import numpy as np
# boston 데이타셋 로드
boston = load_boston()
# boston 데이타셋 DataFrame 변환
bostonDF = pd.DataFrame(boston.data , columns = boston.feature_names)
# boston dataset의 target array는 주택 가격임. 이를 PRICE 컬럼으로 DataFrame에 추가함.
bostonDF['PRICE'] = boston.target
print('Boston 데이타셋 크기 :',bostonDF.shape)
y_target = bostonDF['PRICE']
X_data = bostonDF.drop(['PRICE'],axis=1,inplace=False)
X_train , X_test , y_train , y_test = train_test_split(X_data , y_target ,test_size=0.3, random_state=156)
## Pipeline을 이용하여 PolynomialFeatures 변환과 LinearRegression 적용을 순차적으로 결합.
p_model = Pipeline([('poly', PolynomialFeatures(degree=3, include_bias=False)),
('linear', LinearRegression())])
p_model.fit(X_train, y_train)
y_preds = p_model.predict(X_test)
mse = mean_squared_error(y_test, y_preds)
rmse = np.sqrt(mse)
print('MSE : {0:.3f} , RMSE : {1:.3F}'.format(mse , rmse))
print('Variance score : {0:.3f}'.format(r2_score(y_test, y_preds)))
Boston 데이타셋 크기 : (506, 14) MSE : 79625.593 , RMSE : 282.180 Variance score : -1116.598
In [36]:
X_train_poly= PolynomialFeatures(degree=2, include_bias=False).fit_transform(X_train, y_train)
X_train_poly.shape, X_train.shape
Out[36]:
((354, 104), (354, 13))
In [37]:
import numpy as np
import matplotlib.pyplot as plt
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import cross_val_score
%matplotlib inline
# random 값으로 구성된 X값에 대해 Cosine 변환값을 반환.
def true_fun(X):
return np.cos(1.5 * np.pi * X)
# X는 0 부터 1까지 30개의 random 값을 순서대로 sampling 한 데이타 입니다.
np.random.seed(0)
n_samples = 30
X = np.sort(np.random.rand(n_samples))
# y 값은 cosine 기반의 true_fun() 에서 약간의 Noise 변동값을 더한 값입니다.
y = true_fun(X) + np.random.randn(n_samples) * 0.1
In [38]:
plt.scatter(X, y)
Out[38]:
<matplotlib.collections.PathCollection at 0x2b90ddef7c8>
In [39]:
plt.figure(figsize=(14, 5))
degrees = [1, 4, 15]
# 다항 회귀의 차수(degree)를 1, 4, 15로 각각 변화시키면서 비교합니다.
for i in range(len(degrees)):
ax = plt.subplot(1, len(degrees), i + 1)
plt.setp(ax, xticks=(), yticks=())
# 개별 degree별로 Polynomial 변환합니다.
polynomial_features = PolynomialFeatures(degree=degrees[i], include_bias=False)
linear_regression = LinearRegression()
pipeline = Pipeline([("polynomial_features", polynomial_features),
("linear_regression", linear_regression)])
pipeline.fit(X.reshape(-1, 1), y)
# 교차 검증으로 다항 회귀를 평가합니다.
scores = cross_val_score(pipeline, X.reshape(-1,1), y,scoring="neg_mean_squared_error", cv=10)
coefficients = pipeline.named_steps['linear_regression'].coef_
print('\nDegree {0} 회귀 계수는 {1} 입니다.'.format(degrees[i], np.round(coefficients),2))
print('Degree {0} MSE 는 {1:.2f} 입니다.'.format(degrees[i] , -1*np.mean(scores)))
# 0 부터 1까지 테스트 데이터 세트를 100개로 나눠 예측을 수행합니다.
# 테스트 데이터 세트에 회귀 예측을 수행하고 예측 곡선과 실제 곡선을 그려서 비교합니다.
X_test = np.linspace(0, 1, 100)
# 예측값 곡선
plt.plot(X_test, pipeline.predict(X_test[:, np.newaxis]), label="Model")
# 실제 값 곡선
plt.plot(X_test, true_fun(X_test), '--', label="True function")
plt.scatter(X, y, edgecolor='b', s=20, label="Samples")
plt.xlabel("x"); plt.ylabel("y"); plt.xlim((0, 1)); plt.ylim((-2, 2)); plt.legend(loc="best")
plt.title("Degree {}\nMSE = {:.2e}(+/- {:.2e})".format(degrees[i], -scores.mean(), scores.std()))
plt.show()
Degree 1 회귀 계수는 [-2.] 입니다. Degree 1 MSE 는 0.41 입니다. Degree 4 회귀 계수는 [ 0. -18. 24. -7.] 입니다. Degree 4 MSE 는 0.04 입니다. Degree 15 회귀 계수는 [-2.98300000e+03 1.03900000e+05 -1.87417100e+06 2.03717220e+07 -1.44873987e+08 7.09318780e+08 -2.47066977e+09 6.24564048e+09 -1.15677067e+10 1.56895696e+10 -1.54006776e+10 1.06457788e+10 -4.91379977e+09 1.35920330e+09 -1.70381654e+08] 입니다. Degree 15 MSE 는 182815433.48 입니다.
규제 선형 회귀 개요¶
- 회귀 모델은 적절히 데이터에 적합하면서도 회귀 계수가 기하급수적으로 커지는 것을 제어해야함.
- alpha는 학습 데이터 적합 정도와 회귀계수 값의 크기 제어를 수행하는 튜닝 파라미터 (람다말하는듯)
- 알파값을 작게하면 비용함수는 RSS를 줄이는데 집중하게 될 것이고
- 알파값을 크게 하면 회귀계수를 줄이는데 집중하게 된다. ### Rugularization : 알파값으로 패널티를 부여해 회귀 계수값의 크기를 감소시켜 과적합을 개선하는 방식
Ridge, Lasso, ElasticNet¶
- Ridge : L2규제. W의 제곱에대해 패널티를 부여하는 방식
- Lasso : L1규제. W의 절댓값에 대해 패널티를 부여하는 방식.
- ElasticNet : L1+L2. 피처가 많은 데이터 세트에 적용. L1규제로 피처의 개수를 줄임과 동시에 L2규제로 계수값 크기 조정
5-6. Regularized Linear Models – Ridge, Lasso¶
Regularized Linear Model - Ridge Regression (보스턴 주택가격 예측)¶
In [40]:
# 앞의 LinearRegression예제에서 분할한 feature 데이터 셋인 X_data과 Target 데이터 셋인 Y_target 데이터셋을 그대로 이용
from sklearn.linear_model import Ridge
from sklearn.model_selection import cross_val_score
# boston 데이타셋 로드
boston = load_boston()
# boston 데이타셋 DataFrame 변환
bostonDF = pd.DataFrame(boston.data , columns = boston.feature_names)
# boston dataset의 target array는 주택 가격임. 이를 PRICE 컬럼으로 DataFrame에 추가함.
bostonDF['PRICE'] = boston.target
print('Boston 데이타셋 크기 :',bostonDF.shape)
y_target = bostonDF['PRICE']
X_data = bostonDF.drop(['PRICE'],axis=1,inplace=False)
ridge = Ridge(alpha = 10) ##릿지 !!
neg_mse_scores = cross_val_score(ridge, X_data, y_target, scoring="neg_mean_squared_error", cv = 5)
rmse_scores = np.sqrt(-1 * neg_mse_scores)
avg_rmse = np.mean(rmse_scores)
print(' 5 folds 의 개별 Negative MSE scores: ', np.round(neg_mse_scores, 3))
print(' 5 folds 의 개별 RMSE scores : ', np.round(rmse_scores,3))
print(' 5 folds 의 평균 RMSE : {0:.3f} '.format(avg_rmse))
Boston 데이타셋 크기 : (506, 14) 5 folds 의 개별 Negative MSE scores: [-11.422 -24.294 -28.144 -74.599 -28.517] 5 folds 의 개별 RMSE scores : [3.38 4.929 5.305 8.637 5.34 ] 5 folds 의 평균 RMSE : 5.518
alpha값을 0 , 0.1 , 1 , 10 , 100 으로 변경하면서 RMSE 측정¶
In [41]:
# Ridge에 사용될 alpha 파라미터의 값들을 정의
alphas = [0 , 0.1 , 1 , 10 , 100]
# alphas list 값을 iteration하면서 alpha에 따른 평균 rmse 구함.
for alpha in alphas :
ridge = Ridge(alpha = alpha)
#cross_val_score를 이용하여 5 fold의 평균 RMSE 계산
neg_mse_scores = cross_val_score(ridge, X_data, y_target, scoring="neg_mean_squared_error", cv = 5)
avg_rmse = np.mean(np.sqrt(-1 * neg_mse_scores))
print('alpha {0} 일 때 5 folds 의 평균 RMSE : {1:.3f} '.format(alpha,avg_rmse))
alpha 0 일 때 5 folds 의 평균 RMSE : 5.829 alpha 0.1 일 때 5 folds 의 평균 RMSE : 5.788 alpha 1 일 때 5 folds 의 평균 RMSE : 5.653 alpha 10 일 때 5 folds 의 평균 RMSE : 5.518 alpha 100 일 때 5 folds 의 평균 RMSE : 5.330
각 alpha에 따른 회귀 계수 값을 시각화. 각 alpha값 별로 plt.subplots로 맷플롯립 축 생성¶
In [42]:
# 각 alpha에 따른 회귀 계수 값을 시각화하기 위해 5개의 열로 된 맷플롯립 축 생성
fig , axs = plt.subplots(figsize=(18,6) , nrows=1 , ncols=5)
# 각 alpha에 따른 회귀 계수 값을 데이터로 저장하기 위한 DataFrame 생성
coeff_df = pd.DataFrame()
# alphas 리스트 값을 차례로 입력해 회귀 계수 값 시각화 및 데이터 저장. pos는 axis의 위치 지정
for pos , alpha in enumerate(alphas) :
ridge = Ridge(alpha = alpha)
ridge.fit(X_data , y_target)
# alpha에 따른 피처별 회귀 계수를 Series로 변환하고 이를 DataFrame의 컬럼으로 추가.
coeff = pd.Series(data=ridge.coef_ , index=X_data.columns )
colname='alpha:'+str(alpha)
coeff_df[colname] = coeff
# 막대 그래프로 각 alpha 값에서의 회귀 계수를 시각화. 회귀 계수값이 높은 순으로 표현
coeff = coeff.sort_values(ascending=False)
axs[pos].set_title(colname)
axs[pos].set_xlim(-3,6)
sns.barplot(x=coeff.values , y=coeff.index, ax=axs[pos])
# for 문 바깥에서 맷플롯립의 show 호출 및 alpha에 따른 피처별 회귀 계수를 DataFrame으로 표시
plt.show()
alpha 값에 따른 컬럼별 회귀계수 출력¶
In [43]:
ridge_alphas = [0 , 0.1 , 1 , 10 , 100]
sort_column = 'alpha:'+str(ridge_alphas[0])
coeff_df.sort_values(by=sort_column, ascending=False)
Out[43]:
alpha:0 | alpha:0.1 | alpha:1 | alpha:10 | alpha:100 | |
---|---|---|---|---|---|
RM | 3.809865 | 3.818233 | 3.854000 | 3.702272 | 2.334536 |
CHAS | 2.686734 | 2.670019 | 2.552393 | 1.952021 | 0.638335 |
RAD | 0.306049 | 0.303515 | 0.290142 | 0.279596 | 0.315358 |
ZN | 0.046420 | 0.046572 | 0.047443 | 0.049579 | 0.054496 |
INDUS | 0.020559 | 0.015999 | -0.008805 | -0.042962 | -0.052826 |
B | 0.009312 | 0.009368 | 0.009673 | 0.010037 | 0.009393 |
AGE | 0.000692 | -0.000269 | -0.005415 | -0.010707 | 0.001212 |
TAX | -0.012335 | -0.012421 | -0.012912 | -0.013993 | -0.015856 |
CRIM | -0.108011 | -0.107474 | -0.104595 | -0.101435 | -0.102202 |
LSTAT | -0.524758 | -0.525966 | -0.533343 | -0.559366 | -0.660764 |
PTRATIO | -0.952747 | -0.940759 | -0.876074 | -0.797945 | -0.829218 |
DIS | -1.475567 | -1.459626 | -1.372654 | -1.248808 | -1.153390 |
NOX | -17.766611 | -16.684645 | -10.777015 | -2.371619 | -0.262847 |
라쏘 회귀¶
- L2규제가 회귀 계수의 크기를 감소시키는데 반해,
L1규제는 불필요한 회귀 계수를 급격하게 감소시켜 0으로 만들고 제거 - 그래서 feature selection의 특성을 가지고 있음.
In [44]:
from sklearn.linear_model import Lasso, ElasticNet
# alpha값에 따른 회귀 모델의 폴드 평균 RMSE를 출력하고 회귀 계수값들을 DataFrame으로 반환
def get_linear_reg_eval(model_name, params=None, X_data_n=None, y_target_n=None, verbose=True):
coeff_df = pd.DataFrame()
if verbose : print('####### ', model_name , '#######')
for param in params:
if model_name =='Ridge': model = Ridge(alpha=param)
elif model_name =='Lasso': model = Lasso(alpha=param)
elif model_name =='ElasticNet': model = ElasticNet(alpha=param, l1_ratio=0.7)
neg_mse_scores = cross_val_score(model, X_data_n,
y_target_n, scoring="neg_mean_squared_error", cv = 5)
avg_rmse = np.mean(np.sqrt(-1 * neg_mse_scores))
print('alpha {0}일 때 5 폴드 세트의 평균 RMSE: {1:.3f} '.format(param, avg_rmse))
# cross_val_score는 evaluation metric만 반환하므로 모델을 다시 학습하여 회귀 계수 추출
model.fit(X_data , y_target)
# alpha에 따른 피처별 회귀 계수를 Series로 변환하고 이를 DataFrame의 컬럼으로 추가.
coeff = pd.Series(data=model.coef_ , index=X_data.columns )
colname='alpha:'+str(param)
coeff_df[colname] = coeff
return coeff_df
# end of get_linear_regre_eval
In [45]:
# 라쏘에 사용될 alpha 파라미터의 값들을 정의하고 get_linear_reg_eval() 함수 호출
lasso_alphas = [ 0.07, 0.1, 0.5, 1, 3]
coeff_lasso_df =get_linear_reg_eval('Lasso', params=lasso_alphas, X_data_n=X_data, y_target_n=y_target)
####### Lasso ####### alpha 0.07일 때 5 폴드 세트의 평균 RMSE: 5.612 alpha 0.1일 때 5 폴드 세트의 평균 RMSE: 5.615 alpha 0.5일 때 5 폴드 세트의 평균 RMSE: 5.669 alpha 1일 때 5 폴드 세트의 평균 RMSE: 5.776 alpha 3일 때 5 폴드 세트의 평균 RMSE: 6.189
In [46]:
# 반환된 coeff_lasso_df를 첫번째 컬럼순으로 내림차순 정렬하여 회귀계수 DataFrame출력
sort_column = 'alpha:'+str(lasso_alphas[0])
coeff_lasso_df.sort_values(by=sort_column, ascending=False)
Out[46]:
alpha:0.07 | alpha:0.1 | alpha:0.5 | alpha:1 | alpha:3 | |
---|---|---|---|---|---|
RM | 3.789725 | 3.703202 | 2.498212 | 0.949811 | 0.000000 |
CHAS | 1.434343 | 0.955190 | 0.000000 | 0.000000 | 0.000000 |
RAD | 0.270936 | 0.274707 | 0.277451 | 0.264206 | 0.061864 |
ZN | 0.049059 | 0.049211 | 0.049544 | 0.049165 | 0.037231 |
B | 0.010248 | 0.010249 | 0.009469 | 0.008247 | 0.006510 |
NOX | -0.000000 | -0.000000 | -0.000000 | -0.000000 | 0.000000 |
AGE | -0.011706 | -0.010037 | 0.003604 | 0.020910 | 0.042495 |
TAX | -0.014290 | -0.014570 | -0.015442 | -0.015212 | -0.008602 |
INDUS | -0.042120 | -0.036619 | -0.005253 | -0.000000 | -0.000000 |
CRIM | -0.098193 | -0.097894 | -0.083289 | -0.063437 | -0.000000 |
LSTAT | -0.560431 | -0.568769 | -0.656290 | -0.761115 | -0.807679 |
PTRATIO | -0.765107 | -0.770654 | -0.758752 | -0.722966 | -0.265072 |
DIS | -1.176583 | -1.160538 | -0.936605 | -0.668790 | -0.000000 |
In [47]:
# 엘라스틱넷에 사용될 alpha 파라미터의 값들을 정의하고 get_linear_reg_eval() 함수 호출
# l1_ratio는 0.7로 고정
elastic_alphas = [ 0.07, 0.1, 0.5, 1, 3]
coeff_elastic_df =get_linear_reg_eval('ElasticNet', params=elastic_alphas,
X_data_n=X_data, y_target_n=y_target)
####### ElasticNet ####### alpha 0.07일 때 5 폴드 세트의 평균 RMSE: 5.542 alpha 0.1일 때 5 폴드 세트의 평균 RMSE: 5.526 alpha 0.5일 때 5 폴드 세트의 평균 RMSE: 5.467 alpha 1일 때 5 폴드 세트의 평균 RMSE: 5.597 alpha 3일 때 5 폴드 세트의 평균 RMSE: 6.068
In [48]:
# 반환된 coeff_elastic_df를 첫번째 컬럼순으로 내림차순 정렬하여 회귀계수 DataFrame출력
sort_column = 'alpha:'+str(elastic_alphas[0])
coeff_elastic_df.sort_values(by=sort_column, ascending=False)
Out[48]:
alpha:0.07 | alpha:0.1 | alpha:0.5 | alpha:1 | alpha:3 | |
---|---|---|---|---|---|
RM | 3.574162 | 3.414154 | 1.918419 | 0.938789 | 0.000000 |
CHAS | 1.330724 | 0.979706 | 0.000000 | 0.000000 | 0.000000 |
RAD | 0.278880 | 0.283443 | 0.300761 | 0.289299 | 0.146846 |
ZN | 0.050107 | 0.050617 | 0.052878 | 0.052136 | 0.038268 |
B | 0.010122 | 0.010067 | 0.009114 | 0.008320 | 0.007020 |
AGE | -0.010116 | -0.008276 | 0.007760 | 0.020348 | 0.043446 |
TAX | -0.014522 | -0.014814 | -0.016046 | -0.016218 | -0.011417 |
INDUS | -0.044855 | -0.042719 | -0.023252 | -0.000000 | -0.000000 |
CRIM | -0.099468 | -0.099213 | -0.089070 | -0.073577 | -0.019058 |
NOX | -0.175072 | -0.000000 | -0.000000 | -0.000000 | -0.000000 |
LSTAT | -0.574822 | -0.587702 | -0.693861 | -0.760457 | -0.800368 |
PTRATIO | -0.779498 | -0.784725 | -0.790969 | -0.738672 | -0.423065 |
DIS | -1.189438 | -1.173647 | -0.975902 | -0.725174 | -0.031208 |
In [49]:
print(y_target.shape)
plt.hist(y_target, bins=10)
(506,)
Out[49]:
(array([ 21., 55., 82., 154., 84., 41., 30., 8., 10., 21.]), array([ 5. , 9.5, 14. , 18.5, 23. , 27.5, 32. , 36.5, 41. , 45.5, 50. ]), <BarContainer object of 10 artists>)
In [50]:
from sklearn.preprocessing import StandardScaler, MinMaxScaler, PolynomialFeatures
# method는 표준 정규 분포 변환(Standard), 최대값/최소값 정규화(MinMax), 로그변환(Log) 결정
# p_degree는 다향식 특성을 추가할 때 적용. p_degree는 2이상 부여하지 않음.
def get_scaled_data(method='None', p_degree=None, input_data=None):
if method == 'Standard':
scaled_data = StandardScaler().fit_transform(input_data)
elif method == 'MinMax':
scaled_data = MinMaxScaler().fit_transform(input_data)
elif method == 'Log':
scaled_data = np.log1p(input_data)
else:
scaled_data = input_data
if p_degree != None:
scaled_data = PolynomialFeatures(degree=p_degree,
include_bias=False).fit_transform(scaled_data)
return scaled_data
In [51]:
# Ridge의 alpha값을 다르게 적용하고 다양한 데이터 변환방법에 따른 RMSE 추출.
alphas = [0.1, 1, 10, 100]
#변환 방법은 모두 6개, 원본 그대로, 표준정규분포, 표준정규분포+다항식 특성
# 최대/최소 정규화, 최대/최소 정규화+다항식 특성, 로그변환
scale_methods=[(None, None), ('Standard', None), ('Standard', 2),
('MinMax', None), ('MinMax', 2), ('Log', None)]
for scale_method in scale_methods:
X_data_scaled = get_scaled_data(method=scale_method[0], p_degree=scale_method[1],
input_data=X_data)
print('\n## 변환 유형:{0}, Polynomial Degree:{1}'.format(scale_method[0], scale_method[1]))
get_linear_reg_eval('Ridge', params=alphas, X_data_n=X_data_scaled,
y_target_n=y_target, verbose=False)
## 변환 유형:None, Polynomial Degree:None alpha 0.1일 때 5 폴드 세트의 평균 RMSE: 5.788 alpha 1일 때 5 폴드 세트의 평균 RMSE: 5.653 alpha 10일 때 5 폴드 세트의 평균 RMSE: 5.518 alpha 100일 때 5 폴드 세트의 평균 RMSE: 5.330 ## 변환 유형:Standard, Polynomial Degree:None alpha 0.1일 때 5 폴드 세트의 평균 RMSE: 5.826 alpha 1일 때 5 폴드 세트의 평균 RMSE: 5.803 alpha 10일 때 5 폴드 세트의 평균 RMSE: 5.637 alpha 100일 때 5 폴드 세트의 평균 RMSE: 5.421 ## 변환 유형:Standard, Polynomial Degree:2 alpha 0.1일 때 5 폴드 세트의 평균 RMSE: 8.827 alpha 1일 때 5 폴드 세트의 평균 RMSE: 6.871 alpha 10일 때 5 폴드 세트의 평균 RMSE: 5.485 alpha 100일 때 5 폴드 세트의 평균 RMSE: 4.634 ## 변환 유형:MinMax, Polynomial Degree:None alpha 0.1일 때 5 폴드 세트의 평균 RMSE: 5.764 alpha 1일 때 5 폴드 세트의 평균 RMSE: 5.465 alpha 10일 때 5 폴드 세트의 평균 RMSE: 5.754 alpha 100일 때 5 폴드 세트의 평균 RMSE: 7.635 ## 변환 유형:MinMax, Polynomial Degree:2 alpha 0.1일 때 5 폴드 세트의 평균 RMSE: 5.298 alpha 1일 때 5 폴드 세트의 평균 RMSE: 4.323 alpha 10일 때 5 폴드 세트의 평균 RMSE: 5.185 alpha 100일 때 5 폴드 세트의 평균 RMSE: 6.538 ## 변환 유형:Log, Polynomial Degree:None alpha 0.1일 때 5 폴드 세트의 평균 RMSE: 4.770 alpha 1일 때 5 폴드 세트의 평균 RMSE: 4.676 alpha 10일 때 5 폴드 세트의 평균 RMSE: 4.836 alpha 100일 때 5 폴드 세트의 평균 RMSE: 6.241
Polynomial은 값이 잘 나왔으나 과적합일 수 있음. 보통 로그변환만 하는 추세¶
로지스틱 회귀 개요¶
- 선형회귀 방식을 분류에 적용한 알고리즘.
- 시그모이드 함수 최적선을 찾고 이 시그모이드 함수의 반환값을 확률로 간주해 확률에 따라 분류를 결정.
- 주로 이진분류에 사용(다중 클래스 분류에도 적용가능)
- 로지스틱의 예측 값은 예측 확률을 의미하고 0.5이상은 1, 0.5이하면 0으로 예측.
단순 선형 회귀 y= w1x + w0¶
- 로지스틱 회귀는 0과 1을 예측하기에 단순 회귀식은 의미 없음(-inf ~ inf)
- 하지만 Odds(성공확률/ 실패확률)을 통해 선형 회귀식에 확률을 적용할 수 있음.
$ Odds(p) = p/(1-p) $¶
- 그러나 확률 p의 범위가 (0,1)이므로 선형 회귀의 반환값인 (-inf, inf)에 대응하기 위해
log 변환을 수행하고 이 값에 대한 선형회귀를 적용한다
$ Log(Odds(p)) = w1x + w0 $¶
해당 식을 데이터 값 x의 확률 p로 정리하면 아래와 같다.
$ p(x) = 1/(1+e^{-(w1x+w0)}) $¶
위 수식의 w를 최적화 하여 예측하는 것.
요새는 앙상블에 많이 치이는 느낌이지만 기념비적이다.
주요하이퍼 파라미터¶
- penalty : 규제(Regularization)의 유형을 설정. l2, l1 설정가능.
- C : 규제 강도를 조절하는 alpha값의 역수이다. C = 1/alpha.
그래서 C값이 작을수록 규제 강도가 크다.
로지스틱 회귀 실습¶
In [52]:
import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline
from sklearn.datasets import load_breast_cancer
from sklearn.linear_model import LogisticRegression
cancer = load_breast_cancer()
In [53]:
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split
# StandardScaler( )로 평균이 0, 분산 1로 데이터 분포도 변환
scaler = StandardScaler()
data_scaled = scaler.fit_transform(cancer.data)
X_train , X_test, y_train , y_test = train_test_split(data_scaled, cancer.target, test_size=0.3, random_state=0)
In [54]:
from sklearn.metrics import accuracy_score, roc_auc_score
# 로지스틱 회귀를 이용하여 학습 및 예측 수행.
lr_clf = LogisticRegression()
lr_clf.fit(X_train, y_train)
lr_preds = lr_clf.predict(X_test)
# accuracy와 roc_auc 측정
print('accuracy: {:0.3f}'.format(accuracy_score(y_test, lr_preds)))
print('roc_auc: {:0.3f}'.format(roc_auc_score(y_test , lr_preds)))
accuracy: 0.977 roc_auc: 0.972
In [ ]:
from sklearn.model_selection import GridSearchCV
params={'penalty':['l2', 'l1'],
'C':[0.01, 0.1, 1, 1, 5, 10]}
grid_clf = GridSearchCV(lr_clf, param_grid=params, scoring='accuracy', cv=3 )
grid_clf.fit(data_scaled, cancer.target)
print('최적 하이퍼 파라미터:{0}, 최적 평균 정확도:{1:.3f}'.format(grid_clf.best_params_,
grid_clf.best_score_))
In [56]:
from sklearn.datasets import load_boston
from sklearn.model_selection import cross_val_score
from sklearn.ensemble import RandomForestRegressor
import pandas as pd
import numpy as np
# 보스턴 데이터 세트 로드
boston = load_boston()
bostonDF = pd.DataFrame(boston.data, columns = boston.feature_names)
bostonDF['PRICE'] = boston.target
y_target = bostonDF['PRICE']
X_data = bostonDF.drop(['PRICE'], axis=1,inplace=False)
rf = RandomForestRegressor(random_state=0, n_estimators=1000)
neg_mse_scores = cross_val_score(rf, X_data, y_target, scoring="neg_mean_squared_error", cv = 5)
rmse_scores = np.sqrt(-1 * neg_mse_scores)
avg_rmse = np.mean(rmse_scores)
print(' 5 교차 검증의 개별 Negative MSE scores: ', np.round(neg_mse_scores, 2))
print(' 5 교차 검증의 개별 RMSE scores : ', np.round(rmse_scores, 2))
print(' 5 교차 검증의 평균 RMSE : {0:.3f} '.format(avg_rmse))
5 교차 검증의 개별 Negative MSE scores: [ -7.88 -13.14 -20.57 -46.23 -18.88] 5 교차 검증의 개별 RMSE scores : [2.81 3.63 4.54 6.8 4.34] 5 교차 검증의 평균 RMSE : 4.423
In [57]:
def get_model_cv_prediction(model, X_data, y_target):
neg_mse_scores = cross_val_score(model, X_data, y_target, scoring="neg_mean_squared_error", cv = 5)
rmse_scores = np.sqrt(-1 * neg_mse_scores)
avg_rmse = np.mean(rmse_scores)
print('##### ',model.__class__.__name__ , ' #####')
print(' 5 교차 검증의 평균 RMSE : {0:.3f} '.format(avg_rmse))
사이킷런의 여러 회귀 트리 클래스를 이용하여 회귀 예측
In [58]:
from sklearn.tree import DecisionTreeRegressor
from sklearn.ensemble import GradientBoostingRegressor
from xgboost import XGBRegressor
from lightgbm import LGBMRegressor
dt_reg = DecisionTreeRegressor(random_state=0, max_depth=4)
rf_reg = RandomForestRegressor(random_state=0, n_estimators=1000)
gb_reg = GradientBoostingRegressor(random_state=0, n_estimators=1000)
xgb_reg = XGBRegressor(n_estimators=1000)
lgb_reg = LGBMRegressor(n_estimators=1000)
# 트리 기반의 회귀 모델을 반복하면서 평가 수행
models = [dt_reg, rf_reg, gb_reg, xgb_reg, lgb_reg]
for model in models:
get_model_cv_prediction(model, X_data, y_target)
##### DecisionTreeRegressor ##### 5 교차 검증의 평균 RMSE : 5.978 ##### RandomForestRegressor ##### 5 교차 검증의 평균 RMSE : 4.423 ##### GradientBoostingRegressor ##### 5 교차 검증의 평균 RMSE : 4.269 ##### XGBRegressor ##### 5 교차 검증의 평균 RMSE : 4.251 ##### LGBMRegressor ##### 5 교차 검증의 평균 RMSE : 4.646
회귀 트리는 선형 회귀의 회귀 계수 대신, 피처 중요도로 피처의 상대적 중요도를 알 수 있습니다
In [59]:
import seaborn as sns
%matplotlib inline
rf_reg = RandomForestRegressor(n_estimators=1000)
# 앞 예제에서 만들어진 X_data, y_target 데이터 셋을 적용하여 학습합니다.
rf_reg.fit(X_data, y_target)
feature_series = pd.Series(data=rf_reg.feature_importances_, index=X_data.columns )
feature_series = feature_series.sort_values(ascending=False)
sns.barplot(x= feature_series, y=feature_series.index)
Out[59]:
<AxesSubplot:>
오버피팅을 시각화 하기 위해 한개의 피처 RM과 타겟값 PRICE기반으로 회귀 예측 수행
In [60]:
import matplotlib.pyplot as plt
%matplotlib inline
bostonDF_sample = bostonDF[['RM','PRICE']]
bostonDF_sample = bostonDF_sample.sample(n=100,random_state=0)
print(bostonDF_sample.shape)
plt.figure()
plt.scatter(bostonDF_sample.RM , bostonDF_sample.PRICE,c="darkorange")
(100, 2)
Out[60]:
<matplotlib.collections.PathCollection at 0x2b90dc8cec8>
In [61]:
import numpy as np
from sklearn.linear_model import LinearRegression
# 선형 회귀와 결정 트리 기반의 Regressor 생성. DecisionTreeRegressor의 max_depth는 각각 2, 7
lr_reg = LinearRegression()
rf_reg2 = DecisionTreeRegressor(max_depth=2)
rf_reg7 = DecisionTreeRegressor(max_depth=7)
# 실제 예측을 적용할 테스트용 데이터 셋을 4.5 ~ 8.5 까지 100개 데이터 셋 생성.
X_test = np.arange(4.5, 8.5, 0.04).reshape(-1, 1)
# 보스턴 주택가격 데이터에서 시각화를 위해 피처는 RM만, 그리고 결정 데이터인 PRICE 추출
X_feature = bostonDF_sample['RM'].values.reshape(-1,1)
y_target = bostonDF_sample['PRICE'].values.reshape(-1,1)
# 학습과 예측 수행.
lr_reg.fit(X_feature, y_target)
rf_reg2.fit(X_feature, y_target)
rf_reg7.fit(X_feature, y_target)
pred_lr = lr_reg.predict(X_test)
pred_rf2 = rf_reg2.predict(X_test)
pred_rf7 = rf_reg7.predict(X_test)
In [62]:
fig , (ax1, ax2, ax3) = plt.subplots(figsize=(14,4), ncols=3)
# X축값을 4.5 ~ 8.5로 변환하며 입력했을 때, 선형 회귀와 결정 트리 회귀 예측 선 시각화
# 선형 회귀로 학습된 모델 회귀 예측선
ax1.set_title('Linear Regression')
ax1.scatter(bostonDF_sample.RM, bostonDF_sample.PRICE, c="darkorange")
ax1.plot(X_test, pred_lr,label="linear", linewidth=2 )
# DecisionTreeRegressor의 max_depth를 2로 했을 때 회귀 예측선
ax2.set_title('Decision Tree Regression: \n max_depth=2')
ax2.scatter(bostonDF_sample.RM, bostonDF_sample.PRICE, c="darkorange")
ax2.plot(X_test, pred_rf2, label="max_depth:3", linewidth=2 )
# DecisionTreeRegressor의 max_depth를 7로 했을 때 회귀 예측선
ax3.set_title('Decision Tree Regression: \n max_depth=7')
ax3.scatter(bostonDF_sample.RM, bostonDF_sample.PRICE, c="darkorange")
ax3.plot(X_test, pred_rf7, label="max_depth:7", linewidth=2)
Out[62]:
[<matplotlib.lines.Line2D at 0x2b90dc75088>]
이건 나중에 질문해보자.¶
반응형
'인공지능 > Merchine_Learning' 카테고리의 다른 글
[파이썬 머신러닝 완벽가이드] 협업필터링 (0) | 2020.12.21 |
---|---|
[파이썬 머신러닝 완벽가이드] 추천시스템 - 콘텐츠기반 (1) | 2020.12.21 |
[파이썬 머신러닝 완벽가이드] Ch7 Clustering 내용 (0) | 2020.11.23 |
[파이썬 머신러닝 완벽가이드] Ch4. Practice 산탄데르 고객 만족 예측 (0) | 2020.11.14 |
[파이썬 머신러닝 완벽가이드] Ch4. Classification (0) | 2020.11.10 |