【初心者】コピペでできる決定木回帰

スポンサーリンク
Python




非エンジニアサラリーマンがお届けする、コピペでできる機械学習シリーズの決定木の回帰編です。決定木は以前も分類問題で紹介しましたが、今回は回帰問題です。

  • 分類問題は分けるもの
  • 回帰問題は量を予測するもの

問題解決にコードは最低限でいいと考えています。コードはコピーして、データ収集や結果の解釈に力を注いで下さい。だれでも、すぐに実践できるようにscikit-learnのデータセットを使います。また、自身のデータでもすぐにコピペできるように、scikit-learnのデータセットを一旦データフレームにしてから機械学習を実施していきます。

環境構築は、【2020年最新】Anacondaのインストール方法

それでは、やっていきましょう!

必要なライブラリ―をインポート

import pandas as pd
import numpy as np
from sklearn.datasets import load_boston
import matplotlib.pyplot as plt
%matplotlib inline
import seaborn as sns
import warnings
warnings.filterwarnings('ignore')

今回のデータセットはscikit-learnのデータセットにあるbostonを使用します。

データセットを整える

【超重要】はじめてのデータ収集方法

目的変数:住宅価格(の中央値)
説明変数:目的変数に関係しそうな、さまざまなデータ

boston = load_boston()
df = pd.DataFrame(data = boston.data, columns = boston.feature_names)
df['PRICE'] = boston.target
df

上のコードはデータフレームにするためのコードです。
bostonのデータセットで実践する場合は上のコードを実行して下さい。
自身のデータを使用する場合は、以下のコードから実行して下さい。

機械学習がしやすいデータの形に整える

X = df.iloc[:,:-1].values  # 説明変数(最後の列以外)
y = df.iloc[:,-1].values   # 目的変数(最後の列のみ)

訓練用のデータとテスト用のデータに分割する

from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size = 0.25,
    random_state = 1)

決定木回帰分析

from sklearn.tree import DecisionTreeRegressor
from sklearn.model_selection import GridSearchCV

dtr = DecisionTreeRegressor(random_state=0)

gs_dtr = GridSearchCV(dtr,
                      param_grid = {'max_depth': [2, 3, 4, 5]},
                      cv = 10)

gs_dtr.fit(X_train, y_train)

y_train_pred = gs_dtr.predict(X_train)
y_test_pred = gs_dtr.predict(X_test)

gs_dtr.best_estimator_

出力:
DecisionTreeRegressor(max_depth=4, random_state=0)

もっとも精度が高かったのは、4回分割(max_depth=4)するものであった。

決定木回帰による予測結果と実際の結果との関係を可視化してみる

plt.scatter(y_test, y_test_pred)
plt.savefig('test_pred_plot.jpg')

各点が、右肩上がりの直線に近いほうが当てはまりが良い。

plt.scatter(y_train_pred,  y_train_pred - y_train,
            c='steelblue', marker='o', edgecolor='white',
            label='Training data')
plt.scatter(y_test_pred,  y_test_pred - y_test,
            c='limegreen', marker='s', edgecolor='white',
            label='Test data')
plt.xlabel('Predicted values')
plt.ylabel('Residuals')
plt.legend(loc='upper left')
plt.hlines(y=0, xmin=-10, xmax=50, color='r', lw=1.5, alpha=0.5)
plt.xlim([-10, 50])
plt.tight_layout()
plt.savefig('graph_dtr.jpg')
plt.show()

出力:

各点が赤線に近いほうが当てはまりが良い。まあ、悪くはないかな、という感じですかね。

モデルの評価(決定木回帰)

from sklearn.metrics import r2_score
from sklearn.metrics import mean_squared_error

print('MSE  train: %.3f, test: %.3f' % (
        mean_squared_error(y_train, y_train_pred),
        mean_squared_error(y_test, y_test_pred)))
print('RMSE train: %.3f,  test: %.3f' %(
        np.sqrt(mean_squared_error(y_train, y_train_pred)),
        np.sqrt(mean_squared_error(y_test, y_test_pred))))
print('R^2  train: %.3f,  test: %.3f' % (
        r2_score(y_train, y_train_pred),
        r2_score(y_test, y_test_pred)))

出力:
MSE train: 9.036, test: 13.826
RMSE train: 3.006, test: 3.718
R^2 train: 0.886, test: 0.860

初心者のための回帰問題の評価指標

MSE:小さいほうが当てはまりがよい

RMSE:小さいほうが当てはまり良い

R²:1に近いほうが良い

訓練データ(train)と、テストデータ(test)で上の評価を実施する。

以前紹介した、線形回帰(R²train:0.717、R²test:0.779)やRidge回帰(R²train:0.715、R²test:0.778)、Lasso回帰(R²train:0.717、R²test:0.779)の結果より良いことが分かります。

【初心者】コピペでできる線形回帰

【初心者】コピペでできるRidge・Lasso回帰

下のコードで、予測とテストの差をヒストグラムで可視化する。

一応、正規分布になっているほうが、いいとされています。

sns.distplot((y_test-y_test_pred),bins=50)

決定木回帰回帰の可視化

from sklearn import tree
from IPython.display import Image
from sklearn.tree import export_graphviz
from pydotplus import graph_from_dot_data

feature_names = df.iloc[:,:-1].columns # もとのデータフレームの最後の列以外の説明変数名を指定

dot_data = export_graphviz(gs_dtr.best_estimator_,
                           filled=True,
                           rounded=True,
                           feature_names = feature_names)

graph = graph_from_dot_data(dot_data)
Image(graph.create_png())


一番上は、LSTATが9.755以下はTrue、LSTATが9.755より大きかったらFalseに向かう。

from dtreeviz.trees import dtreeviz


viz = dtreeviz(gs_dtr.best_estimator_,
               X_train,
               y_train,
               feature_names=feature_names,
               target_name='PRICE'
               )

display(viz)

出力:

縦の点線がしきい値、横の点線がしきい値で分けたときの各平均値を表しています。
回帰問題でも分かりやすく表してくれています。





コメント

タイトルとURLをコピーしました