1. 문제 정의
1.1 대회 소개
경진대회 소개 이미지
주최차 | 데이콘, 한국토지주택 공사 |
총 상금 | 총 상금 1,300만원 |
문제 유형 | Regression(회귀) |
평가척도 | MAE |
대회 기간 | 2021.06.10 ~ 2021.07.30 18:00 |
대회 참여팀 | 1885명 |
1.2 배경
아파트 단지 내 필요한 주차대수는 ①법정주차대수 ②장래주차수요 중 큰 값에 따라 결정하게되어 있어, 정확한 ②장래주차수요의 산정을 필요로 합니다.
현재 ②장래주차수요는 ‘주차원단위’와 ‘건축연면적’을 기초로하여 산출되고 있으며, ‘주차원단위’는 신규 건축예정 부지 인근의 유사 단지를 피크 시간대 방문하여 주차된 차량대수를 세는 방법으로 조사하고 있습니다.
이 경우 인력조사로 인한 오차발생, 현장조사 시점과 실제 건축시점과의 시간차 등의 문제로 과대 또는 과소 산정의 가능성을 배제할 수 없습니다.
if: 법정주차 대수 > 장래주차수요: 그럼 그냥 법정 주차 대수를 주차대수로 정합니다.
elif: 법정주차 대수 < 장래주차수요: 장래주차수요를 주차대수로 정합니다.
위의 기사를 요약하면 다음과 같다.
서울에서는 전용면적 85㎡ 이하인 주택단지의 경우 주차대수를 전용면적의 합계로 나눈 값이 75분의 1을 넘어야 한다.
전용면적이 85㎡를 초과하면 그 비율이 65분의 1을 넘어서야 한다.
예를 들어 서울에 전용면적 84㎡ 주택 100가구로 구성된 아파트가 있다면 주차장은 112대(8400/75) 이상의 주차대수를 확보해야 한다.
광역시와 수도권 내 시 지역은 85㎡ 이하인 경우 85분의 1 이상, 85㎡를 초과하면 70분의 1 이상의 주차대수 기준을 확보해야 한다.
그러나 이런 기준은 1996년도를 기준으로 한 것이어서 차량등록 대수가 급증하는 현실을 반영하지 못한다는 지적이 있었다. 따라서 주차대수의 기준을 바꿀 필요가 있다.
배경을 살펴보면, 장래주차수요의 경우, 직접 주차된 차량대수를 세는 방법을 사용한다고 되어있습니다. 이는 결국, 단지별 필요한 주차장의 크기, 주차대수를 산정하는 과정에서 인력이 필요하고, 어쩔 수 없는 오차가 생기기 때문에 주차대수를 정확하게 측정하는 것이 굉장히 어려움을 의미합니다.
이러한 배경을 바탕으로 주차대수의 예측문제에 대해 데이터 분석적 접근 방식의 해결방안을 요구하고 있습니다.
목적을 살펴보면 “유형별 임대주택 설계 시 단지 내 적정 주차 수요를 예측”라고 되어있습니다. 이는 임대주택의 건설과 설계를 할 때, 주차수요를 같이 예측하여 주차 수요, 주차장의 크기를 예측하는 것입니다.
1.3 평가지표
MAE(Mean Absolute Error)
•
모델의 예측값과 실제값의 차이의 절대값의 평균
•
= i번째 예측 값(학습한 모델의 주차 대수)
•
= i번째 실제 값(실제 단지별 주차 대수)
•
= 데이터셋의 크기 (test)
결국 목표는 학습한 값과 실제 주차 대수의 차이를 줄이는 것
2. EDA
정확한 데이터 분석을 위해서는 데이터에 대한 이해가 반드시 선행되어야 합니다. 전박적으로 데이터를 이해하기 위한 데이터 탐색 과정을 탐색적 데이터 분석이라고 합니다. EDA를 통해 데이터의 분포 및 특성 등에 대한 정보를 파악하고 데이터 간의 관계를 확인합니다. 그 이후, 예측 모델링과 전처리에 활용합니다.
import os
import glob
import pandas as pd
import numpy as np
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.metrics import r2_score, mean_absolute_error
import plotly
import plotly.express as px
import seaborn as sns
import matplotlib
import matplotlib.pyplot as plt
from matplotlib import font_manager, rc
%matplotlib inline
import warnings
warnings.filterwarnings(action='ignore')
!pip install pycaret
from pycaret.regression import *
Python
복사
전처리 과정에서 필요한 라이브러리를 불러온다. 사용하지 않은 라이브러리도 있다.
train=pd.read_csv("/content/drive/MyDrive/data/235745_parking_data/train.csv")
test=pd.read_csv("/content/drive/MyDrive/data/235745_parking_data/test.csv")
submission=pd.read_csv("/content/drive/MyDrive/data/235745_parking_data/sample_submission.csv")
age_gender=pd.read_csv("/content/drive/MyDrive/data/235745_parking_data/age_gender_info.csv")
Python
복사
경로는 각자의 컴퓨터의 경로로 수정하면 된다.
2.1 데이터 소개
train.csv 에 대한 간단한 정리
age_gender_info.csv 에 대한 간단한 정리
데이터를 살펴보면 2952개의 데이터가 있고 14개의 feature가 있고 1개의 target인 등록차량 수가 있다.
우선 train 파일의 정보를 확인한다. 예상대로 object 타입의 범주형 변수들이 있으며, train 데이터에서는 임대보증금, 임대료, 도보 10분거리 내 지하철역 수(환승노선 수 반영), 도보 10분거리 내 버스정류장 수에 NULL값 존재한다.
그리고 test파일의 정보를 확인한다. 자격유형, 임대보증금, 임대료, 도보 10분거리 내 지하철역 수(환승노선 수 반영)에 NULL값 존재한다.
3. 전처리 과정
feature가 길고 표현이 복잡하기 때문에 더 간단한 형태로 변형한다.
cols = ['단지코드', '총세대수', '임대건물구분', '지역', '공급유형', '전용면적', '전용면적별세대수', '공가수',
'자격유형', '임대보증금', '임대료', '지하철',
'버스', '단지내주차면수', '등록차량수']
train.columns = cols
test.columns = cols[:14]
Python
복사
3.1 결측치 처리
3.11 임대료, 임대보증금 결측치 처리
임대 보증금과 임대료의 경우, 결측치를 ‘-’로 채워 놓은 경우가 있다. 따라서 이를 실수형 형태로 변형시켜준다.
train.loc[train.임대보증금=='-', '임대보증금'] = np.nan
test.loc[test.임대보증금=='-', '임대보증금'] = np.nan
train['임대보증금'] = train['임대보증금'].astype(float)
test['임대보증금'] = test['임대보증금'].astype(float)
train.loc[train.임대료=='-', '임대료'] = np.nan
test.loc[test.임대료=='-', '임대료'] = np.nan
train['임대료'] = train['임대료'].astype(float)
test['임대료'] = test['임대료'].astype(float)
Python
복사
3.12 지하철, 버스 결측치 처리
train data에 지하철의 경우 결측치가 4개, 버스이 경우 결측치가 211개 있고, 이를 지역별 평균값으로 채워준다. (0으로 채우는 것에 대해도 고민을 해보았는데, 기왕이면 값이 있는 것으로 채우고 싶어 다음과 같이 채워보았다.)
bus = {}
cnt = 0
for i in train['지역'] :
if i not in bus :
bus[i] = []
bus[i].append(train['버스'][cnt])
cnt += 1
subway = {}
cnt = 0
for i in train['지역'] :
if i not in subway :
subway[i] = []
subway[i].append(train['지하철'][cnt])
cnt += 1
bus_mean = {}
for i in bus.keys() :
temp = np.array(bus[i])
temp = np.nanmean(temp)
bus_mean[i] = round(temp)
subway_mean = {}
for i in subway.keys() :
temp = np.array(subway[i])
temp = np.nanmean(temp)
subway_mean[i] = round(temp)
for i in bus.keys() :
train['버스'] = np.where(train['지역'] == i, bus_mean[i], train['버스'])
train['지하철'] = np.where(train['지역'] == i, subway_mean[i], train['지하철'])
test['지하철'] = np.where(test['지역'] == i, subway_mean[i], test['지하철'])
Python
복사
3.13 Test 자격유형 결측치
test[test.자격유형.isnull()]
Python
복사
단지코드 C2411 / C2253 자격유형에 결측치가 있다.
단지코드, 임대건물구분, 지역 등이 동일한 샘플의 자격유형 값을 참고하여 대체한다.
test.loc[test.단지코드.isin(['C2411']) & test.자격유형.isnull(), '자격유형'] = 'A'
test.loc[test.단지코드.isin(['C2253']) & test.자격유형.isnull(), '자격유형'] = 'C'
Python
복사
3.13 임대료 / 임대보증금 결측치 제거
myhome 사이트에 들어가면 조건별로 검색해서 실제 임대조건및 임대료, 보증금을 찾을 수 있다. train.csv의 정보를 통해 검색해서 찾으면 된다.
지역, 세대수, 전용면적, 전용면적별세대수 정보를 바탕으로 실제 임대 모집 공고와 비교를 통해 결측치 대체
1.
[Train] C1786 | 강원도 | 행복주택 | 총 480세대 : 춘천거두2 행복주택
2.
[Train] C1326 | 부산광역시 | 국민임대 | 총 1934세대 : 부산정관 7단지 A-1블록
3.
[Train] C2186 | 대구광역시 | 국민임대 | 총 924세대 : 대구연경 A-2블록 국민임대주택
4.
[Test] C2152 | 강원도 | 영구임대 | 총 120세대 : 화천신읍 공공실버주택
5.
[Test] C1267 | 경상남도 | 행복주택 | 총 675세대 : 창원가포 A-1블록 행복주택
6.
[Test] C1006 | 대전광역시 | 임대상가 | 총 1505세대 : 대전둔산1단지
결측치 제거 코드
결측치를 대체하지 못한 것들은 전부 0으로 대체한다.
train[['임대보증금','임대료']] = train[['임대보증금','임대료']].fillna('0').replace('-','0').astype(int)
test[['임대보증금', '임대료']] = test[['임대보증금', '임대료']].fillna('0').replace('-','0').astype(int)
Python
복사
3.2 지역 데이터 범주 변경
지역 데이터는 범주형 데이터인데 학습을 원활하게 하기 위해서 수치형 데이터로 변경한다.
local_map = {}
for i, loc in enumerate(train['지역'].unique()):
local_map[loc] = i
train['지역'] = train['지역'].map(local_map)
test['지역'] = test['지역'].map(local_map)
Python
복사
범주형 데이터로 그대로 놓고 Catboost로 학습을 진행시켜보았으면 좋겠다는 생각을 하기도 하였다.
3.3 Feature Engineering
3.31 공급유형 feature 수정
공급유형의 종류가 10개로 굉장히 많다. 다음과 같이 categorize해서 구분했다.
0 : 국민임대
1 : 단기공공임대(공공임대(5년)/공공임대(10년)/공공임대(분납)/공공분양)
2 : 임대상가
3 : 장기공공임대(공공임대(50년))
4 : 저소득층(행복주택/영구임대/장기전세)
train.loc[train['공급유형'].isin(['공공임대(50년)']),'공급유형'] = '장기공공임대'
train.loc[train['공급유형'].isin(['공공임대(5년)', '공공임대(10년)', '공공임대(분납)', '공공분양']),'공급유형'] = '단기공공임대'
train.loc[train['공급유형'].isin(['행복주택', '영구임대', '장기전세']), '공급유형'] = '저소득층'
test.loc[test['공급유형'].isin(['공공임대(50년)']),'공급유형'] = '장기공공임대'
test.loc[test['공급유형'].isin(['공공임대(5년)', '공공임대(10년)', '공공임대(분납)', '공공분양']),'공급유형'] = '단기공공임대'
test.loc[test['공급유형'].isin(['행복주택', '영구임대', '장기전세']), '공급유형'] = '저소득층'
train['n공급유형'] = train.loc[:,'공급유형'].astype('category').cat.codes
test['n공급유형'] = test.loc[:,'공급유형'].astype('category').cat.codes
Python
복사
3.32 전용면적 feature 수정
전용면적의 경우, 소숫점 둘째자리까지 표현이 되어있는데 보기 힘들고 표현을 쉽게 하기 위해 5의 배수로 바꾼다.
train['전용면적'] = train['전용면적'] //5*5
test['전용면적'] = test['전용면적'] //5*5
Python
복사
3.33 연령 데이터 feature 추가
미성년자가 많으면 차량의 수가 적을 것이라고 생각해서 미성년자 feature를 추가시켰다.
minors = ['10대미만(여자)', '10대미만(남자)', '10대(여자)', '10대(남자)']
age_gender['미성년자'] = age_gender[minors].sum(axis=1)
age=pd.concat([age_gender['지역'],age_gender['미성년자']],axis=1)
age
Python
복사
local_age = {}
for i, loc in enumerate(age['지역'].unique()):
local_age[loc] = i
age['지역'] = age['지역'].map(local_age)
train = pd.merge(age,train ,left_on= ["지역"], right_on= ["지역"], how='inner')
test = pd.merge(age, test,left_on= ["지역"], right_on= ["지역"], how='inner')
train
Python
복사
train데이터에 미성년자 feature를 병합하였다.
추후에 주차 대수와의 correlation을 파악하였더니 상관관계가 낮고, feature_importance가 낮은 관계로 삭제하였다.
또한 미성년자의 인구비율이 높으면 자동차등록대수가 적을 것이라고 생각하였지만 오히려 1인가구의 비율, 주위의 대중교통이 많은지, 가족단위의 가구가 많은지에 대해 더 생각해볼 필요가 있다고 생각을 해서 feature를 삭제하기로 했다.
3.4 단지코드별로 병합
제출하는 submission.csv를 확인해보면 단지코드별로 주차대수를 예측하는 방식으로 되어있다.
예측에 필요한 feature만 남기고, 몇가지 feature는 생략하도록한다.
사용하는 feature: 단지코드/지역/n공급유형/공가수/지하철/버스/단지내주차면수/미성년자수
단지코드별로 합칠 때, 추가적으로 feature를 생성한다.
총임대세대수는 단지의 총 임대세대수로 단지마다 전용면적별 세대수를 합쳐 만들었다.
평균전용면적은 단지의 모든 전용면적의 평균값을 적용하였다.
총전용면적은 단지의 총 전용면적이 크다면 주차대수가 클 것으로 예측하여 추가하였다.
평균임대보증금과 평균임대료에 대한 feature도 추가하였다.
df_train = pd.DataFrame()
columns = ['단지코드', '지역', 'n공급유형', '공가수', '지하철', '버스', '단지내주차면수','등록차량수']
tmp = train.copy()
codes = train.단지코드.unique()
for i, code in enumerate(codes):
tmp_code = train.loc[train.단지코드 == code].reset_index(drop=True)
df_train.loc[i, columns] = tmp_code.loc[0, columns]
df_train.loc[i, '총임대세대수'] = (tmp_code.전용면적별세대수).sum()
df_train.loc[i, '평균전용면적'] = (tmp_code.전용면적).mean()
df_train.loc[i, '총전용면적'] = (tmp_code.전용면적 * tmp_code.전용면적별세대수).sum()
df_train.loc[i, '평균임대보증금'] = (tmp_code.전용면적별세대수 * tmp_code.임대보증금).sum() / (tmp_code.전용면적별세대수).sum()
df_train.loc[i, '평균임대료'] = (tmp_code.전용면적별세대수 * tmp_code.임대료).sum() / (tmp_code.전용면적별세대수).sum()
Python
복사
한 단지에 대해 얼마나 거주하고 있는지에 대한 비율을 알아보기 위해 거주율에 대한 feature를 마지막으로 추가하였다.
df_train['거주율']=(df_train['총임대세대수']-df_train['공가수'])/(df_train['총임대세대수'])
df_train.head()
Python
복사
test도 같은 방식으로 진행하였다.
최종적인 df_train의 모습 전처리 과정에서 등록차량의 수가 가운데 열에 있으므로 주의를 바랍니다.
4. 모델링
4.1 XGboost
xgboost에 관한 사항은 를 참고 바랍니다.
그리드 서치를 이용해 적절한 하이퍼 파라미터를 찾아준다.
이후, KFold를 이용해 모델을 학습시키고 5개의 모델로 test를 예측한다. 예측한 값들을 평균을 내어 제출하면 된다.
import xgboost
from sklearn.model_selection import KFold
from sklearn.model_selection import GridSearchCV
from sklearn.pipeline import Pipeline
from sklearn.multioutput import MultiOutputRegressor
def modelfit(model, grid_param_xgb, x, y) :
gs_xgb = (GridSearchCV(model,
param_grid=grid_param_xgb,
cv=4,
# scoring='neg_mean_squared_error',
#scoring ='accuracy',
n_jobs=-1,
verbose=10))
gs_xgb = gs_xgb.fit(x, y)
print('Train Done.')
#Predict training set:
y_pred = gs_xgb.predict(x)
#Print model report:
print("\nModel Report")
print("\nCV 결과 : ", gs_xgb.cv_results_)
print("\n베스트 정답률 : ", gs_xgb.best_score_)
print("\n베스트 파라미터 : ", gs_xgb.best_params_)
xgb1 = model = xgboost.XGBRegressor()
grid_param_xgb1 = {
'reg__estimator__max_depth' : [4,5, 6, 7],
'reg__estimator__gamma' : [1, 0.1, 0.01, 0.001, 0.0001, 0],
'reg__estimator__learning_rate' : [0.01, 0.03, 0.05, 0.07, 0.08, 0.009],
'reg__estimator__subsample' : [0.4, 0.6, 0.8,0.9],
'reg__estimator__colsample_bytree' : [0.2, 0.6, 0.8,0.9],
'reg__estimatior__eta': [0.1, 0.01, 0.03, 0.05, 0.008],
'reg__estimatior__n_estimator': [10, 100, 1000, 5000, 10000],
'reg__estimatior__num_boost_around' : [10,100,1000,5000]
}
modelfit(model, grid_param_xgb1, df_train.drop(columns=['단지코드',target_col]), df_train[target_col])
l_model = []
k_fold = KFold(n_splits = 5, shuffle=True, random_state = 123)
for train_idx, val_idx in k_fold.split(df_train) :
model = xgboost.XGBRegressor(
eval_metric = 'mae',
max_depth = 4,
n_estimators = 10000,
eta = 0.008,
learning_rate = 0.009,
num_boost_around = 5000,
min_childe_weight = 1,
seed = 2022,
sub_sample = 0.9,
colsample_bytree = 0.9,
use_missing = False,
)
x_t = df_train.drop(columns=['단지코드',target_col]).iloc[train_idx]
y_t = df_train[target_col].iloc[train_idx]
x_val = df_train.drop(columns=['단지코드',target_col]).iloc[val_idx]
y_val = df_train[target_col].iloc[val_idx]
l_model.append(model.fit(x_t,y_t, eval_set= [(x_val,y_val)], early_stopping_rounds = 100))
Python
복사
xgboost.plot_importance(l_model[0])
Python
복사
첫 번째 모델에 다한 feature importance 그래프는 다음과 같다.
그러나, 아쉽게도 제출한 파일의 점수가 좋지 않았다.
4.2 Random Forest
rf_model = create_model('rf')
rf_2 = tune_model(rf_model, fold=10, optimize = 'MAE', choose_better = True)
Python
복사
randomforest의 경우, hyper parameter tuning의 과정을 거쳤다.
4.3 Pycaret을 이용한 앙상블
4.31 PyCaret이란
PyCaret은 적은 코드로 머신러닝 워크 플로우를 자동화하는 오픈 소스 라이브러리입니다. 머신러닝 모델 개발시 많은 시간을 소요했던 코딩, 전처리, 모델 선택, 파라미터 튜닝 작업을 자동화해주어 쉽고, 높은 생산성의 작업을 가능하게 합니다.
4.32 PyCaret
PyCaret를 활용하기 위한 환경을 만들어줍니다.
pycaret_train=tmp_train.drop(['단지코드'],axis=1)
reg = setup(pycaret_train,
preprocess = False,
train_size = 0.999,
target = '등록차량수',
silent = True,
use_gpu = False,
numeric_features=list(pycaret_train.drop(columns = ['등록차량수']).columns),
fold_shuffle = True
)
Python
복사
평가기준인 MAE를 기준으로 성능이 좋은 순서대로 출력합니다.
top5 = compare_models(n_select = 5, sort = 'MAE')
Python
복사
1.
Extra Tree regressor
ET=create_model('et')
Python
복사
2.
HuberRegressor
huber = create_model('huber')
Python
복사
3.
Lasso
lasso = create_model('lasso')
Python
복사
다음 3개의 모델을 앙상블하여 새로운 모델을 만들었다. blending을 하게 되면 soft voting의 과정을 거치게 된다. soft voting이란 다수의 regressor의 예측 결과값의 평균을 결과로 내게 된다.
blender1 = blend_models(estimator_list = [ET,huber,lasso], optimize = 'MAE')
final_model = finalize_model(blender1)
result = pull(final_model)
Python
복사
최종 모델 설명
PyCaret의 tuning 기능을 사용해서 HyperParameter 조절을 하였지만 오히려 성능 저하가 생겨 tuning은 초기 설정 값으로 진행을 하였다.
Train set에 대한 잔차 분포 그래프
4.33 submission
scaler = StandardScaler()
scaling_features = ['지역', 'n공급유형', '공가수', '지하철', '버스', '단지내주차면수', '총임대세대수', '총전용면적', '평균임대보증금', '평균임대료','거주율']
tmp_test = df_test.copy()
tmp_test.loc[:, scaling_features] = scaler.fit_transform(tmp_test[scaling_features])
test = tmp_test.drop(['단지코드'], axis=1, inplace=False)
pred=predict_model(final_model,data=test)
submission['num'] = pred[["Label"]]
submission.to_csv('/content/drive/MyDrive/data/235745_parking_data/ensemble_02.csv', index=False)
Python
복사
5. 시사하는 바
우선, 이미 종료된 대회이기 때문에 여러 공유된 코드들의 도움을 받을 수 있었다. 점수가 좋았던 팀들의 코드를 분석했을 때, 범주형 데이터가 많아 Catboost를 사용하면 좋을 것 이라 생각했고, 또는 범주형데이터를 수치형으로 바꾼 후 XGboost를 사용하면 충분히 좋은 결과를 얻을 것이라 생각했다.
팀원들 모두 모델링을 직접 해본 경험이 거의 없어 중간세미나 때 발표했던 xgboost로 연습 겸 제출했다. XGboost는 대부분의 상황에 준수한 성능을 보여주기 때문에 점수 역시 상위권에 들지 않을까 생각했지만, 114~5점으로 아쉬운 모습을 보였다. 처음 제출 시 gridsearch를 사용하지 않고 하이퍼 파라미터를 임의로 두어 제출했다. ㅁ
두번째로는, 강의를 들으면서 배웠던 Random Forest를 사용해 제출했다. 셋 중 가장 단순한 방식으로 예상처럼 가장 좋지 않은 성능을 보여주었다. 점수는 119~120점으로 나왔다.
마지막으로, pycaret이라는 auto ml을 사용해 제출했다. auto ml은 앞서 설명한 바와 같은 방식으로 제출하였으며 셋 중 가장 준수한 성능을 보였다. 예상과는 다르게 pycaret에서 뽑은 모델에 catboost나 xgboost는 없었다. pycaret은 104~105의 점수를 보였다.
이런 점은, 머신러닝 초보들은 데이터를 보고 어떤 모델을 사용해야 하는지 잘 모를 수 있기에 pycaret이 방향성을 제시 할 수 있는 좋은 모델임을 시사한다. 그러나, 이런 pycaret 역시 항상 옳은 것은 아니다. 특히나 validation을 기준으로 순위를 매기게 되는데, 1등을 하게 된 팀이 다항 회귀를 사용한 점으로 보아 더 좋은 모델이 있을 수도 있음을 알아야한다. 또한, 데이터 전처리를 어떤식으로 했는지도 영향을 미친다. 가령, 범주형 변수들을 수치형으로 바꿔주는 작업을 하지 않았더라면 pycaret은 다른 모델을 선정했을지도 모른다. 범주형 feature가 많았더라면 Catboosting을 시도했을 것 같다.
모델 별 점수차이가 아주 크지 않다. 이는, 실제로 모델링이 예측에 영향을 미치는 정도보다 데이터 전처리가 더욱 중요하다는 점을 말한다. 데이터 전처리를 어떻게 하는지에 따라 사용할 모델을 적절하게 골라야한다. 변수들을 모두 사용할 것 인가? 변수를 어떻게 조작할 것 인가? 등 데이터에 대한 충분한 분석이 바탕이 되어야 모델의 하이퍼파리미터 튜닝이나 앙상블이 조금 더 유의미한 결과를 도출할 것이다. 선택한 모델의 성능이 비슷하다면, pycaret처럼 앙상블이 도움이 될 수 있다.
6. 개선사항
비록 종료된 대회이며 오픈 소스들이 많이 존재했지만, 개인적으로 아쉽다고 느낀 부분들이 있다.
우선, 아직 머신러닝에 대해 공부한지 얼마 되지 않아 알고 있는 모델이 너무 적다는 점이다. 실제로, pycaret에서 고른 상위 3가지 모델을 모두 처음들었다. 이 모델들이 어떤 원리로 동작하는지 모르지만, 단순히 성능이 좋다고 나와 데이터에 적용을 시켰다. 데이터를 보고 생각했던 모델이 없어서 조금 당황스러웠고 아쉬웠다. 경험과 공부를 통해 여러 모델의 구현방식을 알아보는 것이 좋을 것 같다.
두번째로, 데이터에 대한 미숙함이다. 새로운 ‘거주율’이라는 변수를 추가하였지만, 모든 변수들을 훈련에 사용한 것은 조금 아쉽다고 생각한다. 또한, 단순히 결측치들에 대한 값을 0으로 준 점이나 모델의 특성을 고려하지 않은 채 데이터 전처리를 진행했다고 생각한다.
마지막으로, 과적합, 편향 등에 대한 고려를 하였는가 이다. 대회이다 보니 점수에만 초점을 맞추어 진행하였다. 모델의 각 파라미터들은 과적합을 조절 할 수 있지만, 각 하이퍼 파라미터들을 거의 고려하지 않았다.
결론적으로, 첫 구현이며 대회이다 보니 부족한 점이 많았으며 알고 있는것이 생각보다 적었다. 생각처럼 강의에서 배운 내용을 적용시키는 것이 어려웠다. 다음은 경진대회를 진행하면서 느낀 성능을 좋게 하는 방법이다.
다음과 같은 5가지 순서를 반복해서 성능을 꾸준히 올려야 한다.
1.
데이터 분석, EDA
2.
인사이트의 얻기
3.
Feature Engineering
4.
모델 개발
5.
모델 평가 및 피쳐 성능 확인
위의 과정이 제대로 진행되도록 대회를 진행했어야 했는데 아쉬움이 남았다.