-
회귀모델에서 타겟(y)값의 정규화 방법 비교 실험Data Science/Pandas & Numpy&Scikit-learn 2022. 5. 27. 23:26반응형
선형회귀에서는 타겟(y)값이 정규분포라는 가정을 한다.
문득, 실제로 모델에서 어떠한 성능적 영향을 미치는지 궁금증이 나타났다.
또한 트리기반의 모델에서는 타겟값의 정규분포가 영향을 미치는지 같이 실험을 진행한다.
※ 본 실험은 수학적 분석 기반이 아닌, 라이브러리를 활용한 단순 실험임을 밝힙니다.
여러 지적사항 및 의견이 있으신분은 편하게 댓글로 말씀해주시기 바랍니다.
0. 적용 정규화 방법
1. Raw data
2. MinMaxScaler
3. StandardScaler
4. RobustScaler
5. Log Transfer
6. Log Transfer + StandardScaler
7. Boxcox Transfer
8. Boxcox Transfer + StandardScaler
1. 사용 데이터
오늘 사용할 데이터는 보스턴 지역의 집값 데이터로 다운로드 주소는 아래와 같다.
https://www.kaggle.com/competitions/house-prices-advanced-regression-techniques/data
2. 정규화 별 분포 그래프
타겟(y) 데이터는 약 0~800000 사이에 분포함을 알 수 있다.
MinMaxScaler, StandardScaler, RobustScaler 방법의 경우 분포(왜도,첨도)는 변하지 않고
범위에 대한 Scaling이 이루어진 것을 확인 할 수 있다.
Log Transfer, Boxcox Transfer의 경우 분포가 정규분포에 근사한 것을 확인 할 수 있다.
Log Transfer + StandardScaler, Boxcox Transfer + StandardScaler의 경우
각각 Transfer를 적용한 후 StandardScaler를 적용하였다.
3. 비교 실험
피처(x)는 수치형 값만 사용하였으며 StandardScaler를 적용하였다.
타겟(y)는 각 정규화를 적용하였다.
실험은 선형모델인 Multiple Linear Regression과 트리기반 모델인 XGBoost 모델을 기반으로 진행된다.
동일한 스케일을 통해 성능비교를 하기 위해서 각 산출된 예측결과(y')은 raw data로 역정규화를 진행했다.
역정규화된 예측결과를 R2와 RMSE를 통해 비교평가한다.
3-1. Multiple Linear Regression 예측 결과
정규화 방법 R2 RMSE Normal (Raw Data) 0.8591 28633.8319 MinMaxScaler 0.859 28637.966 StandardScaler 0.859 28640.3746 RobustScaler 0.859 28646.3154 Log Transfer 0.8822 26180.119 Log Transfer + StandardScaler 0.8823 26168.4911 Boxcox Transfer 0.8815 26263.2542 Boxcox Transfer + StandardScaler -219.6484 1133053.942 3-2. XGBoost 예측 결과
정규화 방법 R2 RMSE Normal (Raw Data) 0.9105 22813.6360 MinMaxScaler 0.9119 22643.7367 StandardScaler 0.9136 22416.1819 RobustScaler 0.9112 22725.5135 Log Transfer 0.9102 22852.5051 Log Transfer + StandardScaler 0.9127 22532.4878 Boxcox Transfer 0.9116 22684.0413 Boxcox Transfer + StandardScaler -219.6485 1133053.942 3-3. 결과해석
선형모델에서는 Scaler 방법들이 별다른 성능을 보여주지 못하였다.
반면 Transfer 모델의 경우 유의미한 성능향상을 보였다.
따라서 선형모델에서 타겟이 정규분포에 근사함이 유의미한 성능차이를 가져옴을 확인했다.
트리기반 모델에서는 유의미한 성능차이를 가져오지 못하였다.
Boxcox Transfer + StandardScaler 방법은 모든 실험에서 예측을 전혀 하지 못하는 결과를 가져왔다.
이는 어떠한 이유로 해당 현상이 발생했는지 추가적으로 공부하여 포스팅하겠다.
4. 코드
from google.colab import drive drive.mount('/content/drive') import pandas as pd import numpy as np import seaborn as sns import matplotlib.pyplot as plt from sklearn.preprocessing import MinMaxScaler, StandardScaler, RobustScaler from scipy import stats from scipy.special import boxcox, inv_boxcox from sklearn.linear_model import LinearRegression from xgboost import XGBRegressor from sklearn.metrics import r2_score from sklearn.metrics import mean_squared_error import warnings warnings.filterwarnings('ignore') ###### 데이터 로드 path = "./drive/MyDrive/ColabNotebooks/" df = pd.read_csv(path+"house_prices_train.csv") df = df.sample(frac=1).reset_index(drop=True) train = df.iloc[:1200] test = df.iloc[1200:].reset_index(drop=True) ###### 피처 및 타겟 선정 x_col = [x for x in train.columns[1:] if (type(train[x][0]) != str) and (not pd.isna(train[x][0]))] y_col = "SalePrice" ###### 기본 전처리 train_x = train[x_col] test_x = test[x_col] # Nan 값 제거 train_x = train_x.dropna() test_x = test_x.dropna() # Y 값 추출 train_y_normal = train_x[y_col].tolist() test_y_normal = test_x[y_col].tolist() # X 값에서 Y 값 제거 train_x.drop([y_col], axis=1, inplace=True) test_x.drop([y_col], axis=1, inplace=True) # X변수는 모두 STD 스케일링 적용 sc = StandardScaler() train_x.loc[:,:] = sc.fit_transform(train_x) test_x.loc[:,:] = sc.transform(test_x) ##### 타겟에 정규화 방법 적용 # normal #train_y_normal # MinMaxScaler sc_mm = MinMaxScaler() train_y_mm = sc_mm.fit_transform(pd.DataFrame(train_y_normal)) # StandardScaler sc_std = StandardScaler() train_y_std = sc_std.fit_transform(pd.DataFrame(train_y_normal)) # RobustScaler sc_robust = RobustScaler() train_y_robust = sc_robust.fit_transform(pd.DataFrame(train_y_normal)) # log Transfer #sc_std_log = StandardScaler() train_y_log = np.log1p(train_y_normal) #train_y_log = sc_std_log.fit_transform(pd.DataFrame(train_y_log)) # log Transfer + StandardScaler sc_log_std = StandardScaler() train_y_log_std = np.log1p(train_y_normal) train_y_log_std = sc_log_std.fit_transform(pd.DataFrame(train_y_log_std)) # BoxCox Transfer train_y_boxcox, optimal_lambda_Bc = stats.boxcox(train_y_normal) # BoxCox Transfer sc_boxcox_std = StandardScaler() train_y_boxcox_std, optimal_lambda_BcStd = stats.boxcox(train_y_normal) train_y_boxcox_std = sc_boxcox_std.fit_transform(pd.DataFrame(train_y_boxcox_std)) ##### 분포그래프 생성 fig, ax = plt.subplots(ncols=2, nrows=4, figsize=(15,15)) sns.distplot(train_y_normal, ax=ax[0,0]) sns.distplot(train_y_mm, ax=ax[0,1]) sns.distplot(train_y_std, ax=ax[1,0]) sns.distplot(train_y_robust, ax=ax[1,1]) sns.distplot(train_y_log, ax=ax[2,0]) sns.distplot(train_y_log_std, ax=ax[2,1]) sns.distplot(train_y_boxcox, ax=ax[3,0]) sns.distplot(train_y_boxcox_std, ax=ax[3,1]) ax[0,0].set_title("Normal") ax[0,1].set_title("MinMax") ax[1,0].set_title("STD") ax[1,1].set_title("Robust") ax[2,0].set_title("Log") ax[2,1].set_title("Log + STD") ax[3,0].set_title("Boxcox") ax[3,1].set_title("Boxcox + STD") ##### MLR 실험 # Normal mlr_normal = LinearRegression() mlr_normal.fit(train_x,train_y_normal) pred_y = mlr_normal.predict(test_x) print("Normal : " ,r2_score(test_y_normal, pred_y), '\t',mean_squared_error(test_y_normal, pred_y)**0.5) # MinMax mlr_mm = LinearRegression() mlr_mm.fit(train_x,train_y_mm) pred_y = mlr_mm.predict(test_x) y_pred_inverse = sc_mm.inverse_transform(pd.DataFrame(pred_y)) print("MinMax : " ,r2_score(test_y_normal, y_pred_inverse), '\t',mean_squared_error(test_y_normal, y_pred_inverse)**0.5) # STD mlr_std = LinearRegression() mlr_std.fit(train_x,train_y_std) pred_y = mlr_std.predict(test_x) y_pred_inverse = sc_std.inverse_transform(pd.DataFrame(pred_y)) print("S T D : " ,r2_score(test_y_normal, y_pred_inverse), '\t',mean_squared_error(test_y_normal, y_pred_inverse)**0.5) # Robust mlr_robust = LinearRegression() mlr_robust.fit(train_x,train_y_robust) pred_y = mlr_robust.predict(test_x) y_pred_inverse = sc_robust.inverse_transform(pd.DataFrame(pred_y)) print("Robust : " ,r2_score(test_y_normal, y_pred_inverse), '\t',mean_squared_error(test_y_normal, y_pred_inverse)**0.5) # Log mlr_log = LinearRegression() mlr_log.fit(train_x,train_y_log) pred_y = mlr_log.predict(test_x) y_pred_inverse = np.expm1(pred_y) print("L o g : " ,r2_score(test_y_normal, y_pred_inverse), '\t',mean_squared_error(test_y_normal, y_pred_inverse)**0.5) # Log + STD mlr_log_std = LinearRegression() mlr_log_std.fit(train_x,train_y_log_std) pred_y = mlr_log_std.predict(test_x) y_pred_inverse = sc_log_std.inverse_transform(pd.DataFrame(pred_y)) y_pred_inverse = np.expm1(y_pred_inverse) print("LogStd : " ,r2_score(test_y_normal, y_pred_inverse), '\t',mean_squared_error(test_y_normal, y_pred_inverse)**0.5) # Boxcox mlr_boxcox = LinearRegression() mlr_boxcox.fit(train_x,train_y_boxcox) pred_y = mlr_boxcox.predict(test_x) y_pred_inverse = inv_boxcox(pred_y,optimal_lambda_Bc) print("Boxcox : " ,r2_score(test_y_normal, y_pred_inverse), '\t',mean_squared_error(test_y_normal, y_pred_inverse)**0.5) # Boxcox + STD mlr_boxcox_std = LinearRegression() mlr_boxcox_std.fit(train_x,train_y_boxcox) pred_y = mlr_boxcox_std.predict(test_x) y_pred_inverse = sc_boxcox_std.inverse_transform(pd.DataFrame(pred_y)) y_pred_inverse = inv_boxcox(y_pred_inverse,optimal_lambda_BcStd) print("Boxcox : " ,r2_score(test_y_normal, y_pred_inverse), '\t',mean_squared_error(test_y_normal, y_pred_inverse)**0.5) ##### XGB 실험 # Normal xgb_normal = XGBRegressor(objective='reg:squarederror', n_estimators=100) xgb_normal.fit(train_x,train_y_normal) pred_y = xgb_normal.predict(test_x) print("Normal : " ,r2_score(test_y_normal, pred_y), '\t',mean_squared_error(test_y_normal, pred_y)**0.5) # MinMax xgb_mm = XGBRegressor(objective='reg:squarederror', n_estimators=100) xgb_mm.fit(train_x,train_y_mm) pred_y = xgb_mm.predict(test_x) y_pred_inverse = sc_mm.inverse_transform(pd.DataFrame(pred_y)) print("MinMax : " ,r2_score(test_y_normal, y_pred_inverse), '\t',mean_squared_error(test_y_normal, y_pred_inverse)**0.5) # STD xgb_std = XGBRegressor(objective='reg:squarederror', n_estimators=100) xgb_std.fit(train_x,train_y_std) pred_y = xgb_std.predict(test_x) y_pred_inverse = sc_std.inverse_transform(pd.DataFrame(pred_y)) print("S T D : " ,r2_score(test_y_normal, y_pred_inverse), '\t',mean_squared_error(test_y_normal, y_pred_inverse)**0.5) # Robust xgb_robust = XGBRegressor(objective='reg:squarederror', n_estimators=100) xgb_robust.fit(train_x,train_y_robust) pred_y = xgb_robust.predict(test_x) y_pred_inverse = sc_robust.inverse_transform(pd.DataFrame(pred_y)) print("Robust : " ,r2_score(test_y_normal, y_pred_inverse), '\t',mean_squared_error(test_y_normal, y_pred_inverse)**0.5) # Log xgb_log = XGBRegressor(objective='reg:squarederror', n_estimators=100) xgb_log.fit(train_x,train_y_log) pred_y = xgb_log.predict(test_x) y_pred_inverse = np.expm1(pred_y) print("L o g : " ,r2_score(test_y_normal, y_pred_inverse), '\t',mean_squared_error(test_y_normal, y_pred_inverse)**0.5) # Log + STD xgb_log_std = XGBRegressor(objective='reg:squarederror', n_estimators=100) xgb_log_std.fit(train_x,train_y_log_std) pred_y = xgb_log_std.predict(test_x) y_pred_inverse = sc_log_std.inverse_transform(pd.DataFrame(pred_y)) y_pred_inverse = np.expm1(y_pred_inverse) print("LogStd : " ,r2_score(test_y_normal, y_pred_inverse), '\t',mean_squared_error(test_y_normal, y_pred_inverse)**0.5) # Boxcox xgb_boxcox = XGBRegressor(objective='reg:squarederror', n_estimators=100) xgb_boxcox.fit(train_x,train_y_boxcox) pred_y = xgb_boxcox.predict(test_x) y_pred_inverse = inv_boxcox(pred_y,optimal_lambda_Bc) print("Boxcox : " ,r2_score(test_y_normal, y_pred_inverse), '\t',mean_squared_error(test_y_normal, y_pred_inverse)**0.5) # Boxcox + STD xgb_boxcox_std = LinearRegression() xgb_boxcox_std.fit(train_x,train_y_boxcox) pred_y = xgb_boxcox_std.predict(test_x) y_pred_inverse = sc_boxcox_std.inverse_transform(pd.DataFrame(pred_y)) y_pred_inverse = inv_boxcox(y_pred_inverse,optimal_lambda_BcStd) print("Boxcox : " ,r2_score(test_y_normal, y_pred_inverse), '\t',mean_squared_error(test_y_normal, y_pred_inverse)**0.5)
마치며
포스팅에 대한 피드백과 의견 그리고 질문은 언제나 환영합니다.
감사합니다.
반응형'Data Science > Pandas & Numpy&Scikit-learn' 카테고리의 다른 글
파이썬 수치 데이터 구간화(Binning) 하기 - pd.cut, pd.qcut (0) 2022.09.27 [Pandas] Pandas를 통한 데이터 전처리 (0) 2022.09.13 [Python]다중 조건으로 데이터 프레임 특정 행 추출하기(데이터 프레임 필터링) (0) 2022.05.10 [정규화,sklearn] MinMaxScaler, StandardScaler, RobustScaler (0) 2021.09.14 [인코딩,sklearn] Ordinal Encoding (0) 2021.09.14