
지루한 이론과 설치가 끝나고 드디어 실습이다.
이번 글에서는 sklearn에서 제공하는 보스턴 주택 가격 데이터를 이용해 xgboost 모델을 학습시키고 예측하기까지 해 볼 예정이다.
개발 환경
설치가 완료된 이상 대부분 개발환경의 제약은 받지 않으나 내가 개발한 환경은 다음과 같다.
- AWS Linux
- python 3.6.10
준비하기
- 이전 글에서 설치한 xgboost용 python을 활성화해준다.
source <설치경로>/bin/activate

- sklearn, pandas, matplotlib, graphviz를 설치하지 않은 경우 설치해준다.
pip install sklearn pandas matplotlib graphviz
앞에 sudo를 붙이거나 가상 환경을 활성화시키지 않은 상태로 설치하는 실수는 하지 말자.

실습하기
from sklearn.datasets import load_boston | |
boston = load_boston() | |
print(boston.keys()) | |
print(boston.data.shape) | |
print(boston.feature_names) | |
print(boston.DESCR) | |
import pandas as pd | |
data = pd.DataFrame(boston.data) | |
data.columns = boston.feature_names | |
data.head() | |
data['PRICE'] = boston.target | |
X, y = data.iloc[:,:-1],data.iloc[:,-1] | |
data_dmatrix = xgb.DMatrix(data=X,label=y) | |
from sklearn.model_selection import train_test_split | |
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=123) | |
xg_reg = xgb.XGBRegressor(objective ='reg:linear', colsample_bytree = 0.3, learning_rate = 0.1, max_depth = 5, alpha = 10, n_estimators = 10) | |
xg_reg.fit(X_train,y_train) | |
preds = xg_reg.predict(X_test) | |
rmse = np.sqrt(mean_squared_error(y_test, preds)) | |
print("RMSE: %f" % (rmse)) | |
params = {"objective":"reg:linear",'colsample_bytree': 0.3,'learning_rate': 0.1,'max_depth': 5, 'alpha': 10} | |
cv_results = xgb.cv(dtrain=data_dmatrix, params=params, nfold=3,num_boost_round=50,early_stopping_rounds=10,metrics="rmse", as_pandas=True, seed=123) | |
cv_results.head() | |
print((cv_results["test-rmse-mean"]).tail(1)) | |
import matplotlib.pyplot as plt | |
xgb.plot_tree(xg_reg,num_trees=9) | |
plt.rcParams['figure.figsize'] = [40, 10] | |
plt.show() | |
xgb.plot_importance(xg_reg) | |
plt.rcParams['figure.figsize'] = [8, 10] | |
plt.show() |
Full 코드를 한줄한줄 실행해보며 이해해보는 것을 추천한다.
데이터 준비하기
우리가 사용할 데이터는 sklearn에서 제공해주는 보스턴의 주택 가격 데이터이다.
이 데이터를 통해 주택 가격을 예측해보는 xgboost 모델을 만들어보자.
from sklearn.datasets import load_boston
boston = load_boston()
위 코드를 입력하면 저장된 서버에서 데이터를 읽어와 boston이라는 변수에 저장해준다.
데이터 탐색하기
가져온 데이터가 어떻게 생겼는지 확인해보자.
읽어온 데이터는 dictionary(딕셔너리) 형태이기 때문에 keys() 메서드로 키를 확인할 수 있다.
print(boston.keys())
>>> dict_keys(['data', 'target', 'feature_names', 'DESCR'])
boston.data.shape이라는 값을 통해 데이터 셋의 사이즈를 확인해볼 수 있다.
print(boston.data.shape)
>>> (506, 13)
(506, 13)을 리턴하는 것을 확인할 수 있는데,
506개의 데이터(주택수)와 13개의 칼럼(특성)으로 이루어졌다는 것을 의미한다.
feature_names를 통해 피쳐의 이름을 가져올 수 있다.
print(boston.feature_names)
>>> ['CRIM' 'ZN' 'INDUS' 'CHAS' 'NOX' 'RM' 'AGE' 'DIS' 'RAD' 'TAX' 'PTRATIO' 'B' 'LSTAT']
이름 가지고는 잘 모르겠으니 DESCR으로 설명을 보자
print(boston.DESCR)
>>>
Boston House Prices dataset
===========================
Notes
------
Data Set Characteristics:
:Number of Instances: 506
:Number of Attributes: 13 numeric/categorical predictive
:Median Value (attribute 14) is usually the target
:Attribute Information (in order):
- CRIM per capita crime rate by town
- ZN proportion of residential land zoned for lots over 25,000 sq.ft.
- INDUS proportion of non-retail business acres per town
- CHAS Charles River dummy variable (= 1 if tract bounds river; 0 otherwise)
- NOX nitric oxides concentration (parts per 10 million)
- RM average number of rooms per dwelling
- AGE proportion of owner-occupied units built prior to 1940
- DIS weighted distances to five Boston employment centres
- RAD index of accessibility to radial highways
- TAX full-value property-tax rate per $10,000
- PTRATIO pupil-teacher ratio by town
- B 1000(Bk - 0.63)^2 where Bk is the proportion of blacks by town
- LSTAT % lower status of the population
- MEDV Median value of owner-occupied homes in $1000's
:Missing Attribute Values: None
:Creator: Harrison, D. and Rubinfeld, D.L.
This is a copy of UCI ML housing dataset.
http://archive.ics.uci.edu/ml/datasets/Housing
This dataset was taken from the StatLib library which is maintained at Carnegie Mellon University.
The Boston house-price data of Harrison, D. and Rubinfeld, D.L. 'Hedonic
prices and the demand for clean air', J. Environ. Economics & Management,
vol.5, 81-102, 1978. Used in Belsley, Kuh & Welsch, 'Regression diagnostics
...', Wiley, 1980. N.B. Various transformations are used in the table on
pages 244-261 of the latter.
The Boston house-price data has been used in many machine learning papers that address regression
problems.
**References**
- Belsley, Kuh & Welsch, 'Regression diagnostics: Identifying Influential Data and Sources of Collinearity', Wiley, 1980. 244-261.
- Quinlan,R. (1993). Combining Instance-Based and Model-Based Learning. In Proceedings on the Tenth International Conference of Machine Learning, 236-243, University of Massachusetts, Amherst. Morgan Kaufmann.
- many more! (see http://archive.ics.uci.edu/ml/datasets/Housing)
Attribute Information 아래에 각 칼럼명에 대한 설명이 나와 있다. 자세한 내용은 직접 번역해서 읽어보길..
데이터 변환하기
학습을 시키기 위해서는 내가 필요한 데이터 형태로 변환을 해주어야 한다.
XGBoost에서는 DMatric형태로 데이터를 입력할 수 있는데, 이는 메모리에 효율적이고 학습에 빠르게 구현되어있다고 한다. 예전에 강의 들을 때 triplet 표현식으로 구현되어있다고 들었었는데, 공홈에서는 그런 내용이 안 보인다.
우선 Pandas dataframe 형태로 변환해보자.
import pandas as pd
data = pd.DataFrame(boston.data)
data.columns = boston.feature_names
그리고 출력
data.head()
>>> (다음 표)

아까 보았던 칼럼명들과 그에 해당하는 값이 있다.
그런데 정작 예측할 가격이 없다. 이는 boston.target에 있으니, 이 값을 한 개의 칼럼으로 추가해주자.
data['PRICE'] = boston.target
info() 메서드를 통해서 데이터 프레임의 각 값이 어떤 타입을 사용하고 있는지 확인할 수 있다.
data.info()
>>>
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 506 entries, 0 to 505
Data columns (total 14 columns):
CRIM 506 non-null float64
ZN 506 non-null float64
INDUS 506 non-null float64
CHAS 506 non-null float64
NOX 506 non-null float64
RM 506 non-null float64
AGE 506 non-null float64
DIS 506 non-null float64
RAD 506 non-null float64
TAX 506 non-null float64
PTRATIO 506 non-null float64
B 506 non-null float64
LSTAT 506 non-null float64
PRICE 506 non-null float64
dtypes: float64(14)
memory usage: 55.4 KB
우리가 예측할 가격을 포함해서 모든 칼럼이 float64로 되어있다.
describe() 메서드를 통해 값들의 대략적인 통계를 보자.
data.describe()
>>> 다음표

XGBoost에 들어갈 인풋 데이터를 준비할 때 주의할 점은 categorical value를 onehot 인코딩을 통해서 직접 변환해주어야 하는데, 이 예제에서는 해당사항이 없다.
추가적인 정보로 xgboost는 null(NA) 값을 내부적으로 처리해주는 로직이 있어 별도로 처리하지 않아도 된다.(권장되는지는 모르겠다.)
이제 DMatrix형태로 변환해보자.
import xgboost as xgb
from sklearn.metrics import mean_squared_error
import pandas as pd
import numpy as np
필요 모듈들을 임포트 시키고
X, y = data.iloc[:,:-1],data.iloc[:,-1]
X와 y로 나눈 뒤
data_dmatrix = xgb.DMatrix(data=X,label=y)
dmatrix로 변환해준다.
학습하기
이제 학습을 시킬 차례다. 그런데 위에서 언급한 말을 정정해야 할 것 같다.
XGBoost에서는 DMatric형태로 데이터를 입력할 수 있는데,
XGBoost에서는 DMatric형태나 sklearn에서 지원하는 형태로 데이터를 입력할 수 있다.
정정한 이유는 xgboost가 sklearn estimate wrapper 형태로'도' 지원되기 때문이다.
다만, 이 형태로 학습을 시킬 때의 속도와 메모리 효율성은 DMatrix일 때보다 떨어진다.
우리는 간단한 예제 이기 때문에 sklearn wrapper 형태의 api를 사용해볼 예정이다.
우선 train, test 셋을 80:20 비율로 나누고,
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=123)
우리가 예측할 범위는 (0~무한대)인 특정 값이므로 regressor가 어울리니 regressor를 생성해준다.
(파라미터에 대한 설명은 이글 참고)
xg_reg = xgb.XGBRegressor(objective ='reg:linear', colsample_bytree = 0.3, learning_rate = 0.1, max_depth = 5, alpha = 10, n_estimators = 10)
그리고 fit() 메서드를 호출해 학습시켜준다.
xg_reg.fit(X_train,y_train)
예측하기
학습이 완료되었으면 이제 test 데이터로 예측을 해보자.
precit 메서드에 테스트 데이터를 넣어 호출하면 예측치가 나온다.
preds = xg_reg.predict(X_test)
실제 값과 얼마나 차이가 날까? RMSE로 측정해보자.
rmse = np.sqrt(mean_squared_error(y_test, preds))
print("RMSE: %f" % (rmse))
>>> RMSE: 10.569356
음.. 10.5 정도가 나왔다. RMSE가 낮으면 더 좋은 모델인데, 엄청 좋은 것 같진 않다.
xgb는 cross validation을 기본적으로 제공해주니 더 좋은 모델을 다시 한번 만들어 보자
Cross Validation으로 학습하고 예측 결과 비교하기
우선 cv로 학습은 다음과 같이 하면 된다.
(파라미터에 대한 설명은 이글 참고)
params = {"objective":"reg:linear",'colsample_bytree': 0.3,'learning_rate': 0.1,'max_depth': 5, 'alpha': 10}
cv_results = xgb.cv(dtrain=data_dmatrix, params=params, nfold=3,num_boost_round=50,early_stopping_rounds=10,metrics="rmse", as_pandas=True, seed=123)
cv결과는 cv_results에 매 스탭마다 저장되어있다.
확인해보자.
cv_results.head()
>>> (아래 표)

이런 식으로 모두 저장되는데 마지막에 저장된 test-rmse-mean이 우리가 확인해볼 결과이다.
마지막 값을 확인해보자.
print((cv_results["test-rmse-mean"]).tail(1))
>>> 49 3.975679
>>> Name: test-rmse-mean, dtype: float64
약 4.0 이 나왔다! 10.5보다 훨씬 개선된 결과이다!
모델 시각화하기
모델 시각화를 하기 위해서는 matplotlib이 설치되어있어야 한다.
tree 시각화는 다음과 같은 코드로 할 수 있다.
import matplotlib.pyplot as plt
xgb.plot_tree(xg_reg,num_trees=0)
plt.rcParams['figure.figsize'] = [40, 10]
plt.show()
>>> (다음 그림)

Boostring 방식으로 학습했기 때문에, step 마다 하나의 tree가 생성된다.
즉 위와 비슷한 tree가 step 수만큼 더 있는 것이다.
num_trees=0 이 부분을 수정하면 다른 step에 생성된 tree들도 확인해볼 수 있다.
다음으로 feature importance 확인하기.
graphviz가 설치되어있어야 한다.
xgb.plot_importance(xg_reg)
plt.rcParams['figure.figsize'] = [10, 10]
plt.show()
>>> (다음 그림)

위로 갈수록 feature의 중요도가 높고 아래로 갈수록 중요도가 낮다.
100%는 아니지만 xgb에서 중요한 feature가 다른 모델에서도 중요한 경우가 많다.
xgb는 이렇게 간단하게 시각화하고 결과를 뽑을 수 있기에,
초벌 모델링을 xgb로 하고 중요한 feature를 확인하는데 쓰기도 한다.
이상으로 XGBoost tutorial을 진행해보았다.
다음 글에서는 실전용 데이터로 학습과 시행착오들을 어떻게 겪어 나가는지 과정을 포스팅해 볼 예정이다.
Reference
'ML | DL | Big data > ML' 카테고리의 다른 글
VAR(Vector Auto Regression)을 이용한 다변량 시계열 분석 및 예측 (6) | 2020.09.26 |
---|---|
시계열 예측을 지도 학습으로 바꾸는 방법 - Time Series to Supervised Learning with Sliding window (1) | 2020.09.11 |
Python Prophet - 자동차 판매량 시계열 데이터 예측하기(Time Series Forecasting) (3) | 2020.08.28 |
XGBoost (3) - Python 가상 환경에 설치하기 (0) | 2020.07.13 |
XGBoost (2) - Parameter 이해와 현업자의 설정 방법 (2) | 2020.07.09 |
XGBoost (1) - 입문용 예제로 개념 쉽게 이해하기 (0) | 2020.07.08 |
댓글