선형 회귀를 위한 타겟 변환

Beginner

This tutorial is from open-source community. Access the source code

소개

이 실습에서는 scikit-learn 라이브러리의 TransformedTargetRegressor 를 사용하는 방법을 배웁니다. 선형 회귀 모델을 학습하기 전에 대상 값을 변환하는 이점을 관찰하기 위해 두 개의 다른 데이터 세트에 적용합니다. 합성 데이터와 Ames 주택 데이터 세트를 사용하여 대상 값을 변환하는 영향을 보여줍니다.

VM 팁

VM 시작이 완료되면 왼쪽 상단 모서리를 클릭하여 Notebook 탭으로 전환하여 연습을 위한 Jupyter Notebook에 접근합니다.

때때로 Jupyter Notebook 이 완전히 로드되기까지 몇 초 정도 기다려야 할 수 있습니다. Jupyter Notebook 의 제한으로 인해 작업의 유효성 검사를 자동화할 수 없습니다.

학습 중 문제가 발생하면 Labby 에게 문의하십시오. 세션 후 피드백을 제공하면 문제를 신속하게 해결해 드리겠습니다.

필요한 라이브러리 가져오기 및 합성 데이터 로드

필요한 라이브러리를 가져오고 합성 데이터를 로드하는 것으로 시작합니다. 합성 랜덤 회귀 데이터 세트를 생성하고 모든 항목이 음수가 아니도록 모든 대상을 변환하고 비선형 대상을 얻기 위해 지수 함수를 적용하여 단순 선형 모델로는 맞출 수 없는 대상을 수정합니다. 그런 다음 로그 함수 (np.log1p) 와 지수 함수 (np.expm1) 를 사용하여 대상을 변환한 후 선형 회귀 모델을 학습하고 예측에 사용합니다.

import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_regression
from sklearn.model_selection import train_test_split
from sklearn.compose import TransformedTargetRegressor
from sklearn.linear_model import RidgeCV
from sklearn.metrics import median_absolute_error, r2_score, PredictionErrorDisplay

## 합성 데이터 생성
X, y = make_regression(n_samples=10_000, noise=100, random_state=0)

## 대상 수정
y = np.expm1((y + abs(y.min())) / 200)
y_trans = np.log1p(y)

대상 분포 플롯

로그 함수를 적용하기 전후의 대상 확률 밀도 함수를 플롯합니다.

f, (ax0, ax1) = plt.subplots(1, 2)

ax0.hist(y, bins=100, density=True)
ax0.set_xlim([0, 2000])
ax0.set_ylabel("확률")
ax0.set_xlabel("대상")
ax0.set_title("대상 분포")

ax1.hist(y_trans, bins=100, density=True)
ax1.set_ylabel("확률")
ax1.set_xlabel("대상")
ax1.set_title("변환된 대상 분포")

f.suptitle("합성 데이터", y=1.05)
plt.tight_layout()

원본 대상에 대한 선형 회귀 모델 학습 및 평가

원본 대상에 대한 선형 회귀 모델을 학습하고 평가합니다. 비선형성으로 인해 학습된 모델은 예측 시 정확하지 않습니다.

X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)

ridge_cv = RidgeCV().fit(X_train, y_train)
y_pred_ridge = ridge_cv.predict(X_test)

score = {
    "R2": f"{r2_score(y_test, y_pred_ridge):.3f}",
    "MedAE": f"{median_absolute_error(y_test, y_pred_ridge):.3f}",
}

print("원본 대상에 대한 선형 회귀:")
for key, val in score.items():
    print(f"{key}: {val}")

변환된 대상에 대한 선형 회귀 모델 학습 및 평가

TransformedTargetRegressor 를 사용하여 변환된 대상에 대한 선형 회귀 모델을 학습하고 평가합니다. 로그 함수는 대상을 선형화하여, 중앙 절대 오차 (MedAE) 와 같은 선형 모델로도 더 나은 예측을 가능하게 합니다.

ridge_cv_with_trans_target = TransformedTargetRegressor(
    regressor=RidgeCV(), func=np.log1p, inverse_func=np.expm1
).fit(X_train, y_train)
y_pred_ridge_with_trans_target = ridge_cv_with_trans_target.predict(X_test)

score = {
    "R2": f"{r2_score(y_test, y_pred_ridge_with_trans_target):.3f}",
    "MedAE": f"{median_absolute_error(y_test, y_pred_ridge_with_trans_target):.3f}",
}

print("\n변환된 대상에 대한 선형 회귀:")
for key, val in score.items():
    print(f"{key}: {val}")

두 모델의 실제 값 대 예측 값 플롯

두 모델의 실제 값 대 예측 값을 플롯하고 각 축의 범례에 점수를 추가합니다.

f, (ax0, ax1) = plt.subplots(1, 2, sharey=True)

PredictionErrorDisplay.from_predictions(
    y_test,
    y_pred_ridge,
    kind="actual_vs_predicted",
    ax=ax0,
    scatter_kwargs={"alpha": 0.5},
)
PredictionErrorDisplay.from_predictions(
    y_test,
    y_pred_ridge_with_trans_target,
    kind="actual_vs_predicted",
    ax=ax1,
    scatter_kwargs={"alpha": 0.5},
)

for ax, y_pred in zip([ax0, ax1], [y_pred_ridge, y_pred_ridge_with_trans_target]):
    for name, score in score.items():
        ax.plot([], [], " ", label=f"{name}={score}")
    ax.legend(loc="upper left")

ax0.set_title("타겟 변환 없이 Ridge 회귀")
ax1.set_title("타겟 변환을 사용한 Ridge 회귀")
f.suptitle("합성 데이터", y=1.05)
plt.tight_layout()

Ames 주택 데이터 로드 및 전처리

Ames 주택 데이터 세트를 로드하고 숫자 열만 유지하고 NaN 또는 Inf 값이 있는 열을 제거하여 전처리합니다. 예측할 대상은 각 주택의 판매 가격입니다.

from sklearn.datasets import fetch_openml
from sklearn.preprocessing import quantile_transform

ames = fetch_openml(name="house_prices", as_frame=True, parser="pandas")

## 숫자 열만 유지
X = ames.data.select_dtypes(np.number)

## NaN 또는 Inf 값이 있는 열 제거
X = X.drop(columns=["LotFrontage", "GarageYrBlt", "MasVnrArea"])

## 가격을 k 달러로 표시
y = ames.target / 1000
y_trans = quantile_transform(
    y.to_frame(), n_quantiles=900, output_distribution="normal", copy=True
).squeeze()

Ames 주택 데이터의 타겟 분포 플롯

QuantileTransformer 를 적용하기 전후의 타겟의 확률 밀도 함수를 플롯합니다.

f, (ax0, ax1) = plt.subplots(1, 2)

ax0.hist(y, bins=100, density=True)
ax0.set_ylabel("확률")
ax0.set_xlabel("타겟")
ax0.set_title("타겟 분포")

ax1.hist(y_trans, bins=100, density=True)
ax1.set_ylabel("확률")
ax1.set_xlabel("타겟")
ax1.set_title("변환된 타겟 분포")

f.suptitle("Ames 주택 데이터: 판매 가격", y=1.05)
plt.tight_layout()

Ames 주택 데이터의 원본 타겟에 대한 선형 회귀 모델 학습 및 평가

Ames 주택 데이터의 원본 타겟에 대한 선형 회귀 모델을 학습하고 평가합니다.

X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=1)

ridge_cv = RidgeCV().fit(X_train, y_train)
y_pred_ridge = ridge_cv.predict(X_test)

score = {
    "R2": f"{r2_score(y_test, y_pred_ridge):.3f}",
    "MedAE": f"{median_absolute_error(y_test, y_pred_ridge):.3f}",
}

print("\n원본 타겟에 대한 선형 회귀:")
for key, val in score.items():
    print(f"{key}: {val}")

Ames 주택 데이터의 변환된 타겟에 대한 선형 회귀 모델 학습 및 평가

Ames 주택 데이터의 변환된 타겟에 대해 TransformedTargetRegressor 를 사용하여 선형 회귀 모델을 학습하고 평가합니다.

ridge_cv_with_trans_target = TransformedTargetRegressor(
    regressor=RidgeCV(),
    transformer=QuantileTransformer(n_quantiles=900, output_distribution="normal"),
).fit(X_train, y_train)
y_pred_ridge_with_trans_target = ridge_cv_with_trans_target.predict(X_test)

score = {
    "R2": f"{r2_score(y_test, y_pred_ridge_with_trans_target):.3f}",
    "MedAE": f"{median_absolute_error(y_test, y_pred_ridge_with_trans_target):.3f}",
}

print("\n변환된 타겟에 대한 선형 회귀:")
for key, val in score.items():
    print(f"{key}: {val}")

두 모델의 실제 값 대 예측 값 및 잔차 대 예측 값 플롯

두 모델의 실제 값 대 예측 값 및 잔차 대 예측 값 플롯을 생성하고 각 축의 범례에 점수를 추가합니다.

f, (ax0, ax1) = plt.subplots(2, 2, sharey="row", figsize=(6.5, 8))

PredictionErrorDisplay.from_predictions(
    y_test,
    y_pred_ridge,
    kind="actual_vs_predicted",
    ax=ax0[0],
    scatter_kwargs={"alpha": 0.5},
)
PredictionErrorDisplay.from_predictions(
    y_test,
    y_pred_ridge_with_trans_target,
    kind="actual_vs_predicted",
    ax=ax0[1],
    scatter_kwargs={"alpha": 0.5},
)

for ax, y_pred in zip([ax0[0], ax0[1]], [y_pred_ridge, y_pred_ridge_with_trans_target]):
    for name, score in score.items():
        ax.plot([], [], " ", label=f"{name}={score}")
    ax.legend(loc="upper left")

ax0[0].set_title("타겟 변환 없음의 Ridge 회귀")
ax0[1].set_title("타겟 변환 적용의 Ridge 회귀")

PredictionErrorDisplay.from_predictions(
    y_test,
    y_pred_ridge,
    kind="residual_vs_predicted",
    ax=ax1[0],
    scatter_kwargs={"alpha": 0.5},
)
PredictionErrorDisplay.from_predictions(
    y_test,
    y_pred_ridge_with_trans_target,
    kind="residual_vs_predicted",
    ax=ax1[1],
    scatter_kwargs={"alpha": 0.5},
)
ax1[0].set_title("타겟 변환 없음의 Ridge 회귀")
ax1[1].set_title("타겟 변환 적용의 Ridge 회귀")

f.suptitle("Ames 주택 데이터: 판매 가격", y=1.05)
plt.tight_layout()
plt.show()

요약

이 실습에서는 scikit-learn 라이브러리의 TransformedTargetRegressor 를 사용하는 방법을 배웠습니다. 선형 회귀 모델을 학습하기 전에 타겟 값을 변환하는 것이 가져오는 이점을 관찰하기 위해 두 개의 다른 데이터 세트에 적용했습니다. 합성 데이터와 Ames 주택 데이터 세트를 사용하여 타겟 값을 변환하는 영향을 보여주었습니다. 로그 함수가 타겟을 선형화하여 중앙 절대 오차 (MedAE) 와 같은 유사한 선형 모델로도 더 나은 예측을 가능하게 한다는 것을 관찰했습니다. 또한, Ames 주택 데이터 세트의 경우 변환기의 효과가 약했지만, R2 가 증가하고 MedAE 가 크게 감소하는 결과를 얻었습니다.