728x90
1. Model Extension (모델 확장)
기본적인 모델들은 다양한 방식으로 확장이 가능
- 우리가 사용할 수 있는 모델을 풍부하게 만듦
- 일반적으로 모델의 복잡성을 줄이는(Overfitting의 가능성을 줄이는) 방향으로 확장
Feature Selection (입력 변수 선택)
- 활용가능한 입력 변수 중 일부를 골라서 사용
- 모든 모델에 적용 가능
- 복잡성을 줄이는 역할
Dimension Reduction (차원 축소)
- 입력 변수의 차원을 더 낮은 차원으로 압축하여 사용
- 연속형 입력 변수에 대하여 사용 가능
- 복잡성을 줄이는 역할
Regularization (규제화)
- 모델 파라미터의 범위를 제한
- 모델 파라미터가 존재하는 모수적 모델에 적용 가능
- 복잡성을 줄이는 역할
Regularization Expression
$Loss(\theta, \lambda | X, Y) = Error(\theta | X, Y) + \lambda Penalty(\theta)$
- Error Function: Squared_Error, Cross_Entropy, Logistic, Hinge Loss 등
- Penalty: $L_{0}, L_{1}, L_{2}, L_{infinite}$
- $\theta$는 Model Parameter로 훈련 과정에서 최적화됨
- $\lambda$는 Hyper Parameter(Tuning Parameter)로 사용자가 최적의 성능을 얻기 위해 결정
2. Regularized Linear Regression (규제 선형 회귀) 개요
규제 선형 회귀
- 회귀 모델은 적절히 데이터에 적합하면서도 회귀 계수가 기하급수적으로 커지는 것을 제어할 수 있어야 함
- 학습 데이터 잔차 오류 최소화 (RSS(W) 최소화) + 회귀계수 크기 제어 -> 최적 모델을 위한 Cost 함수 구성요소
- 비용함수 목표 = $Min(RSS(W) + alpha * \left\| W \right\|_{2}^{2})$
- $\alpha$: 학습 데이터 적합 정도와 회귀 계수 값의 크기 제어를 수행하는 튜닝 파라미터
- $\alpha$가 커질수록 규제의 정도가 심해진다
- 규제는 Overfitting을 방지하는 것이 목적이므로, $\alpha$가 커질수록 Underfitting의 가능성이 높아진다
- $\alpha$: 학습 데이터 적합 정도와 회귀 계수 값의 크기 제어를 수행하는 튜닝 파라미터
- $\alpha$가 0으로 갈 경우: Model Parameter를 자유롭게 결정 가능
- Error Function의 최소화
- 학습 데이터 적합을 더 개선할 수 있음 (Train Loss를 줄임)
- 제약이 적음 -> 모델이 복잡해짐 -> Overfitting
- $\alpha$가 무한대로 갈 경우: 비용함수를 최소화하기 위해서는 Model Parameter를 0으로 보내야 함
- Model parameter $\theta$ 감소
- Model Parameter의 값을 작게 해 Overfitting을 방지할 수 있음
- 제약이 강함 -> 모델이 단순해짐 -> Underfitting
규제 선형 회귀의 유형
- L2 Regularization: $Penalty(\theta) = \theta_{1}^{2} + \theta_{2}^{2} + \cdots + \theta_{p}^{2} $
- Model Parameter의 제곱에 대해 penalty를 부여하는 방식
- 상관관계가 높은 변수들이 존재할 때 효과적인 규제 방법
- 두 변수 중 하나의 변수의 회귀 계수 값을 크게 감소
- 규제가 강해질 수록 각 Model Parameter가 0으로 수렴 (0이 되지는 않음)
- Ridge: L2 Regularization + Regression
- L1 Regularization: $Penalty(\theta) = \left|\theta_{1} \right| + \left|\theta_{2} \right| + \cdots + \left|\theta_{p} \right| $
- Model Parameter의 절댓값에 대해 penalty를 부여하는 방식
- 중요한 변수만 선택하고 나머지는 제거할 때 유용한 규제 방법
- 두 변수 중 더 중요한 변수만 남기고 나머지 변수의 회귀 계수 값을 0으로 만듦
- 규제가 강해질 수록 각 Model Parameter가 0으로 접근하다가 0이 된다 (Feature Selection = 변수 선택이 가능)
- Lasso: L1 Regularization + Regression
- ElasticNet: $Penalty(\theta) = \alpha(\lambda \sum_{i=1}^{p} \left| \theta_{i} \right| + \frac {1} {2} (1-\lambda) \sum_{i=1}^{p} \theta_{i}^{2})$
- L2, L1 규제를 함께 결합한 모델
- 주로 Feature가 많은 데이터 세트에서 적용
- L1 규제로 Feature selection을 통해 Feature의 개수를 줄임과 동시에 L2 규제로 계수 값을 크기를 조정
3. Ridge Regression (릿지 회귀)
릿지 선형 회귀
- L2 Regularization: $Penalty(\theta) = \theta_{1}^{2} + \theta_{2}^{2} + \cdots + \theta_{p}^{2} $
- Ridge: L2 Regularization + Regression
- 릿지 회귀는 $\alpha$값을 이용하여 회귀 계수의 크기를 조정
- $\alpha$값이 크면 회귀 계수 값이 작아지고, $\alpha$값이 작으면 회귀 계수 값이 커짐
- Scikit-Learn은 Ridge Regression을 위해 Ridge 클래스를 제공함
Regularized Linear Model - Ridge Regression
# 앞의 LinearRegression예제에서 분할한 feature 데이터 셋인 X_data과 Target 데이터 셋인 Y_target 데이터셋을 그대로 이용
from sklearn.linear_model import Ridge
from sklearn.model_selection import cross_val_score
# boston 데이타셋 로드
bostonDF = pd.read_csv(filepath_or_buffer="./Boston.csv", index_col=0)
# boston dataset의 target array는 주택 가격임. 이를 PRICE 컬럼으로 DataFrame에 추가함.
bostonDF.rename(columns={"medv": "PRICE"}, inplace=True)
bostonDF.columns = [col.upper() for col in bostonDF.columns]
y_target = bostonDF["PRICE"]
X_data = bostonDF.drop(["PRICE"], axis=1)
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))
# 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 측정
# 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 = cross_val_score(
ridge, X_data, y_target, scoring="neg_mean_squared_error", cv=5
)
rmse = np.mean(np.sqrt((-1) * neg_mse))
print(f"alpha {alpha}일 때 5 folds 의 평균 RMSE : {rmse:.3f}")
# 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로 matplotlib축 생성
coeff = pd.Series(data=ridge.coef_ , index=X_data.columns )
coeff.sort_values(ascending=False, inplace=True)
coeff
# RM 2.334536
# CHAS 0.638335
# RAD 0.315358
# ZN 0.054496
# BLACK 0.009393
# AGE 0.001212
# TAX -0.015856
# INDUS -0.052826
# CRIM -0.102202
# NOX -0.262847
# LSTAT -0.660764
# PTRATIO -0.829218
# DIS -1.153390
# dtype: float64
# 각 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$값에 따른 column별 회귀계수 출력
- $\alpha = 0$일 때의 column을 기준으로 전체 DataFrame을 내림차순 정렬
ridge_alphas = [0 , 0.1 , 1 , 10 , 100]
sort_column = 'alpha:'+str(ridge_alphas[0])
coeff_df.sort_values(by=sort_column, ascending=False)
4. Lasso Regression (라쏘 회귀)
라쏘 선형 회귀
- L1 Regularization: $Penalty(\theta) = \left|\theta_{1} \right| + \left|\theta_{2} \right| + \cdots + \left|\theta_{p} \right| $
- Lasso: L1 Regularization + Regression
- Model Parameter의 절댓값에 페널티를 부여하는 L1 regularization을 선형 회귀에 적용한 것이 Lasso 회귀
- L1 regularization: $alpha * \left\| W \right\|_{1} $를 의미하며
- Lasso 회귀 비용함수의 목표는 $Min(RSS(W) + \alpha * \left\| W \right\|_{2}^{2})$ 을 최소화하는 W(model parameter)를 찾는 것
L2 규제가 회귀 계수의 크기를 감소시키는데 반해,
L1 규제는 불필요한 회귀 계수를 급격하게 감소시켜 0으로 만들고 제거함
이러한 측면에서 L1 규제는 적절한 feature만 회귀에 포함시키는 feature selection의 특성을 가지고 있음
- Scikit-Learn은 Lasso 클래스를 통해 Lasso 회귀를 구현함
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, return_coeff=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_n , y_target_n)
if return_coeff:
# alpha에 따른 피처별 회귀 계수를 Series로 변환하고 이를 DataFrame의 컬럼으로 추가.
coeff = pd.Series(data=model.coef_ , index=X_data_n.columns )
colname='alpha:'+str(param)
coeff_df[colname] = coeff
return coeff_df
# end of get_linear_regre_eval
# 라쏘에 사용될 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
- $\alpha$값이 높아질수록 Feature Selection의 영향이 커진다
# 반환된 coeff_lasso_df를 첫번째 컬럼순으로 내림차순 정렬하여 회귀계수 DataFrame출력
sort_column = 'alpha:'+str(lasso_alphas[0])
coeff_lasso_df.sort_values(by=sort_column, ascending=False)
5. Elastic Net (엘라스틱넷 회귀)
엘라스틱넷 회귀
- ElasticNet: $Penalty(\theta) = \alpha(\lambda \sum_{i=1}^{p} \left| \theta_{i} \right| + \frac {1} {2} (1-\lambda) \sum_{i=1}^{p} \theta_{i}^{2})$
- L1, L2 규제를 함께 결합한 모델
- 엘라스틱넷 회귀 비용함수의 목표는 $Min(RSS(W) + \alpha_{2} * \left\| W \right\|_{2}^{2} + \alpha_{1} * \left\| W \right\|_{1})$ 을 최소화하는 W(model parameter)를 찾는 것
엘라스틱넷은 Lasso 회귀가 서로 상관관계가 높은 feature들의 경우에 이들 중에서 중요 feature들만 선택하고 다른 feature들은 모두 회귀계수를 0으로 만드는 성향이 강함
특히 이러한 성향으로 인해 $\alpha$값에 따라 회귀 계수의 값이 급격히 변동할 수도 있는데, Elastic Net 회귀는 이를 완화하기 위해 L2 규제를 Lasso 회귀에 추가한 것
Elastic Net @ Scikit - Learn
$Min(RSS(W) + \alpha_{2} * \left\| W \right\|_{2}^{2} + \alpha_{1} * \left\| W \right\|_{1})$
- ElasticNet Class 주요 생성 parameter: alpha, l1_ratio
- ElasticNet alpha parameter
- alpha = $\alpha_{1} + \alpha_{2}$
- L1, L2 규제의 alpha 값들의 합
- ElasticNet l1_ratio parameter
- l1_ratio = $\frac {\alpha_{1}} {\alpha_{1} + \alpha_{2}}$
- L1, L2 규제의 alpha 값들의 비율
- l1_ratio = 0이면 $\alpha_{1}$가 0이므로 L2 규제와 동일
- l1_ratio = 1이면 $\alpha_{2}$가 0이므로 L1 규제와 동일
- 0 < l1_ratio < 1 이며, L1과 L2 규제를 적절히 적용
# 엘라스틱넷에 사용될 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
# 반환된 coeff_elastic_df를 첫번째 컬럼순으로 내림차순 정렬하여 회귀계수 DataFrame출력
sort_column = 'alpha:'+str(elastic_alphas[0])
coeff_elastic_df.sort_values(by=sort_column, ascending=False)
6. Linear Regression 모델을 위한 데이터 변환
선형 회귀 모델의 가정
선형 회귀 모델은 일반적으로 Feature와 Target value간에 선형의 관계가 있다고 가정하고 이러한 최적의 선형 함수를 찾아내 결과 값을 예측한다
선형 회귀 모델은 Feature값과 Target value의 분포가 정규 형태인 것을 선호함
선형 회귀를 위한 데이터 변환 방법
- Target Value 변환
- 타겟값은 정규 분포 선호
- Skew 되어 있을 경우 주로 로그 변환을 적용
- Feature값 변환 - Scaling
- Feature들에 대한 균일한 Scaling/Normalization 적용
- StandardSaclar를 이용하여 표준 정규 분포 형태 변환 또는 MinMaxScalar를 이용하여 최소값 0, 최대값 1로 정규화
- Feature값 변환 - 다항 특성 변환
- Scaling/Normalization 수행한 데이터 세트에 다시 다항 특성(Polynomial Feature)를 적용하여 변환
- Variance가 높아서 Overfitting의 가능성이 존재 -> 최근에는 많이 사용X
- Feature값 변환 - 로그 변환
- 왜도(Skewness)가 심한 중요 Feature들에 대해서 로그 변환을 적용. 일반적으로 많이 사용됨
Target Value를 로그 변환(log1p)했을 경우 예측값(y_preds)이나 실제값(y_test)은 다시 scale 변환(expm1)해줘야 함
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
return_coeff=False
- Scaling에서 transform()시 scale 변환된 데이터 셋이 numpy ndarray로 반환되어 이를 DataFrame으로 변환
- X_data_scaled 가 ndarray이므로 DataFrame로 변환해줘야 함 or return_coeff=False 로 처리
# 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, return_coeff=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
728x90