Skip to content

(오*성) (Kaggle 경진대회) 두터운 꼬리 분포 데이터의 로그 변환 #55

@5comet

Description

@5comet
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이 나왔습니다.

수치가 너무 큰 것 같아 스타터 노트북을 보면서 더 개선할 방법이 없을까 고민해봤는데,

Image

편향된 히스토그램들을 교재에서 본 것 같아 교재를 찾아보았습니다.

Image

교재의 내용과 교수님이 추가로 올려주신 노트북에도 특성의 그래프가 정규분포 형태가 아니면 로그를 취해 정규분포 형태로 바꿔주는 것을 보고,
정규분포 형태가 아닌 특성들을 나누어서 모델학습을 진행했습니다.
타겟(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)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions