기본적인 구조의 회귀 모델
손실함수에 따라 다중 선형 회귀(multiple linear regression), 라쏘(Lasso), 릿지(Ridge), 엘라스틱넷(Elastic Net) 등으로 구분
w는 가중치 벡터(weight vector), b는 편향(bias)
선형적인 모델 구조이며, 가중합 형태로 구성되어 있어서 스케일 차이에 크게 영향을 받는다.
따라서 모든 특징이 연속형이고 스케일이 유사한 데이터에 적합하다.
선형회귀모델 학습은 w와 b 가운데 손실 함수를 최소화하는 w*와 b*를 찾는 문제라고 정의할 수 있다.
위 식의 손실함수 L(w,b)를 어떻게 설정하느냐에 따라 모델의 종류가 달라진다.
다중 선형 회귀 모델은 오차 제곱합을 손실 함수로 사용한다.
이를 손실함수로 사용하면 학습 데이터에 대한 오차를 줄이려다 모델이 과적합 될 우려가 있다.
과적합된 선형 회귀 모델은 각 학습 샘플을 정밀하게 예측하는 방식으로 학습돼 계수의 절댓값이 큰 경향이 있다.
따라서 손실함수에 큰 계수에 대한 페널티를 부여하여 과적합을 방지한다.
라쏘(Lasso)는 계수 절대값의 합(L1 페널티)을, 릿지(Ridge)는 계수 제곱합(L2 페널티)을,
엘라스틱넷(Elastic Net)은 두 개 모두를 페널티로 추가했다.
페널티를 부여한 손실 함수는 계수 절대값이 크고 학습 오차가 작은 모델보다 계수 절댓값과 학습 오차 둘 다 적당히 작은 모델을 좋게 평가한다. 따라서 페널티를 부여하면 계수의 절댓값이 작은 모델을 학습하는 효과가 있다.
구체적으로 L1페널티를 불필요한 계수를 0으로 만들고 L2 페널티는 불필요한 계수를 0에 가깝게 만든다. 그러나 이론적 차이일 뿐 예측 성능에 차이는 없다. 또한 엘라스틱넷도 더 발전된 모델이 아니며 하이퍼파라미터 튜닝은 더 어렵다.
따라서 라쏘나 릿지 중 하나를 임의로 선택하면 된다.
α는 계수 페널티의 가중치를 나타내는 파라미터다. 이 값이 클수록 상대적 오차제곱합에 대한 가중치가 적어지며, 반대로 이 값이 작을수록 오차 제곱합에 대한 가중치가 커지므로, 계수 페널티의 가중치와 모델의 복잡도는 반비례한다.
이처럼 모델의 복잡도를 결정짓는 하이퍼파라미터를 복잡도 파라미터라고 한다.
# 모델 학습
from sklearn.linear_model import *
LR = LinearRegression().fit(X_train, y_train)
ridge = Ridge().fit(X_train, y_train)
lasso = Lasso().fit(X_train, y_train)
EN = ElasticNet().fit(X_train, y_train)
# MAE로 평가
from sklearn.metrics import mean_absolute_error as MAE
def regression_model_test(model, X_test, y_test):
y_pred = model.predict(X_test)
mae = MAE(y_test, y_pred)
return mae
LR_mae = regression_model_test(LR, X_test, y_test)
ridge_mae = regression_model_test(ridge, X_test, y_test)
lasso_mae = regression_model_test(lasso, X_test, y_test)
EN_mae = regression_model_test(EN, X_test, y_test)
print(LR_mae, ridge_mae, lasso_mae, EN_mae) #모델 간 성능차이 확인
# 복잡도 파라미터(alpha) 튜닝
Lasso1 = Lasso(alpha = 0.1, random_state = 50).fit(X_train, y_train) #alpha = 0.1
Lasso2 = Lasso(alpha = 1, random_state = 50).fit(X_train, y_train) #alpha = 1
Lasso3 = Lasso(alpha = 10, random_state = 50).fit(X_train, y_train) #alpha = 10
Lasso1_mae = regression_model_test(Lasso1, X_test, y_test)
Lasso2_mae = regression_model_test(Lasso2, X_test, y_test)
Lasso3_mae = regression_model_test(Lasso3, X_test, y_test)
print(Lasso1_mae, Lasso2_mae, Lasso3_mae)
##작은 mae를 갖는 범위로 성능 확인하고, 각 범위 사이 값들로 알파 설정해 다시 확인
Lasso4 = Lasso(alpha = 0.05, random_state = 50).fit(X_train, y_train) #alpha = 0.05
Lasso5 = Lasso(alpha = 5, random_state = 50).fit(X_train, y_train)
Lasso4_mae = regression_model_test(Lasso4, X_test, y_test)
Lasso5_mae = regression_model_test(Lasso5, X_test, y_test)
print(Lasso4_mae, Lasso5_mae) #추가 확인 후 가장 작은 mae 갖는 범위 확인
로지스틱 회귀는 특정 x가 주어졌을 떄 라벨이 1(긍정 클래스)일 확률을 계산하고, 임계치 θ를 기반으로 분류한다.
로지스틱 회귀도 마찬가지로 손실함수에서 L1과 L2 페널티를 추가할 수 있다.
# 모델 학습
from sklearn.linear_model import LogisticRegression
model = LogisticRegression().fit(X_train,y_train)
# f1 스코어 계산
from sklearn.metrics import f1_score
y_pred = model.predict(X_test)
f1 = f1_score(y_test, y_pred)
print(f1)
임계치에 따라서 정밀도와 재현율이 어떻게 변하는지 확인해보자.
y_prob = model.predict_proba(X_test)
model.classes_ #결과 [0 1]
##0번째 열은 클래스 0에, 1번째 열은 클래스 1에 속할 확률임을 확인
# 임계치에 따른 정밀도와 재현율 계산 함수
from sklearn.metrics import precision_score, recall_score
def precision_andrecall_accto_threshold(y_prob, y_test, threshold):
y_prob_pred = (y_prob[:,1] > threshold).astype(int) #threshold보다 크면 1, 아니면 0
precision = precision_score(y_test, y_prob_pred)
recall = recall_score(y_test, y_prob_pred)
return precision, recall
# 임계치(0~1) 넣고 계산
import numpy as np
precision_list = []
recall_list = []
threshold_list = np.arange(0,1,0.01) #0부터 1까지 0.01씩 늘리며 계산
for threshold in threshold_list:
precision, recall = precision_andrecall_accto_threshold(y_prob, y_test, threshold)
precision_list.append(precision)
recall_list.append(recall)
# 시각화
from matplotlib import pyplot as plt
plt.plot(threshold_list, precision_list, label = "precision")
plt.plot(threshold_list, recall_list, label = "recall")
plt.legend()
plt.show()
임계치와 정밀도는 비례하며, 재현율은 반비례한다.
그러나 임계치가 커지면서 정밀도가 소폭 줄어드는 지점도 있으며, 0.8정도 되는 지점에서는 긍정클래스로 분류하는 샘플이 하나도 없어서 0이 된다.
선형모델은 선형적인 관계만 적절히 모델링할 수 있다.
왼쪽과 같이 선형회귀 모델로는 y=x²이라는 관계를 표현할 수 없다.
선형 회귀 모델로 특징과 라벨 간 비선형 관계를 표현하는 방법은 새로운 특징을 추가하거나 기존 특징을 변환하는 것이다.
원래 있던 특징 x에 제곱을 취한 새로운 특징을 추가하면 선형회귀모델로도 오른쪽처럼 표현할 수 있다.
그러나 지금은 특징과 라벨 간 관계를 정확히 알고 있기때문에 x²을 추가했지만,
실제로는 관계를 알 수 없고 각 특징별로 하나하나 시각화하여 관계를 파악해야한다는 문제가 있다.
오래 걸리더라도 선형 모델을 반드시 사용해야하고 성능이 매우 중요하다면, 미리 새로운 특징을 생성하는 함수(제곱, 루트, 지수 등)를 정의하고 그 함수를 이용해 여러개 특징을 생성한 뒤 특징 선택을 통해 다시 차원을 줄이는 방법이 있다.
참고
GIL's LAB, 「파이썬을 활용한 머신러닝 자동화 시스템 구축」, 위키북스(2022)
[ML/python] 결정 트리 (decision tree, DTC, class_weight, export_text, plot_tree) (0) | 2025.02.14 |
---|---|
[ML/python] K-최근접 이웃(K-Nearest Neighbors, K-NN) (0) | 2025.02.14 |
[ML/python] 머신러닝 파이프라인 사용하기 (0) | 2025.02.12 |
[ML/python] 분류모델, 회귀모델 평가 (0) | 2025.02.12 |
[ML] 사이킷런 지도 학습 클래스 정리 (0) | 2025.02.12 |