가장 쉬운 랜덤 포레스트 (Random forest) by 바죠

가장 쉬운 랜덤 포레스트 (Random forest)

먼저 의사결정 나무(decision tree)를 생각한다.
한 번의 분기 선택으로  변수 영역을 두 개로 구분한다. Yes or No를 질문하므로써 상황를 양갈래로 나눌 수 있다.
의사결정 나무(decision tree)에서 질문이나 정답을 담은 네모 상자를 노드(Node)라고 한다. 
맨 처음 분류 기준 (즉, 첫 질문)을 Root Node라고 하고, 맨 마지막 노드를 Terminal Node 혹은 Leaf Node라고 한다.

이는 통계학과 데이터 마이닝, 기계 학습에서 사용하는 예측 모델링 방법 중 하나이다. 
의사 결정 분석에서 결정 나무는 시각적이고 명시적인 방법으로 의사 결정 과정과 결정된 의사를 보여주는데 사용된다.
의사결정 나무(decision tree) 학습법은 데이터 마이닝에서 일반적으로 사용되는 방법론으로, 몇몇 입력 변수를 바탕으로 목표 변수의 값을 예측하는 모델을 생성하는 것을 목표로 한다.
의사결정 나무(decision tree) 학습법은 지도 분류 학습에서 가장 유용하게 사용되고 있는 기법 중 하나이다. 

결과를 해석하고 이해하기 쉽다. 간략한 설명만으로 의사결정 나무(decision tree)를 이해하는 것이 가능하다.
자료를 가공할 필요가 거의 없다. 다른 기법들의 경우 자료를 정규화하거나 임의의 변수를 생성하거나 값이 없는 변수를 제거해야 하는 경우가 있다.
수치 자료와 범주 자료 모두에 적용할 수 있다. 다른 기법들은 일반적으로 오직 한 종류의 변수를 갖는 데이터 셋을 분석하는 것에 특화되어 있다. 
(일례로 신경망 학습은 숫자로 표현된 변수만을 다룰 수 있는 것에 반해 관계식(relation rules)은 오직 명목 변수만을 다룰 수 있다.
화이트박스 모델을 사용한다. 
모델에서 주어진 상황이 관측 가능하다면 불(Bool) 논리를 이용하여 조건에 대해 쉽게 설명할 수 있다. 
(결과에 대한 설명을 이해하기 어렵기 때문에 인공신경망은 대표적인 블랙 박스 모델이다.)
안정적이다. 해당 모델 추리의 기반이 되는 명제가 다소 손상되었더라도 잘 동작한다.
대규모의 데이터 셋에서도 잘 동작한다. 방대한 분량의 데이터를 일반적인 컴퓨터 환경에서 합리적인 시간 안에 분석할 수 있다.
과적합의 문제가 있다. overfitting 문제 발생한다.

의사결정 나무(decision tree)에서 발생하는 과적합 문제를 해결하는 것이 랜덤 포레스트(random forest) 방법이다.
랜덤 포레스트, 이것은 분류, 회귀 분석 등에 사용되는 앙상블 (ensemble) 학습 방법의 일종이다. 
훈련 과정에서 구성한 다수의 의사결정 나무(decision tree)(decision tree, 이것이 나무이다.)로부터 분류 또는 평균 예측치(회귀 분석)를 출력한다.
의사결정 나무(decision tree)는 계층적 접근방식이기 때문에 만약 중간에 오류가 발생한다면 다음 단계로 오류가 계속 전파되는 특성을 가진다.

배깅(Bagging; bootstrap aggregating) 또는 랜덤 노드 최적화(Randomized node optimization)와 같은 랜덤화 기술은 의사결정 나무(decision tree)가 가진 이러한 단점을 극복하고 일반화 성능을 갖도록 한다. 
변수 변환이 필요없는 알고리듬이다. 즉, 전처리 과정이 필요없다. 랜덤 포레스트를 이용해 분류 혹은 회귀문제에서 각 변수(variable)들의 중요성에 순위를 매길 수 있다. 몇몇 입력 변수를 바탕으로 목표 변수의 값을 예측하는 모델을 생성하는 것을 목표로 한다. 

\[ \vec{X} \]
\[\vec{y}\]


  • 월등히 높은 정확성
  • 간편하고 빠른 학습 및 테스트 알고리즘
  • 변수소거 없이 수천 개의 입력 변수들을 다루는 것이 가능
  • 임의화를 통한 좋은 일반화 성능
  • 다중 클래스 알고리즘 특성


랜덤 포레스트 방법은 bootstraping을 사용한다. 즉, 중복을 허용하는 resampling을 시도한다. 
따라서, 우리는 다수의 의사결정 나무(decision tree)들을 가지게 된다. 이를 숲이라고 한다. 임의로 resampling을 했기 때문에 random forest라고 이름을 붙였다. 무작위 숲이라고 불러도 될 것 같다.
다시 말해서 기존의 주어진 데이터를 분해해서 많은 수의 sub-sample들을 우선 만들어 낸다. 
아주 성능이 뛰어난 분류, 회귀 방법이다. 
물론, LightGBM 등 보다 다소 성능이 좋지 못하지만 많은 연구에 활용되었다. 
현재로서는 LightGBM, XGBoost, CATboost 등이 많이 활용되고 있다.

사람에 대한 정보를 주고 그 사람이 게임을 많이 할 가능성을 예측하는 문제를 풀기 위해서 아래와 같이 결정 나무 두 개를 활용할 수 있다.


scikit-learn에서 제공하는 다양한 분류, 회귀 방법들이 있다. 분류와 회귀에 각각 6가지 7가지가 있다. 
확장성 있는 방법으로서 의사결정 나무(decision tree)를 사용하는 방법이 독특하다. 일종의 '스무고개'라고 볼 수 있다. 나아가, 나무를 여러 개 사용하는 방법이 개발되어 있다. 나무들이 모이면 숲이 되는 것이다. 
bootstrap aggregating(bagging)이라는 방법의 하나로 random forest가 있다. 

LightGBM (최고 성능을 자랑하는 분류, 회귀) : http://incredible.egloos.com/7479081
베이지안 옵티마이제이션 : http://incredible.egloos.com/7479039

일반적으로 Categorical Data인 경우, 투표 방식 (Voting)으로 집계하며 Continuous Data인 경우, 평균 (Average)으로 집계합니다.

bg=BaggingClassifier(DecisionTreeClassifier(),max_samples=0.5, max_features=1.0, n_estimators=20)
bg.fit(x_train,y_train)
bg.score(x_test,y_test)
bg.score(x_train,y_train)

lr=LogisticRegression()
dt=DecisionTreeClassifier()
svm=SVC(kernel=‘poly’, degree=2)
evc=VotingClassifier(estimators=[(‘lr’,lr), (‘dt’, dt), (‘svm’, svm)], voting=‘hard’)
evc.fit(x_train,y_train)
evc.score(x_test,y_test)

부스팅은 잘못 분류된 개체들에 집중하여 새로운 분류규칙을 만드는 단계를 반복하는 방법이다.
adb=AdaBoostClassifier(DecisionTreeClassifier(),n_estimators=10, learning_rate=1)
adb.fit(x_train,y_train)
adb.score(x_test,y_test)
adb.score(x_train,y_train)
from sklearn.datasets import make_moons
from sklearn.metrics import accuracy_score
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier
#     Step1: Create data set
X, y = make_moons(n_samples=10000, noise=.5, random_state=0)
#      Step2: Split the training test set
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
#     Step 3: Fit a Decision Tree model as comparison
clf = DecisionTreeClassifier()
clf.fit(X_train, y_train)
y_pred = clf.predict(X_test)
accuracy_score(y_test, y_pred)
#     Step 4: Fit a Random Forest model, " compared to "Decision Tree model, accuracy go up by 5-6%
clf = RandomForestClassifier(n_estimators=100,max_features="auto",random_state=0)
clf.fit(X_train, y_train)
y_pred = clf.predict(X_test)
accuracy_score(y_test, y_pred)

0.7555
0.7965

n_estimators is how many tree you want to grow. In other word, how many subset you want to split and train

max_features is the number of random features that individual decision tree will be used for finding the optimal splitting.

If “auto”, then max_features=sqrt(n_features).
If “sqrt”, then max_features=sqrt(n_features) (same as “auto”).
If “log2”, then max_features=log2(n_features).
If None, then max_features=n_features.



https://scikit-optimize.github.io/stable/auto_examples/hyperparameter-optimization.html#sphx-glr-auto-examples-hyperparameter-optimization-py
--------------------------------------------------------------------------------------------------------------------
"""
============================================
Tuning a scikit-learn estimator with `skopt`
============================================

Gilles Louppe, July 2016
Katie Malone, August 2016
Reformatted by Holger Nahrstaedt 2020

.. currentmodule:: skopt

If you are looking for a :obj:`sklearn.model_selection.GridSearchCV` replacement checkout
:ref:`sphx_glr_auto_examples_sklearn-gridsearchcv-replacement.py` instead.

Problem statement
=================

Tuning the hyper-parameters of a machine learning model is often carried out
using an exhaustive exploration of (a subset of) the space all hyper-parameter
configurations (e.g., using :obj:`sklearn.model_selection.GridSearchCV`), which
often results in a very time consuming operation.

In this notebook, we illustrate how to couple :class:`gp_minimize` with sklearn's
estimators to tune hyper-parameters using sequential model-based optimisation,
hopefully resulting in equivalent or better solutions, but within less
evaluations.

Note: scikit-optimize provides a dedicated interface for estimator tuning via
:class:`BayesSearchCV` class which has a similar interface to those of
:obj:`sklearn.model_selection.GridSearchCV`. This class uses functions of skopt to perform hyperparameter
search efficiently. For example usage of this class, see
:ref:`sphx_glr_auto_examples_sklearn-gridsearchcv-replacement.py`
example notebook.
"""
print(__doc__)
import numpy as np

#############################################################################
# Objective
# =========
# To tune the hyper-parameters of our model we need to define a model,
# decide which parameters to optimize, and define the objective function
# we want to minimize.

from sklearn.datasets import load_boston
from sklearn.ensemble import GradientBoostingRegressor
from sklearn.model_selection import cross_val_score

boston = load_boston()
X, y = boston.data, boston.target
n_features = X.shape[1]

# gradient boosted trees tend to do well on problems like this
reg = GradientBoostingRegressor(n_estimators=50, random_state=0)

#############################################################################
# Next, we need to define the bounds of the dimensions of the search space
# we want to explore and pick the objective. In this case the cross-validation
# mean absolute error of a gradient boosting regressor over the Boston
# dataset, as a function of its hyper-parameters.

from skopt.space import Real, Integer
from skopt.utils import use_named_args


# The list of hyper-parameters we want to optimize. For each one we define the
# bounds, the corresponding scikit-learn parameter name, as well as how to
# sample values from that dimension (`'log-uniform'` for the learning rate)
space  = [Integer(1, 5, name='max_depth'),
          Real(10**-5, 10**0, "log-uniform", name='learning_rate'),
          Integer(1, n_features, name='max_features'),
          Integer(2, 100, name='min_samples_split'),
          Integer(1, 100, name='min_samples_leaf')]

# this decorator allows your objective function to receive a the parameters as
# keyword arguments. This is particularly convenient when you want to set
# scikit-learn estimator parameters
@use_named_args(space)
def objective(**params):
    reg.set_params(**params)

    return -np.mean(cross_val_score(reg, X, y, cv=5, n_jobs=-1,
                                    scoring="neg_mean_absolute_error"))

#############################################################################
# Optimize all the things!
# ========================
# With these two pieces, we are now ready for sequential model-based
# optimisation. Here we use gaussian process-based optimisation.

from skopt import gp_minimize
res_gp = gp_minimize(objective, space, n_calls=50, random_state=0)

"Best score=%.4f" % res_gp.fun

#############################################################################

print("""Best parameters:
- max_depth=%d
- learning_rate=%.6f
- max_features=%d
- min_samples_split=%d
- min_samples_leaf=%d""" % (res_gp.x[0], res_gp.x[1],
                            res_gp.x[2], res_gp.x[3],
                            res_gp.x[4]))

#############################################################################
# Convergence plot
# ================

from skopt.plots import plot_convergence

plot_convergence(res_gp)

--------------------------------------------------------------------------------------------------------------------


pip install shap

feature 를 빼는 순서.

변수를 아예 포함하지 않는 것 대신, 그 feature의 값들을 무작위로 섞어서(permutation) 그 feature를 노이즈로 만드는 것.


# Let's load the packages
import numpy as np
import pandas as pd
from sklearn.datasets import load_boston
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestRegressor
from sklearn.inspection import permutation_importance
from matplotlib import pyplot as plt

plt.rcParams.update({'figure.figsize': (12.0, 8.0)})
plt.rcParams.update({'font.size': 14})

boston = load_boston()
X = pd.DataFrame(boston.data, columns=boston.feature_names)
y = boston.target
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25, random_state=12)

rf = RandomForestRegressor(n_estimators=100)
rf.fit(X_train, y_train)

rf.feature_importances_

plt.barh(boston.feature_names, rf.feature_importances_)

sorted_idx = rf.feature_importances_.argsort()
plt.barh(boston.feature_names[sorted_idx], rf.feature_importances_[sorted_idx])
plt.xlabel("Random Forest Feature Importance")

perm_importance = permutation_importance(rf, X_test, y_test)

sorted_idx = perm_importance.importances_mean.argsort()
plt.barh(boston.feature_names[sorted_idx], perm_importance.importances_mean[sorted_idx])
plt.xlabel("Permutation Importance")

import shap
explainer = shap.TreeExplainer(rf)

shap_values = explainer.shap_values(X_test)

shap.summary_plot(shap_values, X_test, plot_type="bar")

shap.summary_plot(shap_values, X_test)



핑백

덧글

  • 바죠 2020/01/23 09:11 # 답글

    each node of the tree is a test on a feature,
    each branch represents an outcome of the test;
    leaves contain the output of the model,
    whether it is a discrete label or a real number.
  • 바죠 2020/01/23 09:12 # 답글

    https://towardsdatascience.com/xgboost-is-not-black-magic-56ca013144b4?source=email-1e0b00610a37-1579705862126-digest.reader------0-71------------------8ed92c3e_4182_42ea_906e_620dd4f59f98-27-----&gi=34f80acc2146
  • 바죠 2020/01/27 09:15 # 답글

    https://towardsdatascience.com/explain-your-machine-learning-with-feature-importance-774cd72abe
    cats=['SEX', 'EDUCATION', 'MARRIAGE', 'PAY_0', 'PAY_2', 'PAY_3', 'PAY_4', 'PAY_5', 'PAY_6']
    for c in cats:
    credit[c]=credit[c].astype('category')
    credit_ohe=pd.get_dummies(credit, drop_first=True)

    y=credit_ohe['default.payment.next.month']
    X=credit_ohe.drop(columns=['default.payment.next.month'])

    X_train, X_test, y_train, y_test = train_test_split(X, y, stratify=y)

    rf=RandomForestClassifier(n_estimators=100)
    rf.fit(X_train, y_train)

    print('Training set metrics:')
    print('Accuracy:', accuracy_score(y_train, rf.predict(X_train)))
    print('Precision:', precision_score(y_train, rf.predict(X_train)))
    print('Recall:', recall_score(y_train, rf.predict(X_train)))

    print('Test set metrics:')
    print('Accuracy:', accuracy_score(y_test, rf.predict(X_test)))
    print('Precision:', precision_score(y_test, rf.predict(X_test)))
    print('Recall:', recall_score(y_test, rf.predict(X_test)))

    col_sorted_by_importance=rf.feature_importances_.argsort()
    feat_imp=pd.DataFrame({
    'cols':X.columns[col_sorted_by_importance],
    'imps':rf.feature_importances_[col_sorted_by_importance]
    })

    import plotly_express as px
    px.bar(feat_imp, x='cols', y='imps')

    def PermImportance(X, y, clf, metric, num_iterations=100):
    '''
    Calculates the permutation importance of features in a dataset.
    Inputs:
    X: dataframe with all the features
    y: array-like sequence of labels
    clf: sklearn classifier, already trained on training data
    metric: sklearn metric, such as accuracy_score, precision_score or recall_score
    num_iterations: no. of repetitive runs of the permutation
    Outputs:
    baseline: the baseline metric without any of the columns permutated
    scores: differences in baseline metric caused by permutation of each feature, dict in the format {feature:[diffs]}
    '''
    bar=progressbar.ProgressBar(max_value=len(X.columns))
    baseline_metric=metric(y, clf.predict(X))
    scores={c:[] for c in X.columns}
    for c in X.columns:
    X1=X.copy(deep=True)
    for _ in range(num_iterations):
    temp=X1[c].tolist()
    random.shuffle(temp)
    X1[c]=temp
    score=metric(y, clf.predict(X1))
    scores[c].append(baseline_metric-score)
    bar.update(X.columns.tolist().index(c))
    return baseline_metric, scores


  • 2020/01/27 09:20 # 답글 비공개

    비공개 덧글입니다.
  • 바죠 2021/06/22 11:02 # 답글

    https://mljar.com/blog/feature-importance-in-random-forest/

댓글 입력 영역

최근 포토로그



MathJax