데이콘 대회 참여 - 02 GBM을 활용한 머신러닝 예제
Page content
공지
제 수업을 듣는 사람들이 계속적으로 실습할 수 있도록 강의 파일을 만들었습니다. 늘 도움이 되기를 바라며. 참고했던 교재 및 Reference는 꼭 확인하셔서 교재 구매 또는 관련 Reference를 확인하시기를 바랍니다.
개요
- 본 예제에서는 제주 빅데이터 경진대회에서 제공하는 베이스라인 코드를 살려서 작성하였다.
- 처음 대회를 입문하는 데 있어서, 빠르게 제출하는 것에 의미부여를 하기 바란다.
- 다만, 데이터를 불러오는 영역 및 머신러닝 모형 알고리즘만 조금 수정하였다.
- 향후 매일 업데이트 하면서 일종의 가이드라인이 되었으면 좋겠다.
I. 빅쿼리 연동
- 지난 시간에 데이콘에서 내려받은 데이터를 빅쿼리에 넣는 작업을 진행하였다.
- 빅쿼리에 저장된 데이터를 구글 코랩으로 불러오려면 다음과 같이 진행한다.
(1) 사용자 계정 인증
구글 코랩을 사용해서 인증 절차를 밟도록 한다. 아래 소스코드는 변경시키지 않는다. 아래 절차대로 진행하면 된다. Gmail
인증 절차와 비슷하다.
from google.colab import auth
auth.authenticate_user()
print('Authenticated')
Authenticated
(2) 데이터 불러오기
- 데이터를 불러오는 데, 간단한 실습을 위해 상위
1000
개의 데이터만 불러오는 작업을 실시한다.
from google.cloud import bigquery
from tabulate import tabulate
import pandas as pd
project_id = 'your_project_id'
client = bigquery.Client(project=project_id)
train = client.query('''
SELECT
*
FROM `your_project_id.jeju_data_ver1.201901_202003_train`
LIMIT 1000
''').to_dataframe()
(3) 데이터 시각화 하기
pandas_profiling
을 통해서 간단하게 확인하도록 한다.- 먼저 구글 코랩 내에서
pandas_profiling
을 확인하기 위해master.zip
을 설치한다. - 설치가 끝나면 구글코랩에서 런타임 다시 시작 한다.
!pip install https://github.com/pandas-profiling/pandas-profiling/archive/master.zip
Collecting https://github.com/pandas-profiling/pandas-profiling/archive/master.zip
[?25l Downloading https://github.com/pandas-profiling/pandas-profiling/archive/master.zip
.
.
.
Successfully installed confuse-1.3.0 htmlmin-0.1.12 imagehash-4.1.0 pandas-profiling-2.8.0 phik-0.10.0 tangled-up-in-unicode-0.0.6 tqdm-4.46.1 visions-0.4.4
from pandas_profiling import ProfileReport
profile = ProfileReport(train, title='Pandas Profiling Report', explorative=True)
profile.to_file("report.html") # create html file
profile
- 데이터 시각화를 통해서 전처리를 진행하는 것이 순리이다. 그러나, 본 과정에서는
GBM
의 개념과 원리에 집중해야하기 때문에,Raw-Data
로 그대로 적용하도록 한다.
II. GBM의 개요 및 실습
- 부스팅 알고리즘은 여러 개의 약한 학습기(
Weak Learner
)를 순차적으로 학습-예측하면서 잘못 예측한 데이터에 가중치 부여를 통해 오류 개선하며 학습하는 방식.
- 위 그림에서 첫번째 그림과 마지막 그림의 차이점에서 결국 성능입니다.
- 첫번째에서 오분류는 3개가 발생되었지만, 마지막 그림에서는 오분류가 발생하지 않음을 확인할 수 있다.
- 산술적으로 가중치는 다음과 같이 부여할 수 있습니다.
- 첫번째 학습기에 0.3, 두번째 학습기에 0.5, 세번째 학습기에 0.8을 부여합니다.
- 가중치를 업데이트 방법은 경사하강법을 이용합니다.
- 오류값은 실제값 - 예측값이다.
- 경사하강법의 기본 원리는 반복 수행을 통해 오류를 최소화할 수 있도록 가중치의 업데이트 값을 도출하는 기법 정도로 이해하면 좋습니다.
(1) 머신러닝 패키지 Loading
- 종속변수와 독립변수로 구분할 필요가 있다.
import pandas as pd
import numpy as np
import sklearn
from sklearn.ensemble import GradientBoostingRegressor
from sklearn.preprocessing import LabelEncoder
print('Pandas : %s'%(pd.__version__))
print('Numpy : %s'%(np.__version__))
print('Scikit-Learn : %s'%(sklearn.__version__))
!python --version
Pandas : 1.0.5
Numpy : 1.18.5
Scikit-Learn : 0.22.2.post1
Python 3.6.9
(2) 날짜 데이터 전처리
- 데이터 전처리 기본함수 작성
- 우선 날짜 처리 진행
year
&month
로 구분한다.
def grap_year(data):
data = str(data)
return int(data[:4])
def grap_month(data):
data = str(data)
return int(data[4:])
# 날짜 처리
data = train.copy()
data = data.fillna('')
print(data['REG_YYMM'].head())
0 201901
1 201901
2 201901
3 201901
4 201902
Name: REG_YYMM, dtype: int64
data['year'] = data['REG_YYMM'].apply(lambda x: grap_year(x))
print(data[['REG_YYMM', 'year']].head())
REG_YYMM year
0 201901 2019
1 201901 2019
2 201901 2019
3 201901 2019
4 201902 2019
data['month'] = data['REG_YYMM'].apply(lambda x: grap_month(x))
print(data[['REG_YYMM', 'year', 'month']].head())
REG_YYMM year month
0 201901 2019 1
1 201901 2019 1
2 201901 2019 1
3 201901 2019 1
4 201902 2019 2
data = data.drop(['REG_YYMM'], axis=1)
(3) 시군구 컬럼 제거
submission
제출 파일 목록에서시/도
는 해당되나,시군구
항목은 해당되지 않는다.- 따라서, 해당 컬럼은 삭제한다.
# 데이터 정제
df = data.drop(['CARD_CCG_NM', 'HOM_CCG_NM'], axis=1)
columns = ['CARD_SIDO_NM', 'STD_CLSS_NM', 'HOM_SIDO_NM', 'AGE', 'SEX_CTGO_CD', 'FLC', 'year', 'month']
df = df.groupby(columns).sum().reset_index(drop=False)
(4) 라벨 인코딩
- 사이킷런의
ML
알고리즘은 결측치가 허용되지 않는다. - 사이킷런의 머신러닝 알고리즘은 문자열 값을 입력 값으로 허용하지 않는다.
- 따라서, 이를 숫자형으로 변환해야 한다.
- 이를 데이터 인코딩이라 부른다.
- 데이터 인코딩에는 크게 두가지 있다.
- 레이블 인코딩 VS. 원-핫 인코딩
- 레이블 인코딩은 카테고리 피처를 코드형 숫자 값으로 변환한다.
- 이 때, 일괄적으로 숫자로 변환이 되면 선형회귀와 같은 ML 알고리즘에는 적용하지 않는다. 이유는 숫자 값의 경우 크고 작음에 대한 특성이 작용한다.
- 그러나, 본 예제에서는 주로 트리 계열을 알고리즘을 사용할 것이기 때문에 크게 상관은 없다.
- 원핫 인코딩은 피처 값의 유형에 따라 새로운 피처를 추가해 고유 값에 해당하는 칼럼에만 1을 표시하고 나머지 칼럼에는 0을 표시한다.
- 본 실습에서는 주로 라벨 인코딩만 사용하고 진행해본다.
# 인코딩
dtypes = df.dtypes
encoders = {}
for column in df.columns:
if str(dtypes[column]) == 'object':
encoder = LabelEncoder()
encoder.fit(df[column])
encoders[column] = encoder
df_num = df.copy()
for column in encoders.keys():
encoder = encoders[column]
df_num[column] = encoder.transform(df[column])
(5) 변수 선택 및 모델 구축
- 이용 고객수, 건수, 이용금액은 사실상 같이 움직이는 변수 들이다.
- 그에 해당하는 변수들은 제거한다.
- 훈련데이터와 독립변수와 종속변수를 구분하여 저장한다.
np.loglp
는 자연로그를 취해주는 것을 의미한다.
# feature, target 설정
train_num = df_num.sample(frac=1, random_state=0)
train_features = train_num.drop(['CSTMR_CNT', 'AMT', 'CNT'], axis=1)
train_target = np.log1p(train_num['AMT'])
(6) 하이퍼 파라미터 및 튜닝
- 1차적으로 모형은
GBM
만 사용한다. - 이 때, 보통 모형 알고리즘에 대한 하이퍼 파라미터 튜닝도 같이 진행하게 된다.
- n_estimators: weak learner가 순차적으로 오류를 보정함. 개수가 많아지면 성능이 좋아지지만, 수행시간이 오래 발생될 수 있음.
- learning_rate: 오차를 얼마나 강하게 보정할 것인지 제어
- max_depth: 복잡도를 너무 높이지 말고 트리의 깊이가 5보다 깊어지지 않게 함.
# 훈련
gbm = GradientBoostingRegressor(n_estimators=4000);
gbm.fit(train_features, train_target)
GradientBoostingRegressor(alpha=0.9, ccp_alpha=0.0, criterion='friedman_mse',
init=None, learning_rate=0.1, loss='ls', max_depth=3,
max_features=None, max_leaf_nodes=None,
min_impurity_decrease=0.0, min_impurity_split=None,
min_samples_leaf=1, min_samples_split=2,
min_weight_fraction_leaf=0.0, n_estimators=4000,
n_iter_no_change=None, presort='deprecated',
random_state=None, subsample=1.0, tol=0.0001,
validation_fraction=0.1, verbose=0, warm_start=False)
(7) 예측 템플릿 작성
- 예측 템플릿을 작성한다.
from itertools import product
# 예측 템플릿 만들기
CARD_SIDO_NMs = df_num['CARD_SIDO_NM'].unique()
STD_CLSS_NMs = df_num['STD_CLSS_NM'].unique()
HOM_SIDO_NMs = df_num['HOM_SIDO_NM'].unique()
AGEs = df_num['AGE'].unique()
SEX_CTGO_CDs = df_num['SEX_CTGO_CD'].unique()
FLCs = df_num['FLC'].unique()
years = [2020]
months = [4, 7]
comb_list = [CARD_SIDO_NMs, STD_CLSS_NMs,HOM_SIDO_NMs, AGEs, SEX_CTGO_CDs, FLCs, years, months]
temp = np.array(list(product(*comb_list)))
temp = pd.DataFrame(data=temp, columns=train_features.columns)
- 예측된 결과를 데이터프레임에 제출한다.
# 예측
pred = gbm.predict(temp)
pred = np.expm1(pred)
temp['AMT'] = np.round(pred, 0)
temp['REG_YYMM'] = temp['year']*100 + temp['month']
temp = temp[['REG_YYMM', 'CARD_SIDO_NM', 'STD_CLSS_NM', 'AMT']]
temp = temp.groupby(['REG_YYMM', 'CARD_SIDO_NM', 'STD_CLSS_NM']).sum().reset_index(drop=False)
- 라벨 인코딩 했던 부분을 제출을 위해 다시 디코딩하는 작업을 진행한다.
# 디코딩
temp['CARD_SIDO_NM'] = encoders['CARD_SIDO_NM'].inverse_transform(temp['CARD_SIDO_NM'])
temp['STD_CLSS_NM'] = encoders['STD_CLSS_NM'].inverse_transform(temp['STD_CLSS_NM'])
print(temp.head())
(8) Submission 파일 작업 및 내보내기
submission = client.query('''
SELECT
*
FROM `your_project_id.jeju_data_ver1.submission`
''').to_dataframe()
submission = submission.drop(['AMT'], axis=1)
submission = submission.merge(temp, left_on=['REG_YYMM', 'CARD_SIDO_NM', 'STD_CLSS_NM'], right_on=['REG_YYMM', 'CARD_SIDO_NM', 'STD_CLSS_NM'], how='left')
submission['AMT'] = submission['AMT'].fillna(0)
print(submission.head())
id REG_YYMM CARD_SIDO_NM STD_CLSS_NM AMT
0 0 202004 강원 건강보조식품 소매업 0.0
1 1 202004 강원 골프장 운영업 238823.0
2 2 202004 강원 과실 및 채소 소매업 0.0
3 3 202004 강원 관광 민예품 및 선물용품 소매업 0.0
4 4 202004 강원 그외 기타 분류안된 오락관련 서비스업 0.0
submission.to_csv('submission.csv', encoding='utf-8-sig', index=False)
III. What’s next
- 다음 시간에는
Feature Enginnering
을 활용하여 모형을 업데이트 해본다. - 다음 시간에는 평가 측정 지표인
RMSLE
의 함수에 대해 설명한다.