요약 :
# 데이터 분석
import pandas as pd
import numpy as np
# 데이터 분석(시각화)
import matplotlib.pyplot as plt
import seaborn as sns
# ML 모델링
from sklearn.model_selection import train_test_split
import skimage
import shap
import xgboost
# RMSE
from sklearn.metrics import mean_squared_error
train_data = pd.read_csv("./dataset/train.csv")
train_data
test_data = pd.read_csv("./dataset/test.csv")
test_data
# 결측치 확인
train_data.isna().sum()
# 결측치 0으로 채우기
train_data=train_data.fillna(0)
train_data.isna().sum()
• 값이 어떤 데이터 타입의 값이 들어가 있는지 확인해줍니다.
print(train_data.columns)
print(train_data.dtypes)
print("행 열 :", train_data.shape)
• Bool 변수를 one-hot encoding을 통해서 0,1값으로 바꿔줍니다.
train_data["IsHoliday"] = train_data["IsHoliday"].astype(int)
• Date데이터의 연,월,일의 값이 object형태이기 때문에 값을 바꿔줍니다.
# Date데이터의 연월일을 변환
day =[]
month=[]
year=[]
for i in range(len(train_data["Date"])):
day.append(int(train_data.iloc[i]["Date"][0:2]))
month.append(int(train_data.iloc[i]["Date"][3:5]))
year.append(int(train_data.iloc[i]["Date"][6:]))
train_data["day"]=day
train_data["month"] = month
train_data["year"] = year
• pandas에 자동으로 histogram을 만들어 주는 함수인 .hist를 이용해서 histogram을 만들어줍니다.
train_data.hist(figsize=(30,20))
• 이제 데이터의 값의 분포를 describe함수를 통해 숫자로 확인합니다. 각 값이 mean, std, min을 살펴 분포가 어떻게 되어 있는지 파악합니다.
train_data.describe()
# id 는 제외하고 정규화 진행
norm = train_data.drop(['id','Date', 'Weekly_Sales'],axis=1)
# z-정규화( x-평균/표준편차)
train_data_normed = (norm- norm.mean())/norm.std()
train_data_normed
train_data_normed.hist(figsize=(30,20))
analysis = pd.merge(train_data_normed, train_data['Weekly_Sales'],
left_index = True, right_index=True)
# 선형성 확인
plt.figure(figsize=(16,16))
sns.heatmap(analysis.corr(), linewidths=.5, cmap = 'Blues', annot=True)
#pairplot with Seaborn
sns.pairplot(analysis,hue='Weekly_Sales')
plt.show()
train_y = train_data['Weekly_Sales']
train_x = train_data_normed
#drop(['IsHoliday','year'],axis=1)
#.drop(['year','Promotion1','IsHoliday','Promotion4','Promotion2','Fuel_Price'],axis=1)
print(train_x.shape, train_y.shape)
Boosting이란? 앙상블 기법중 하나로오분류된 데이터에 초점을 맞추어 더 많은 가중치를 주는 방식입니다.
초기에는 모든 데이터가 동일한 가중치를 가지지만, 각 round가 종료된 후 가중치와 중요도를 계산하며, 복원 추출 시에 가중치 분포를 더 많이 고려합니다.
Boosting 기법에는 여러가지 기법이 있지만 그 중에서 Gradient Boosting 기법 중 하나인 XGboost 기법을 이용해서 모델링을 진행해주었습니다.
Gradient Boosting이란?Round의 합성 분류기의 데이터 별 오류를 예측하는 약한 분류기를 학습하는 방식으로 쉽게 말해 줄일 수 있는 오차를 학습하여 오차를 줄여나가는 방식입니다.
xgb_model= xgboost.XGBRegressor(learning_rate=0.2,
n_estimators=100,
max_depth=8,
min_child_weight=1,
gamma=0,
colsample_bytree = 0.7,
subsample=0.75,
objective= 'reg:squarederror',
nthread=-1,
reg_alpha = 1e-5,
scale_pos_weight=1,
seed=2011)
xgb_model.fit(train_x,train_y)
predict = xgb_model.predict(train_x )
print("RMSE: {}".format((mean_squared_error(predict, train_y)**0.5)))
RMSE: 30367.758432242645
xgboost.plot_importance(xgb_model, importance_type = 'gain', title='gain', xlabel='', grid=False)
xgboost.plot_importance(xgb_model, importance_type = 'cover', title='cover', xlabel='', grid=False)
xgboost.plot_importance(xgb_model, importance_type = 'weight', title='weight', xlabel='', grid=False)
xgboost.plot_importance(xgb_model, importance_type = 'total_gain', title='total_gain', xlabel='', grid=False)
xgboost.plot_importance(xgb_model, importance_type = 'total_cover', title='total_cover', xlabel='', grid=False)
plt.tight_layout()
plt.show()
import shap
explainer = shap.TreeExplainer(xgb_model) # 트리 모델 Shap Value 계산 객체 지정
shap_values = explainer.shap_values(train_x)
shap.initjs() # 자바스크립트 초기화 (그래프 초기화)
shap.force_plot(explainer.expected_value, shap_values[1,:], train_x.iloc[1,:])
# 첫 번째 검증 데이터 인스턴스에 대해 Shap Value를 적용하여 시각화
# 빨간색이 영향도가 높으며, 파란색이 영향도가 낮음
shap.summary_plot(shap_values, train_x)
# 정확도 향상
from sklearn.model_selection import GridSearchCV
params = {
'max_depth':range(3,10,3),
'min_child_weight':range(1,6,2),
'n_estimators':range(100,1100,100)
}
grid_xgb = GridSearchCV(estimator = xgboost.XGBRegressor(learning_rate=0.1,
n_estimators=1000,
max_depth=5,
min_child_weight=1,
gamma=0,
subsample=0.8,
colsample_bytree=0.8,
objective= 'reg:squarederror',
nthread=-1,
scale_pos_weight=1,
seed=2019),
param_grid = params, n_jobs=-1, cv=10)
grid_xgb.fit(train_x,train_y)
predict=grid_xgb.predict(train_x)
print("RMSE:",mean_squared_error(train_y, predict)**0.5)
print(grid_xgb.best_params_)
from sklearn.model_selection import GridSearchCV
params = {
'gamma':[i/10.0 for i in range(0,5)]
}
grid_xgb = GridSearchCV(estimator = xgboost.XGBRegressor(learning_rate=0.1,
n_estimators=100,
max_depth=3,
min_child_weight=3,
gamma=0,
subsample=0.8,
colsample_bytree=0.8,
objective= 'reg:squarederror',
nthread=-1,
scale_pos_weight=1,
seed=2019),
param_grid = params, n_jobs=-1, cv=10)
grid_xgb.fit(train_x,train_y)
predict=grid_xgb.predict(train_x)
print("RMSE:",mean_squared_error(train_y, predict)**0.5)
print(grid_xgb.best_params_)
from sklearn.model_selection import GridSearchCV
params = {
'colsample_bytree':[i/10.0 for i in range(6,10)],
'subsample':[i/100.0 for i in range(40,80)],
}
grid_xgb = GridSearchCV(estimator = xgboost.XGBRegressor(learning_rate=0.1,
n_estimators=100,
max_depth=3,
min_child_weight=3,
gamma=0,
subsample=0.6,
colsample_bytree=0.74,
objective= 'reg:squarederror',
nthread=-1,
scale_pos_weight=1,
seed=2019),
param_grid = params, n_jobs=-1, cv=10)
grid_xgb.fit(train_x,train_y)
predict=grid_xgb.predict(train_x)
print("RMSE:",mean_squared_error(train_y, predict)**0.5)
print(grid_xgb.best_params_)
from sklearn.model_selection import GridSearchCV
params = {
'subsample':[i/100.0 for i in range(40,80)],
}
grid_xgb = GridSearchCV(estimator = xgboost.XGBRegressor(learning_rate=0.1,
n_estimators=100,
max_depth=3,
min_child_weight=3,
gamma=0,
colsample_bytree = 0.6,
subsample=0.74,
objective= 'reg:squarederror',
nthread=-1,
scale_pos_weight=1,
seed=2019),
param_grid = params,n_jobs=-1, cv=10)
grid_xgb.fit(train_x,train_y)
predict=grid_xgb.predict(train_x)
print("RMSE:",mean_squared_error(train_y, predict)**0.5)
print(grid_xgb.best_params_)
from sklearn.model_selection import GridSearchCV
params = {
'reg_alpha':[1e-5, 1e-2, 0.1, 1, 100]
}
grid_xgb = GridSearchCV(estimator = xgboost.XGBRegressor(learning_rate=0.1,
n_estimators=100,
max_depth=3,
min_child_weight=3,
gamma=0,
colsample_bytree = 0.6,
subsample=0.74,
objective= 'reg:squarederror',
nthread=-1,
scale_pos_weight=1,
seed=2019),
param_grid = params,n_jobs=-1, cv=10)
grid_xgb.fit(train_x,train_y)
predict=grid_xgb.predict(train_x)
print("RMSE:",mean_squared_error(train_y, predict)**0.5)
print(grid_xgb.best_params_, grid_xgb.best_score_)
params = {
'learning_rate':[0.001, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9]
}
grid_xgb = GridSearchCV(estimator = xgboost.XGBRegressor(learning_rate=0.1,
n_estimators=100,
max_depth=3,
min_child_weight=3,
gamma=0,
colsample_bytree = 0.6,
subsample=0.74,
objective= 'reg:squarederror',
nthread=-1,
scale_pos_weight=1,
reg_alpha = 100,
seed=2019),
param_grid = params,n_jobs=-1, cv=10)
grid_xgb.fit(train_x,train_y)
predict=grid_xgb.predict(train_x)
print("RMSE:",mean_squared_error(train_y, predict)**0.5)
print(grid_xgb.best_params_, grid_xgb.best_score_)
import tqdm
best_seed = []
for i in tqdm.notebook.tqdm(range(2019)):
xgb_model=xgboost.XGBRegressor(learning_rate=0.1,
n_estimators=100,
max_depth=3,
min_child_weight=3,
gamma=0,
subsample=0.6,
colsample_bytree=0.74,
objective= 'reg:squarederror',
nthread=-1,
scale_pos_weight=1,
reg_alpha = 100,
seed=i)
xgb_model.fit(train_x,train_y)
predict=xgb_model.predict(train_x)
best_seed.append(((mean_squared_error(predict, train_y)**0.5),i))
best_seed.sort()
print(best_seed[0])
xgboost.plot_importance(xgb_model, importance_type = 'gain', title='gain', xlabel='', grid=False)
xgboost.plot_importance(xgb_model, importance_type = 'cover', title='cover', xlabel='', grid=False)
xgboost.plot_importance(xgb_model, importance_type = 'weight', title='weight', xlabel='', grid=False)
xgboost.plot_importance(xgb_model, importance_type = 'total_gain', title='total_gain', xlabel='', grid=False)
xgboost.plot_importance(xgb_model, importance_type = 'total_cover', title='total_cover', xlabel='', grid=False)
plt.tight_layout()
plt.show()
#전처리
test_data["IsHoliday"] = test_data["IsHoliday"].astype(int)
test_data=test_data.fillna(0)
# Date데이터의 연월일을 변환
day =[]
month=[]
year=[]
for i in range(len(test_data["Date"])):
day.append(int(test_data.iloc[i]["Date"][0:2]))
month.append(int(test_data.iloc[i]["Date"][3:5]))
year.append(int(test_data.iloc[i]["Date"][6:]))
test_data["day"]=day
test_data["month"] = month
test_data["year"] = year
# 필요없는 데이터 제외하고
normed = test_data.drop(['id','Date','year', 'Fuel_Price', 'IsHoliday','Promotion2'],axis=1)
#drop(['id','Date','year','Promotion1','IsHoliday','Promotion4','Promotion2'],axis=1)
# z-정규화
test_data_normed = (normed- normed.mean())/normed.std()
test_data_normed=test_data_normed.fillna(0)
test_data_normed
predict = xgb_model.predict(test_data_normed)
sample_submission = pd.read_csv('./dataset/sample_submission.csv')
sample_submission['Weekly_Sales'] = predict
sample_submission.to_csv('submission.csv',index = False)
sample_submission.head()
위와 같은 코드로 30번 정도 제출하여, Public Score 151등으로 마무리 했다. 아쉬운 등수인데, 마지막 제출정도 코드상의 문제점을 파악할 수 있었다. 바로 Train Set에서는 총 여러해의 정보가 활용되었는데, Test Set에서는 랜덤하게 나누어져있지않고 특정 해의 특정 월정보가 적혀있었다. 따라서 정규화를 진행하면 해당 부분에 대한 데이터가 없어지는 오류가 있었는데, 테스트 데이터에 대한 분석을 아예 진행하지 않고 진행해서 해당 부분에 대한 오류가 발생한 것 같았다. 물론 테스트 데이터를 모델에 활용하면 안되겠지만, 적어도 분포가 Test와 Train Data가 다른지 아닌지정도는 파악해야될 것 같다는 생각이 들었다. Public Score는 151등, Private Score는 172등 정도로 전체 700팀 정도에서 상위 25%안에 드는 성적을 거둘 수 있었던 것 같다.