특성 공학 (Feature Engineering)

1. 정의

  • 모델 정확도를 높이기 위해 주어진 데이터를 예측 모델의 문제를 잘 표현할 수 있는 features로 변형시키는 과정
  • 머신러닝 알고리즘을 작동하기 위해 데이터의 도메인 지식을 활용해 feature를 만드는 과정
  • features -> more flexibility, simpler models, and better results
  • tech) Imputations, Outliers, Binning, One-Hot Encoding, Scaling


2. 예시

from sklearn.linear_model import LinearRegression

lr = LinearRegression()
lr.fit(train_poly, train_target)
print(lr.score(train_poly, train_target))
# 0.9903...

print(lr.score(test_poly, test_target))
# 0.9714...

# 특성 개수 늘리기
poly = PolynomialFeatures(degree=5, include_bias=False)
poly.fit(train_input)
train_poly = poly.transform(train_input)
test_poly = poly.transform(test_input)

print(train_poly.shape)
# (42, 55)

lr.fit(train_poly, train_target)
print(lr.score(train_poly, train_target))
# 0.9999...

print(lr.score(test_poly, test_target))
# -144.4057...
  • 다중회귀모델의 훈련은 선형회귀모델 훈련 방식과 동일
  • 단, 여러 개의 특성을 사용하여 회귀를 수행한다는 차이가 있음


  • PolynomialFeatures()
    • 특성의 개수를 늘리면 강력한 선형 모델이 됨


  • 다중 회귀 모델을 훈련시킨 test set에 대한 score
    • test set에 대한 score가 큰 음수
    • train set에 과대적합되어 test 예측 성능이 떨어지는 현상

    스크린샷 2023-04-01 오후 11 09 48


규제

1. 개념

  • 사용하는 이유
    • 모델이 지나치게 복잡하여 주어진 데이터가 아닌 새로운 데이터에 대해 정확한 예측을 하지 못하는 과적합(overfitting) 현상 해결
  • 적용 방법
    • 모델의 각 변수의 weight(가중치, 회귀계수)의 크기가 작게끔 모델을 설계하여 모델의 복잡도를 줄이는 방식
      -> 가중치에 대한 제약조건(penalty) 추가
          = 계수의 크기 제한
  • main concept
    • perfect fit을 포기함으로써(training accuracy를 낮춤으로써)
    • potential fit을 증가시키고자(testing accuracy를 높이고자) 하는 것


  • Regularized Linear Regression Method(정규화 선형회귀)
    • 종류에 따라 가중치에 제약을 거는 방법이 다름

Ridge Regression L2 Regularization penalizes (weight)²
Lasso Regression L1 Regularization penalizes |weight|
Elastic Net Regression Combination of L1 & L2 Regularization


2. 선형회귀와 규제

  • 선형회귀모델은 bias = 0인 대신, variance가 높음
  • 즉, 정답 근처에서 정확도가 낮게 예측
    스크린샷 2023-04-01 오후 11 31 02
  • 정규화를 적용하면 bias가 높아지지만, 소수의 데이터에 영향을 받지 않도록 variance를 크게 줄여 결과적으로 오차(error)를 감소시킬 수 있음


  • 선형모델의 예측력/설명력을 높이기 위해 정규화 실시


Rigde Regression 릿지 회귀

1. 정의

  • 독립 변수의 상관 관계가 높은 경우에 다중 회귀 모델의 계수를 추정하는 방법
  • 다중선형회귀모델은 특성이 많아질수록 훈련 데이터에 과적합되기 쉬움
  • 이때 회귀선의 기울기는 단 하나의 특이값에도 크게 변할 수 있음
  • L2 Regularizaton L2 Norm에 기반해서 회귀계수의 크기에 패널티를 부여하는 회귀


2. L2 Regularization

  • 제약조건: 가중치들의 제곱합을 최소화하는 것

스크린샷 2023-04-01 오후 11 35 54

  • hyper parameters $\gamma, \alpha$
    • lambda, alpha, regularization parameter, penality term


  • regularization for simplicity
  • L2 fit is more precise
  • 미분 가능, Gradient Descent 최적화 가능
  • 파라미터의 크기가 작은 것보다 큰 것을 더 빠른 속도로 줄여줌
  • 제약에 따라 계수들이 shrinkage하여 모델의 변동이 크지 않음


3. Ridge vs Lasso

  • Ridge는 가중치 계수를 한꺼번에 축소시키며, 0이 될 수 없음
  • Lasso는 일부 가중치 계수가 먼저 0으로 수렴하는 특성이 있음
    스크린샷 2023-04-02 오전 12 26 20


4. Hyperparameter alpha

규제 효과 원리

  • $RidgeMSE = \frac{1}{N} \sum_{i=1}^{N}(y_i - \hat{y_i})^2 + \alpha \sum_{i=1}^{p} w_i^2$

  • $Cost = \sum_{i=0}^{N}(y_i - \sum_{j=0}^{M}x_{ij}W_j)^2 + \lambda \sum_{j=0}^{M} W_j^2$

스크린샷 2023-04-02 오전 12 37 13


  • $\alpha, \lambda$ : 사용자가 지정하는 매개변수
    • penalty의 크기를 결정하는 변수로, 규제의 강도 조절
  • $\alpha, \lambda$ 가 크면 규제의 효과가 커짐
    • 계수를 0에 가깝게 만들어 train set의 score는 낮아지지만, 일반화는 쉬워짐(underfitting)
    • Flexibility 감소, Variance 감소, Bias 증가
  • $\alpha, \lambda$ 가 작으면 규제의 효과가 작아짐
    • 계수에 대한 제약이 풀리면서 Linear Regression으로 만든 모델과 거의 같아짐(overfitting)


ex1) Alpha 값 찾기 - plot(R²)

from sklearn.linear_model import Ridge

ridge = Ridge()
ridge.fit(train_scaled, train_target)
print(ridge.score(train_scaled, train_target))
# 0.9896...

print(ridge.score(test_scaled, test_target))
# 0.9706...

import matplotlib.pyplot as plt

train_score = []
test_score = []

alpha_list = [0.001, 0.01, 0.1, 1, 10, 100]
for alpha in alpha_list:
    # ridge model 
    ridge = Ridge(alpha = alpha)
    # train
    ridge.fit(train_scaled, train_target)
    # score
    train_score.append(ridge.score(train_scaled, train_target))
    test_score.append(ridge.score(test_scaled, test_target))

plt.plot(np.log10(alpha_list), train_score)
plt.plot(np.log10(alpha_list), test_score)
plt.xlabel('alpha')
plt.ylabel('R^2')
plt.show()

스크린샷 2023-04-02 오전 2 29 04


ex2) Alpha 값 찾기 - Cross Validation (Ridge CV)

  • 교차 검증 CV
    • 주어진 데이터를 동일한 크기의 지정된 k개로 여러 등분한 후, 각각에 대해 k번씩 자체적으로 검증해 정확도를 올리는 방법
    • 모델이 한 가지 경우에만 잘맞는 과적합을 줄이고자 실시하는 방법
    • 데이터가 부족해 교차검증이 힘든 경우에도 이를 통해 자체적인 교차 검증을 할 수 있음


from sklear.linear_model import RidgeCV
from sklearn.metrics import mean_absolute_error, r2_score

alphas = [0, 0.001, 0.01, 0.1, 1]

# RidgeCV는 alpha로 넣고자 하는 값들을 리스트로 전달하면 내부적으로 최적의 alpha값 찾아냄
ridgecv = RidgeCV(alphas=alphas, normalize=True, cv=5)

# cv -> 가장 점수가 높은 모델 채택
ridgecv.fit(x_train, y_train)
y_pred = ridgecv.predict(x_test)

mae = mean_absolute_error(y_test, y_pred)
r2 = r2_score(y_test, y_pred)
print(f'Test MAE: ${mae:, .0f}')
print(f'R2 Score: ${r2:, .4f}\n')

# 최종 결정된 alpha 값
print(f'alpha: {ridgecv.alpha_}')  
# 최종 alpha에서의 점수 (R² of self.predict(X) wrt. y.)
print(f'cv best score: {ridgecv.best_score_}') 

Test MAE: 255,264
R2 Score: 0.5878

alpha: 0.001
cv best score: 0.5706…


5. 한계점/단점 및 보완방법

  • 예측의 측면에서는 문제가 안되지만, 해석의 측면에서 약점을 가짐
  • 패널티 항 ${W_j^2}$ 이 0으로 가까워지면 $W_j$ 은 0으로 수렴하는데, 이 때 0의 값을 가지지는 못함
  • 따라서, 실제로 $W_j$ 가 0에 가까워지긴 하지만, 회귀 모형에서 없어지진 않음
  • 따라서, Ridge Regression은 변수 선택 방법으로는 사용되지 못함

<b#r>

  • 몇몇 변수를 아예 0으로 보내 제외시킨다는 점에서 Lasso가 Ridge보다 해석력이 좋음


Lasso Regression 라쏘 회귀

1. 정의

  • shirinkage를 사용하는 선형회귀의 일종
  • shirinkage: 데이터값이 평균과 같은 중심값을 향해 축소되는 경우
  • Lasso Regression을 통해 overfitting을 피할 수 있음
    • training data와의 차이인 bias를 조금 늘리는 대신, test data와의 차이인 variance를 줄일 수 있음 -> 과대적합 피함

스크린샷 2023-04-02 오전 2 53 20


2. 사용하는 경우

  • overfitting이 일어날 때
  • variable selection / parameter elimination과 같은 model selection의 특정 부분들을 자동화시키고 싶을 때
  • 높은 수준의 다중공선성(Multicollinearity)을 보이는 데이터에 낮은 성능을 보일 때
    • 다중공선성: 독립변수(x)들 간에 상관관계가 있는 경우 다중공선성이 있다고 함


3. 다중공선성 확인

1) VIF

  • VIF: Variance Inflation Factor(분산 팽창 지수)
  • 보통 VIF가 10이 넘으면 다중공선성이 있다고 판단


from statsmodels.stats.outliers_influence import variance_inflation_factor

vif = pd.DataFrame()
vif['VIF Factor'] = [variance_inflations_factor(X.values, i) for i in range(X.shape[1])]
vif['features'] = X.columns
vif = vif.sort_values('VIF Factor', ascending=False).reset_index(drop=True)
vif

스크린샷 2023-04-02 오전 2 57 51

  • 세 변수 모두 VIF 값이 매우 높은 것으로 보아 다중공선성이 있다고 판단됨


2) scatter plot

  • seaborn 패키지로 heatmap 그려서 산점도 확인


X = pd.Dataframe(pearch_full, columns = ['length', 'height', 'width'])

from matplotlib import pyplot as plt
import seaborn as sns

sns.heatmap(X.corr(), annot=True)
plt.show()

스크린샷 2023-04-02 오전 3 09 29

  • length, height, width 세 변수 모두 상관관계가 매우 높음을 알 수 있음


4. L1 Regularization

  • $Cost = \sum_{i=0}^{N}(y_i - \sum_{j=0}^{M}x_{ij}W_j)^2 + \lambda \sum_{j=0}^{M} W_j $
  • 비용함수 -> Ridge와 다르게 패널티항으로 계수들의 절댓값을 합한 것에 람다를 곱한 항을 SSR(잔차제곱합)에 합함
    • 계수가 0이 되는 것 가능
    • sparse / simple model
    • 변수 선택의 효과가 있음
    • 다중공선성이 높은 데이터에서 ridge에 비해 상대적으로 예측 성능이 떨어짐


스크린샷 2023-04-02 오전 3 18 22

  • Lasso의 경우 최적값이 모서리에 나타날 확률이 Ridge에 비해 높기 때문에 몇몇 유의미하지 않은 변수들에 대해 계수를 0에 가깝게 추정해주어 독립변수를 효과적으로 선택하는 기능 제공
  • 즉, Lasso는 계수를 0으로 만들면서 데이터 손실이 일어나 정확도가 떨어질 수 있음


비용함수 최소화

  • Ridge의 비용함수(L2)는 미분 가능하여 경사하강법으로 최소화할 수 있음
  • Lasso의 비용함수(L1)은 미분 불가능하여 numerical optimization methods 사용
    스크린샷 2023-04-02 오전 3 20 51


ex1) Alpha 값 찾기 - plot

from sklearn.linear_model import Lasso
lasso = Lasso()

train_score = []
test_score = []
alpha_list = [0.001, 0.01, 0.1, 1, 10, 100]
for alpha in alpha_list:
    lasso = Lasso(alpha=alpha, max_iter=10000)
    lasso.fit(train_scaled, train_target)
    train_score.append(lasso.score(train_scaled, train_target))
    test_score.append(lasso.score(test_scaled, test_target))


\[\sum_{i=0}^{n}(y_i - \sum_{j} x_{ij}{\beta}_j)^2 + \lambda \sum_{j=1}^{p} |\beta_j|\]
  • ${\lambda}$ -> ${\alpha}$
  • ${\alpha}$ 는 규제의 강도를 나타내고, 사람이 직접 지정하는 hyper parameter


plt.plot(np.log10(alpha_list), train_score)
plt.plot(np.log10(alpha_list), test_score)
plt.xlabel('alpha')
plt.ylabel('R^2')
plt.show()

스크린샷 2023-04-02 오전 3 29 33

  • 1에서 점수 차가 가장 작고 test set의 점수가 가장 높으므로 ${\alpha}$ = 10


ex2) Alpha 값 찾기 - Cross Validation

from sklearn.linear_model import LassoCV
lassocv = LassoCV()
lassocv.fit(train_scaled, train_target)
print(lassocv.alpha_)
# 3.2565...


ex3) Alpha 값 설정하여 Lasso Regression 적용

lasso = Lasso(alpha=10)
lasso.fit(train_scaled, train_target)
print(lasso.score(train_scaled, train_target))
print(lasso.score(test_scaled, test_target))
#0.9888...
#0.9824...
  • 과대적합 없이 모델 fit 잘 됨!


Cross Validation

  • 교차검증: train set을 train set + validation set으로 분리한 뒤, validation set을 사용해 검증하는 방식
  • 보통 train set으로 훈련시키고 test set으로 검증
    -> 고정된 test set을 통해 모델 성능을 검증하고 수정하는 과정을 반복하면 test set에 과적합 될 수 있어 성능이 떨어질 수 있음


  • 장점
    • 모든 데이터셋을 훈련에 활용할 수 있음
      -> 정확도 향상
      -> 데이터 부족으로 인한 undefitting 방지
    • 모든 데이터셋을 평가에 활용할 수 있음
      -> 평가에 사용되는 데이터 편중 방지
      -> 평과 결과에 따라 좀 더 일반화된 모델 생성
  • 단점
    • 반복 횟수가 많기 때문에 모델의 훈련 / 평가에 시간이 오래 걸림


K-Fold Cross Validation

스크린샷 2023-04-02 오전 4 02 48


1) training data와 test data로 나눔
2) training data를 k개의 fold로 나눔
3) 각 fold를 validation set으로 설정하여 검증에 사용하고, 나머지 fold를 이용하여 모델 훈련
4) 총 k개의 성능 결과가 나오며, 이 k개의 평균을 해당 학습 모델의 성능이라고 함


Elastic-Net Regression 엘라스틱넷

1. 정의

  • 정규화 선형회귀의 일종으로 모델의 과적합 현상을 막는 방법
  • Lidge회귀와 Lasso회귀를 절충한 모델


2. 사용하는 경우

  • 너무 많은 변수들이 있고, 이들이 유용한지 아닌지 모를 때
  • 변수 간 다중공선성이 높고, 변수 선택이 필요할 때


3. Regularization

\[\arg \min_{\beta_j} (\sum_{i=1}^{n}(y_i - \beta_0 - \sum_{j=1}^{p}x_{ij}\beta_j)^2 + \lambda \sum_{j=1}^{n} (\alpha |\beta_j| + (1 - \alpha)\beta_j^2))\]
  • n: 데이터 수
  • i: 데이터 인덱스
  • j: 예측변수 인덱스

    hyper parameter

  • lambda: 규제 크기
  • alpha: 규제항(L1, L2) 비중 조절


  • 변수 선택 기능을 갖지 못하는 Lidge 회귀 모델과, 다중공선성이 높으면 좋은 성능을 갖지 못하는 Lasso 회귀 모델의 단점을 절충한 모델이기 때문에 변수 선택과 다중공선성이 높은 변수에 대해 좋은 성능을 가짐


스크린샷 2023-04-02 오전 4 14 40

  • 엘라스틱넷의 제약조건의 모양은 릿지와 라쏘 제약조건의 모양을 적절히 섞은 모양
  • 이러한 제약조건의 모양은 회귀계수를 0으로 추정할 수 있음
  • 또한, 볼록(convexity)하기 때문에 상관이 높은 예측변수들이 모두 선택되도록 하는 특징이 있음 (그룹화 효과, grouping effect)


ex1) ElasticNetCV 이용하여 lambda, alpha 결정

from sklearn.linear_model import ElasticNetCV
elastic_cv = ElasticNetCV(max_iter=10000, cv=10)
train_target_df = pd.DataFrame(train_target)
elastic_cv.fit(train_scaled, train_target_df.values.ravel())
print(elastic_cv.alpah_)
print(elastic_cv.l1_ratio_)
# 1.3086...
# 0.5


ex2) 결정된 하이퍼 파라미터 넣은 후 elastic-net regression 시행

from sklearn.linear_model import ElasticNet
elasticnet = ElasticNet(alpha=0.13, l1_ratio=0.5)
elasticnet.fit(train_scaled, train_target)
print(elasticnet.score(train_scaled, train_target))
print(elasticnet.score(test_scaled, test_target))
# 0.9893...
# 0.9762...
  • 과대적합 없이 좋은 fit!