โ Process Check
์ง๊ธ๊น์ง ์ด์์น์ ๊ฒฐ์ธก์น ๋ฑ์ ์ ๊ฒํ๋ EDA๋ฅผ ๋ง์น ํ, ํ์๋ณ์๋ฅผ ์์ฑํ๋ค.
์ด์ ๋ชจ๋ธ๋ง์ ํตํด ์ ์๋ฏธํ ํ์๋ณ์๋ฅผ ์ ํํ๊ณ , ์ต์ข ๋ชจ๋ธ๋ง์ ํ์ํ ๋ณ์๋ฅผ ์ฑํํ๋ ๊ณผ์ ์ด ๋จ์๋ค.
์ด๋ฅผ ์ํด ์๋์ ๊ฐ์ด LightGBM + K-fold CV + RandomSearch ์ ํ์ฉํ ๋ชจ๋ธ๋ง ๋ฒ ์ด์ค๋ผ์ธ ์ฝ๋๊ฐ ์์ฑ๋์๋ค.
1. ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋ถ๋ฌ์ค๊ธฐ
import numpy as np
import pandas as pd
import lightgbm as lgb
from lightgbm import LGBMRegressor
from sklearn.model_selection import KFold, train_test_split, RandomizedSearchCV
from sklearn.metrics import mean_squared_error, mean_absolute_error
import matplotlib.pyplot as plt
import seaborn as sns
import matplotlib.font_manager as fm
import joblib
import os
โถ๏ธ ํฐํธ ์ค์
#font ์ค๋ฅ ์์
font_list = fm.findSystemFonts()
font_name = None
for font in font_list:
if 'AppleGothic' in font:
font_name = fm.FontProperties(fname=font).get_name()
plt.rc('font', family=font_name)
2. ๋ชจ๋ธ๋ง์ฉ ๋ฐ์ดํฐ ๋ถ๋ฌ์ค๊ธฐ
- ๋ชจ๋ธ๋ง์ ์ํด ์ ์ฒ๋ฆฌ๋ฅผ ์๋ฃํ ๋ฐ์ดํฐ์ ์ ๋ถ๋ฌ์จ๋ค.
# ๋ฐ์ดํฐ ๋ถ๋ฌ์ค๊ธฐ ๋ฐ ์ ์ฒ๋ฆฌ
data = pd.read_csv('./data/๊ณจ๋ชฉ_model์ฉ.csv')
โถ๏ธ X, Y ๋ณ์ ๋ถ๋ฆฌ
- ๋ ๋ฆฝ๋ณ์ : ๋ชจ๋ธ๋ง์ ์ฌ์ฉํ ๋ณ์๋ก, ์ฐ๋, ๋ถ๊ธฐ, ์๊ถ์ฝ๋, ์๊ถ์ฝ๋๋ช , ์๊ฐ๋ ๋ฐ ๋งค์ถ์ ์ ์ธํ ๋๋จธ์ง ๋ณ์
- ์ข ์๋ณ์ : ํธ์์ ๋งค์ถ
# ๋ฐ์ดํฐ ๋ก๋(์ค์ ๋ฐ์ดํฐ์
๊ฐ์ ธ์ค๊ธฐ)
X = data.iloc[:, 5:]
y = data.iloc[:, 0]
3. K-fold ๊ต์ฐจ ๊ฒ์ฆ & lightGBM ๋ชจ๋ธ ์ด๊ธฐ ๋งค๊ฐ๋ณ์ ์ค์
- ๋ฐ์ดํฐ์ ์ ํฌ๊ธฐ๋ฅผ ๊ณ ๋ คํ์ฌ k ๊ฐ์ 10์ผ๋ก ์ค์ ํ์ฌ k-fold ์งํ
- ๊ธฐ๋ณธ์ ์ธ LightGBM ํ๋ผ๋ฏธํฐ ์ค์ ์๋ฃ
# k-ํด๋ ๊ต์ฐจ ๊ฒ์ฆ
num_folds = 10
kf = KFold(n_splits= num_folds, shuffle=True, random_state=42)
# LightGBM ๋ชจ๋ธ ์ด๊ธฐํ
params = {
'boosting_type': 'gbdt',
'objective': 'regression',
'metric': 'rmse',
'num_leaves': 31,
'learning_rate': 0.05,
'feature_fraction': 0.9
}
โถ๏ธ ํน์ฑ ์ค์๋ ๋ฆฌ์คํธ / ๊ฒฐ๊ณผ ์ค์ฝ๋ ๋ฆฌ์คํธ ์์ฑ
- ๋ชจ๋ธ๋ง ๊ฒฐ๊ณผ์ธ (1) ํน์ฑ ์ค์๋์ (2) ํด๋๋ณ ๊ฒฐ๊ณผ ์ค์ฝ์ด๋ฅผ ์ ์ฅํ ๋ฆฌ์คํธ๋ฅผ ์์ฑ
# ํน์ฑ ์ค์๋ ๋ฆฌ์คํธ ์ด๊ธฐํ
feature_importance_list = []
# ๊ฒฐ๊ณผ ์ค์ฝ์ด
rmse_scores = [] # RMSE ์ค์ฝ์ด๋ฅผ ์ ์ฅํ ๋ฆฌ์คํธ
mae_scores = [] # MAE ์ค์ฝ์ด๋ฅผ ์ ์ฅํ ๋ฆฌ์คํธ
best_params_list = [] # ๊ฐ fold์์์ ์ต์ ํ๋ผ๋ฏธํฐ๋ฅผ ์ ์ฅํ ๋ฆฌ์คํธ
โถ๏ธ ๋ฐ์ดํฐ ๋ถํ (train, test)
- train ์ฉ, test ์ฉ ๋ฐ์ดํฐ๋ฅผ ์ฐ์ ๋ถ๋ฆฌ
- (์ดํ, train ๋ฐ์ดํฐ๋ฅผ k-fold์์ ๋ค์ํ๋ฒ Train, validation์ฉ์ผ๋ก ๋๋ ์์ )
# ๋ฐ์ดํฐ ๋ถํ
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
โถ๏ธ RandomSearch ํ์ดํผ ํ๋ผ๋ฏธํฐ ์ข ๋ฅ & ๋ฒ์ ์ค์
- ๋ชจ๋ธ ์ต์ ํ๋ฅผ ์ํ ํ์ดํผ ํ๋ผ๋ฏธํฐ ํ๋
- ์ฃผ์ํ ํ์ดํผ ํ๋ผ๋ฏธํฐ๋ฅผ ์ ์ ํ๊ณ , RandomSearch๋ฅผ ์ํด ๋ฒ์ ์ค์ ํด ์ค
param_dist = {
'objective': ['regression'],
'metric': ['mse'],
'num_leaves': list(range(7, 64)), # 7๋ถํฐ 63๊น์ง
'learning_rate': [0.01, 0.02, 0.03, 0.04, 0.05], #0.01๋ถํฐ 0.05๊น์ง
'n_estimators': list(range(200, 301)), # 200๋ถํฐ 300๊น์ง
'early_stopping_rounds': list(range(40, 51)) # 40๋ถํฐ 50๊น์ง
}
4. K-fold ๊ต์ฐจ ๊ฒ์ฆ 10ํ ์ํ ๐ ๋ชจ๋ธ๋ง๊ณผ ํ์ต ๊ณผ์
- for๋ฌธ์ผ๋ก K-fold์ k๊ฐ ๋งํผ train, valiation ๋ฐ์ดํฐ ์ ์ ๋๋๊ณ
- lightGBM ์ฉ ๋ฐ์ดํฐ ์ ์ ์ง์
- RandomSearchCV() ๋ชจ๋ธ์ ์์ฑํ๊ณ , lightGBMRegressor ๋ชจ๋ธ ์ง์ , ์ธํ ํ ํ์ดํผ ํ๋ผ๋ฏธํฐ ๋ฒ์ ์ง์
- ํ์ต ํ, ์ต์ ํ๋ผ๋ฏธํฐ ๋์ถ
- ์ต์ ํ๋ผ๋ฏธํฐ๋ก ๋ชจ๋ธ ์ฌ์ ํฉ & ์ฌํ์ต
- valid ๋ฐ์ดํฐ๋ก ์์ธก ๋ฐ ํ๊ฐ ๊ฒฐ๊ณผ ๋์ถ, ๋ฆฌ์คํธ์ ์ ์ฅ
# K-Fold ๊ต์ฐจ ๊ฒ์ฆ ์ํ
for train_index, val_index in kf.split(X_train):
# train, validation ๋ฐ์ดํฐ์
ํธ ๋ถ๋ฆฌ(fold ๋ณ)
X_train_kf, X_val_kf = X.iloc[train_index], X.iloc[val_index]
y_train_kf, y_val_kf = y.iloc[train_index], y.iloc[val_index]
# lightGBM์ฉ ๋ฐ์ดํฐ์
์ง์
train_data = lgb.Dataset(X_train_kf, label=y_train_kf)
val_data = lgb.Dataset(X_val_kf, label=y_val_kf, reference=train_data)
# RandomSearch๋ฅผ ์ฌ์ฉํ LightGBM ๋ชจ๋ธ ํ๋ ์ค๋น
random_search = RandomizedSearchCV(
lgb.LGBMRegressor(),
param_distributions=param_dist,
n_iter=10,
scoring='neg_mean_squared_error',
cv=kf,
random_state=42,
n_jobs=-1,
verbose=1
)
# LightGBM ํ๊ฐ์ฉ ๋ฐ์ดํฐ์
์ง์
evals = [(X_train_kf, y_train_kf),(X_val_kf, y_val_kf)]
# RandomSearch(LightGBM) ํ์ต
random_search.fit(X_train_kf, y_train_kf, eval_set = evals, eval_metric='rmse')
# ์ต์ ํ๋ผ๋ฏธํฐ ๋์ถ
best_params = random_search.best_params_
# bst ๋ณ์์ ์ต์ ํ๋ผ๋ฏธํฐ๋ก ๋ชจ๋ธ ์ฌํ์ต
bst = lgb.LGBMRegressor(**best_params)
bst.fit(X_train_kf, y_train_kf,
eval_set=evals,
eval_metric='rmse',
verbose=False)
#Feature importance ๊ณ์ฐ, ๋ฆฌ์คํธ์ ์ ์ฅ
feature_importance = bst.feature_importances_
feature_importance_list.append(feature_importance)
# ๋ชจ๋ธ ํ๊ฐ (RMSE) ๋ฐ ๊ฒฐ๊ณผ ๋ฆฌ์คํธ์ ์ ์ฅ
y_pred = bst.predict(X_val_kf)
mse = mean_squared_error(y_val_kf, y_pred)
rmse = np.sqrt(mean_squared_error(y_val_kf, y_pred))
mae = mean_absolute_error(y_val_kf, y_pred)
rmse_scores.append(rmse)
mae_scores.append(mae)
best_params_list.append(best_params)
โถ๏ธ ๊ต์ฐจ ๊ฒ์ฆ ๊ฒฐ๊ณผ ์ข ํฉ
- np.mead() ์ผ๋ก ํด๋๋ณ ๊ต์ฐจ๊ฒ์ฆ ๊ฒฐ๊ณผ๋ฅผ ํ๊ท ๋ด๊ธฐ
- RMSE, MAE ํ๊ท ๊ฒฐ๊ณผ๊ฐ ํ์ธ
- ํน์ฑ ์ค์๋ ๊ฒฐ๊ณผ๋ ํ๊ท ๋ด๊ธฐ
- ํน์ฑ ์ค์๋ ๊ฒฐ๊ณผ๋ฅผ ํน์ฑ๋ช ๊ณผ ํจ๊ป ์๊ฐํ : ๋ฐ์ดํฐํ๋ ์ ์์ฑ ํ, ๋ด๋ฆผ์ฐจ์ ์ ๋ ฌ
- ๊ฐ์ฅ ๋์ ํน์ฑ ์ค์๋๋ฅผ ๊ฐ์ง ํผ์ณ๋ถํฐ ํ์ธ ๊ฐ๋ฅ
# ๊ต์ฐจ ๊ฒ์ฆ ๊ฒฐ๊ณผ ์ถ๋ ฅ
mean_rmse = np.mean(rmse_scores)
mean_mae = np.mean(mae_scores)
print(f'ํ๊ท RMSE: {mean_rmse}')
print(f'ํ๊ท MAE: {mean_mae}')
# ํน์ฑ ์ค์๋ ํ๊ท ๊ณ์ฐ
average_feature_importance = np.mean(feature_importance_list, axis=0)
# ํน์ฑ ์ด๋ฆ
feature_names = X.columns
# ์ค์๋๋ฅผ ํน์ฑ ์ด๋ฆ๊ณผ ํจ๊ป ์ถ๋ ฅ
feature_importance_df = pd.DataFrame({'Feature': feature_names, 'Importance': average_feature_importance})
feature_importance_df = feature_importance_df.sort_values(by='Importance', ascending=False)
print(feature_importance_df)
# ํน์ฑ ์ค์๋ ์๊ฐํ
plt.figure(figsize=(12, 8))
sns.barplot(x='Importance', y='Feature', data=feature_importance_df)
plt.title('ํน์ฑ ์ค์๋')
plt.show()
โถ๏ธ ์ต์ ํ์ดํผ ํ๋ผ๋ฏธํฐ ํ์ธ ๋ฐ ๋ชจ๋ธ ์ ์ฅ
# K-fold ๊ต์ฐจ ๊ฒ์ฆ์์ ์ป์ ์ต์ ํ๋ผ๋ฏธํฐ ์ถ๋ ฅ(ํด๋๋ณ)
print("K-fold ๊ต์ฐจ ๊ฒ์ฆ์ ์ํ ์ต์ ํ์ดํผํ๋ผ๋ฏธํฐ:")
for i, params in enumerate(best_params_list):
print(f'Fold {i + 1}: {params}')
# ๋ชจ๋ธ ์ ์ฅ
if not os.path.exists("models"):
os.mkdir("models")
model_file = open("models/gm_model.pkl", "wb")
joblib.dump(bst, model_file) # Export
model_file.close()
๐ ์ด๋ ๊ฒ ๊ตฌ์ถํ ๋ฒ ์ด์ค๋ผ์ธ ๋ชจ๋ธ๋ง ์ฝ๋๋ก, ์๊ฐ๋๋ณ ํธ์์ ๋งค์ถ ์์ธก์ ์ํํ๋ฉฐ
์ด๋ฅผ streamlit ๋์๋ณด๋์ ๊ตฌํํ๋ ์์ ์ด ์ด์ด์ง๋ค.
728x90