-
Notifications
You must be signed in to change notification settings - Fork 6
Description
numerical_transformer = SimpleImputer(strategy='median')
categorical_transformer = Pipeline(steps=[
('imputer', SimpleImputer(strategy='most_frequent')),
('onehot', OneHotEncoder(handle_unknown='ignore'))
])처음 모델은 수치형 변수의 결측치를 중위값으로, 범주형 변수의 결측치를 SimpleImputer로 최빈값으로 채운 뒤, OneHotEncoder로 나누어주었습니다.
교수님의 교재에서 훈련 결과가 좋았던 sklearn의 RandomForestRegressor 모델을 사용하여 결정트리는 100개로 설정하고 훈련시킨 후 RMSE 값을 확인한 결과 약 34624가 나왔습니다.
꽤 높은 수치라고 판단해 다른 사람의 코드를 보고 싶어서 찾아본 결과 경진대회 설명 페이지에서 스타터 노트북이 있길래 확인해보았습니다.
이 노트북에선 Tensorflow의 decision_forests(TF-DF) 모델을 사용하여 따로 전처리 과정 없이(찾아보니 이 모델은 내부에 결측치 처리 기능이 있다고 합니다.)
데이터만 나눈 후 모델 학습을 했는데, RMSE가 약 26000이 나왔습니다.
수치가 너무 큰 것 같아 스타터 노트북을 보면서 더 개선할 방법이 없을까 고민해봤는데,
편향된 히스토그램들을 교재에서 본 것 같아 교재를 찾아보았습니다.
교재의 내용과 교수님이 추가로 올려주신 노트북에도 특성의 그래프가 정규분포 형태가 아니면 로그를 취해 정규분포 형태로 바꿔주는 것을 보고,
정규분포 형태가 아닌 특성들을 나누어서 모델학습을 진행했습니다.
타겟(SalePrice)도 정규분포 형태가 아니라서 변환해주었고, TF-DF와 같이 결정트리를 300개로 늘려서 학습시킨 결과 RMSE가 약 0.13으로 크게 줄어든 모습을 확인할 수 있었습니다.
결론은, 데이터가 두터운 꼬리 분포를 따르는 경우에 로그 함수를 적용해 정규분포 형태로 바꾸는 것이 모델의 성능을 이렇게 크게 향상시키는 이유가 궁금합니다.
아래는 코드 전문입니다.
Details
import os
for dirname, _, filenames in os.walk('/kaggle/input'):
for filename in filenames:
print(os.path.join(dirname, filename))
import pandas as pd
import numpy as np
from sklearn.ensemble import RandomForestRegressor
from sklearn.metrics import mean_squared_error
from sklearn.model_selection import train_test_split
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import OneHotEncoder, StandardScaler, FunctionTransformer
from sklearn.compose import ColumnTransformer
from sklearn.pipeline import make_pipeline, Pipeline
train = pd.read_csv('/kaggle/input/competitions/house-prices-advanced-regression-techniques/train.csv')
test = pd.read_csv('/kaggle/input/competitions/house-prices-advanced-regression-techniques/test.csv')
y = train.SalePrice
X = train.drop(['SalePrice', 'Id'], axis=1, errors='ignore')
X_test = test.drop(['Id'], axis=1, errors='ignore')
train.info()
log_cols = ['LotFrontage', 'LotArea', 'MasVnrArea', 'BsmtFinSF1', 'BsmtFinSF2', 'BsmtUnfSF',
'TotalBsmtSF', '1stFlrSF', '2ndFlrSF', 'LowQualFinSF', 'GrLivArea', 'WoodDeckSF',
'OpenPorchSF', 'EnclosedPorch', '3SsnPorch', 'ScreenPorch', 'PoolArea', 'MiscVal']
num_cols = ['MSSubClass', 'OverallQual', 'OverallCond', 'YearBuilt', 'YearRemodAdd',
'BsmtFullBath', 'BsmtHalfBath', 'FullBath', 'HalfBath', 'BedroomAbvGr',
'KitchenAbvGr', 'TotRmsAbvGrd', 'Fireplaces', 'GarageYrBlt', 'GarageCars',
'GarageArea', 'MoSold', 'YrSold']
cat_cols = X.select_dtypes(include=['object']).columns
log_pipeline = make_pipeline(
SimpleImputer(strategy="median"),
FunctionTransformer(np.log1p, feature_names_out="one-to-one"),
StandardScaler())
num_pipeline = make_pipeline(
SimpleImputer(strategy='median'),
StandardScaler())
cat_pipeline = make_pipeline(
SimpleImputer(strategy='most_frequent'),
OneHotEncoder(handle_unknown='ignore'))
preprocessor = ColumnTransformer(
transformers=[
('log', log_pipeline, log_cols),
('num', num_pipeline, num_cols),
('cat', cat_pipeline, cat_cols)
])
model = RandomForestRegressor(n_estimators=300, random_state=42)
my_pipeline = make_pipeline(preprocessor, model)
X_train, X_valid, y_train, y_valid = train_test_split(X, y, train_size=0.8, test_size=0.2, random_state=0)
my_pipeline.fit(X_train, np.log1p(y_train))
preds = my_pipeline.predict(X_valid)
mse = mean_squared_error(np.log1p(y_valid), preds)
rmse = np.sqrt(mse)
print('RMSE Score:', rmse)
my_pipeline.fit(X, np.log1p(y))
final_preds = my_pipeline.predict(X_test)
final_preds = np.expm1(final_preds)
output = pd.DataFrame({'Id': test.Id, 'SalePrice': final_preds})
output.to_csv('submission.csv', index=False)