본문 바로가기

공부/kaggle

[Kaggle] Competition - 중고차 가격 예측

중고차 구매의 기술 🤑

2개월전 작성한 notebook...
처음 참여한 Competition에서 노트북 메달을 받았다..!!! 

순위는... 1722/3066 😭

 

Art of Buying Used Cars 🤑

Explore and run machine learning code with Kaggle Notebooks | Using data from Regression of Used Car Prices

www.kaggle.com

 

1. 개요

이 노트북에서는 여러 가지 특성(feature)을 바탕으로 중고차의 가격을 예측하는 것을 목표로 합니다. 평가 지표는 Root Mean Squared Error (RMSE) 입니다. 예측 정확도를 높이기 위해 다양한 머신러닝 모델을 사용하고, 이를 앙상블하여 성능을 향상시킬 예정입니다

 

2. 라이브러리 임포트 및 데이터 로딩

import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split, StratifiedKFold
from sklearn.preprocessing import StandardScaler, OrdinalEncoder
from sklearn.metrics import mean_squared_error
from xgboost import XGBRegressor
from lightgbm import LGBMRegressor
from catboost import CatBoostRegressor

# Loading the datasets
df_train = pd.read_csv('/kaggle/input/playground-series-s4e9/train.csv', index_col='id')
df_test = pd.read_csv('/kaggle/input/playground-series-s4e9/test.csv', index_col='id')
df_sub = pd.read_csv('/kaggle/input/playground-series-s4e9/sample_submission.csv')

 

 

3. 피쳐 개요

 

  • brand: 자동차 브랜드
  • model: 자동차 모델
  • model_year: 자동차 제조 연도
  • milage: 자동차 주행 거리
  • fuel_type: 연료 유형 (예: 휘발유, 하이브리드 등)
  • engine: 엔진 사양
  • transmission: 변속기 유형 (수동/자동)
  • accident: 자동차의 사고 이력
  • clean_title: 자동차가 깨끗한 제목(clean title)을 가지고 있는지 여부
  • price: 목표 변수, 자동차의 가격을 나타냄

 

4. 데이터 전처리

pd.options.display.max_columns = None
df_train.tail(10)

 

BMW 328 i 2011 239000 Gasoline 230.0HP 3.0L Straight 6 Cylinder Engine Gasoli... 6-Speed A/T Black Black None reported Yes 8000
Chevrolet Camaro 1LT 2019 59692 Gasoline 335.0HP 3.6L V6 Cylinder Engine Gasoline Fuel 10-Speed A/T Red Black At least 1 accident or damage reported Yes 33600
Audi A4 2.0T Premium quattro 2011 121886 Gasoline 211.0HP 2.0L 4 Cylinder Engine Gasoline Fuel 8-Speed A/T Gray Black None reported Yes 6000
GMC Yukon XL Denali 2016 89291 Gasoline 420.0HP 6.2L 8 Cylinder Engine Gasoline Fuel 8-Speed A/T Red Black At least 1 accident or damage reported Yes 24700
Chevrolet Camaro Z28 1999 110000 Gasoline 310.0HP 5.7L 8 Cylinder Engine Gasoline Fuel A/T White Gray None reported Yes 14500
Cadillac Escalade ESV Platinum 2017 49000 Gasoline 420.0HP 6.2L 8 Cylinder Engine Gasoline Fuel Transmission w/Dual Shift Mode White Beige None reported Yes 27500
Mercedes-Benz AMG C 43 AMG C 43 4MATIC 2018 28600 Gasoline 385.0HP 3.0L V6 Cylinder Engine Gasoline Fuel 8-Speed A/T White Black At least 1 accident or damage reported Yes 30000
Mercedes-Benz AMG GLC 63 Base 4MATIC 2021 13650 Gasoline 469.0HP 4.0L 8 Cylinder Engine Gasoline Fuel 7-Speed A/T White Black None reported Yes 86900
Audi S5 3.0T Prestige 2022 13895 Gasoline 3.0L 1-Speed Automatic Daytona Gray Pearl Effect Black None reported NaN 84900
Porsche Macan Base 2016 59500 Gasoline 252.0HP 2.0L 4 Cylinder Engine Gasoline Fuel Transmission w/Dual Shift Mode White Black None reported Yes 28995

 

4.1 결측치 확인

print("Train Data Missing Values:")
print(df_train.isnull().sum())

print("\nTest Data Missing Values:")
print(df_test.isnull().sum())
 
 

 

Train Data Missing Values:
brand               0
model               0
model_year          0
milage              0
fuel_type        5083
engine              0
transmission        0
ext_col             0
int_col             0
accident         2452
clean_title     21419
price               0
dtype: int64

Test Data Missing Values:
brand               0
model               0
model_year          0
milage              0
fuel_type        3383
engine              0
transmission        0
ext_col             0
int_col             0
accident         1632
clean_title     14239
dtype: int64

 

4.2 결측치 처리

 

  • fuel_type: 이 특성은 결측치가 상당히 많고, 가장 빈번한 값은 "gasoline"입니다. 결측치는 "gasoline"으로 채우겠습니다.
  • accidentclean_title: 이 특성들은 가격 예측에 중요한 변수이므로, 결측치는 'missing'으로 레이블을 지정합니다.
from sklearn.impute import SimpleImputer

def cleaning_data(df):
    # Filling missing values for 'fuel_type'
    fuel_type_imputer = SimpleImputer(strategy='most_frequent')
    df['fuel_type'] = fuel_type_imputer.fit_transform(df[['fuel_type']]).ravel()

    # Filling missing values for 'accident' and 'clean_title'
    missing_label_imputer = SimpleImputer(strategy='constant', fill_value='missing')
    df[['accident', 'clean_title']] = missing_label_imputer.fit_transform(df[['accident', 'clean_title']])
    
    return df

# Applying cleaning function to both train and test data
df_train_cleaned = cleaning_data(df_train)
df_test_cleaned = cleaning_data(df_test)

 

 

4.3 숫자형 및 범주형 특성 분리

적절한 전처리를 위해 특성들을 숫자형과 범주형으로 나눕니다.

num_features = ['milage', 'model_year']
cat_features = ['brand', 'model', 'fuel_type', 'accident', 'clean_title', 'transmission', 'ext_col', 'int_col']

 

4.4 스케일링 및 인코딩

숫자형 특성은 StandardScaler를 사용하여 표준화하고, 범주형 특성은 OrdinalEncoder를 사용하여 인코딩합니다.

from sklearn.compose import ColumnTransformer
from sklearn.pipeline import Pipeline

# Numerical pipeline
num_pipeline = Pipeline([
    ('scaler', StandardScaler())
])

# Categorical pipeline
cat_pipeline = Pipeline([
    ('ordinal', OrdinalEncoder(handle_unknown='use_encoded_value', unknown_value=-1))
])

# Combining pipelines
preprocessor = ColumnTransformer([
    ('num', num_pipeline, num_features),
    ('cat', cat_pipeline, cat_features)
])

# Applying transformations to training and test data
X_train = df_train_cleaned.drop(columns=['price'])
y_train = df_train_cleaned['price']
X_test = df_test_cleaned

X_train_transformed = preprocessor.fit_transform(X_train)
X_test_transformed = preprocessor.transform(X_test)

 

5. 모델링 및 평가

5.1 데이터 분할

데이터를 훈련 세트와 검증 세트로 나누고, StratifiedKFold를 사용하여 교차 검증을 합니다.

X_train, X_valid, y_train, y_valid = train_test_split(X_train_transformed, y_train, test_size=0.2, random_state=42)
skf = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)

 

5.2 모델 선택 및 훈련

세 가지 모델인 XGBoost, LightGBM, RandomForestRegressor를 훈련시킵니다.

# XGBoost model
xgb_model = XGBRegressor(n_estimators=300, learning_rate=0.05, random_state=42)
xgb_model.fit(X_train, y_train)
xgb_valid_pred = xgb_model.predict(X_valid)

# LightGBM model
lgbm_model = LGBMRegressor(n_estimators=300, learning_rate=0.05, random_state=42)
lgbm_model.fit(X_train, y_train)
lgbm_valid_pred = lgbm_model.predict(X_valid)

# CatBoost model
cat_model = CatBoostRegressor(iterations=300, learning_rate=0.05, random_state=42, verbose=0)  # verbose=0 to suppress output
cat_model.fit(X_train, y_train)
cat_valid_pred = cat_model.predict(X_valid)
[LightGBM] [Info] Auto-choosing col-wise multi-threading, the overhead of testing was 0.019312 seconds.
You can set `force_col_wise=true` to remove the overhead.
[LightGBM] [Info] Total Bins 1004
[LightGBM] [Info] Number of data points in the train set: 150826, number of used features: 10
[LightGBM] [Info] Start training from score 43890.785316

 

5.3 모델 평가

각 모델을 평가하기 위해 RMSE를 계산합니다.

def calculate_rmse(y_true, y_pred):
    return np.sqrt(mean_squared_error(y_true, y_pred))

# Evaluating each model
xgb_rmse = calculate_rmse(y_valid, xgb_valid_pred)
lgbm_rmse = calculate_rmse(y_valid, lgbm_valid_pred)
cat_rmse = calculate_rmse(y_valid, cat_valid_pred)

print(f"XGBoost RMSE: {xgb_rmse:.5f}")
print(f"LightGBM RMSE: {lgbm_rmse:.5f}")
print(f"CatBoost RMSE: {cat_rmse:.5f}")
XGBoost RMSE: 69245.96084
LightGBM RMSE: 68315.71391
CatBoost RMSE: 68548.69844

 

5.4 최종 예측 및 제출

세 모델의 예측을 앙상블하여 최종 예측을 생성하고, 제출 파일을 준비합니다.

test_pred = (lgbm_model.predict(X_test_transformed) * 0.6 + 
             cat_model.predict(X_test_transformed) * 0.3 + 
             xgb_model.predict(X_test_transformed) * 0.1)

# Preparing the submission file
df_sub['price'] = test_pred
df_sub.to_csv('submission.csv', index=False)

df_sub.head()

 

  id price
0 188533 20522.992960
1 188534 77216.713175
2 188535 50774.795522
3 188536 25234.286778
4 188537 32651.528025

 

요약

 

  • XGBoost, LightGBM, CatBoost 세 가지 모델을 훈련시켰습니다.
  • 각 모델을 RMSE로 평가한 결과, LightGBM이 가장 낮은 RMSE를 기록하여 가장 우수한 성능을 보였습니다.
  • 최종 제출에서는 세 모델을 앙상블하여 예측을 생성했습니다.

 

'공부 > kaggle' 카테고리의 다른 글

[kaggle] 타이타닉 데이터 분석 튜토리얼  (0) 2024.06.30