Python scikit-learnのランダムフォレストによる回帰分析の実務的ver

'20/07/12更新:graphvizを使用しない(インストール作業が不要な)verです。
 分析データはcsvファイルであれば良く、お試し用の作成例は右記参照Python scikit-learn 付属のボストン市の住宅価格データ(Boston house prices dataset)をcsvファイル化する - HK29’s blog

▼本プログラム実行後のフォルダ内には、下図のようなファイルを出力する仕様です。
1. 行列散布図:サンプルに使用した分布と、指標(目的変数)に対する設計因子(説明変数)の傾向がわかる。
2. 個別散布図:詳細な傾向がわかる
3. 特徴量の順:指標(目的変数)を決める重要因子(設計因子)とその感度がわかる
4. 適合度の変化の様子をグラフ化:決定係数R2のあてはまりの良さの変化を示す。
5. 適合度90%を超えた時点の回帰モデルをオブジェクトファイルで保存する(.joblib)

f:id:HK29:20200712215700p:plain

■本プログラム

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import os, sys, glob
import shutil

import itertools
import pandas as pd
import numpy as np
import scipy as sp
from scipy import optimize
import math
from sklearn import linear_model
from sklearn.ensemble import RandomForestRegressor
from sklearn.preprocessing import StandardScaler
from sklearn.preprocessing import MinMaxScaler

import matplotlib
matplotlib.use('Agg') # バックグラウンドで画像生成などする宣言
import matplotlib.pyplot as plt
plt.rcParams.update({'figure.max_open_warning': 0})
import matplotlib.ticker as tick
import seaborn as sns

from joblib import dump, load # 学習モデルの保存

import datetime
now = datetime.datetime.now()
now = now.strftime("%y%m%d")

######################################## csvファイルの任意のデータセットをロード
def my_load_csv(path, check_column, check_duplicate_columns,
                start_row, input_columns, out_start_column,
                target_Yname, target_value2ln):
    df = pd.read_csv(path, skiprows=start_row-1, encoding="utf-8")
    print("df -> " + str(df))
    print(df.dtypes) # pandasの列毎の型確認。その列に文字列があるかで決まる。但し、object型は要素毎に異なる可能性がある。
    df.replace('none', '0', inplace=True) # 置換。 inplace=Trueでdfが置換される(df=と新規に代入しなくてよい)
    df.replace('FALSE', '0', inplace=True)
    df_buf1 = df.iloc[:, :out_start_column]
    df_buf2 = df.iloc[:, out_start_column:] # ilocとreplaceは同時に使用できなかったため、一旦分割して処理する
    
    df_buf2.replace('0', np.nan, inplace=True) #文字列0をnumpy形式のNaNにする
    df_buf2.replace(0, np.nan, inplace=True) #数値0をnumpy形式のNaNにする    
    
    columns_list = df_buf2.columns
    #df_buf2[columns_list] = pd.to_numeric(df_buf2[columns_list], errors='coerce') #文字列をNaNへ置換する
    
    df = pd.concat([df_buf1, df_buf2], axis=1) #データフレームの列を連結して、ひとつのdfへ戻す

    file_path = os.path.join(target_Yname, "data_nan.csv")
    df.to_csv(file_path, sep=",", header=True, index=False)
    print('check NaN -> ' + str(df.isnull().any())) # ひとつでもNaNがある列はTrue、そうでなければFalseと表示される。
    print(df.dtypes)
    
    if check_duplicate_columns: #指定した列名があった場合、重複行を削除する
        df2 = df.drop_duplicates(check_duplicate_columns, keep='first') #最初の行が重複とみなされずに残す
    else:
        df2 = df
    print("df2 -> " + str(df2))
    
    if check_column[0]:
        df3 = df2.dropna(subset=[check_column[1]]) # NaNやNoneなどの欠損値を除外する場合
    else:
        df3 = df2[df2[check_column[1]].str.contains(check_column[2], na=False)] # 指定文字列の行を残す場合
    print("df3 -> " + str(df3))
    
    if target_value2ln: # 目的変数Yを対数に変換する場合
        df4 = df3.assign(tmp = np.log(df3[target_Yname]))
        target_Yname = target_Yname + '_ln'
        tmp_columns = df4.columns.values
        print("tmp_columns -> " + str(tmp_columns))
        tmp_columns[-1] = target_Yname
        df4.columns = tmp_columns
        print("df4 -> " + str(df4))
        file_path = os.path.join(target_Yname, "data_df4.csv")
        df4.to_csv(file_path, sep=",", header=True, index=False)
        DF = df4
    else:
        DF = df3
        
    x_DF = DF.iloc[:, input_columns[0]:input_columns[1]]
    print("x_DF -> " + str(x_DF))
    y = DF.loc[:,target_Yname] 
    DF_columns = x_DF.columns
    print("DF_columns -> " + str(DF_columns))
    file_path = os.path.join(target_Yname, "data_DF.csv")
    DF.to_csv(file_path, sep=",", header=True, index=False)
    print('check2 NaN -> ' + str(DF.isnull().any()))
    
    return x_DF, y, DF_columns, target_Yname

######################################## 説明変数Xを標準化
######################################## 各因子のデータを平均0,標準偏差を1へ変換
def my_scaler(X_df, my_feature_names):
    scaler = StandardScaler()
    x_sc = scaler.fit_transform(X_df)  
    # sklearnの上記のようなfit関連の実行後、データの書式がnumpy形式となりカラム(列)名が無くなる。
    # そのため、再度、pandas形式に変換する(次の2行)。これはグラフの軸名で使用するため。
    x_sc = pd.DataFrame(x_sc) # pandasデータフレーム形式へ変換
    x_sc.columns = my_feature_names # カラム名を追記
    file_path = os.path.join(target_Yname, 'data_scalerX.csv')
    x_sc.to_csv(file_path, sep=',', index=False, encoding='utf-8', header=True)
    x_sc.describe().to_csv('data_describe.csv', index=True, encoding='utf-8', mode='w', header=True)

    return x_sc

######################################## 説明変数Xを正規化
######################################## 各因子のデータ範囲を0~1へ変換
def my_mscaler(X_df, my_feature_names):
    mscaler = MinMaxScaler()
    x_msc = mscaler.fit_transform(X_df)  
    # sklearnの上記のようなfit関連の実行後、データの書式がnumpy形式となりカラム(列)名が無くなる。
    # そのため、再度、pandas形式に変換する(次の2行)。これはグラフの軸名で使用するため。
    x_msc = pd.DataFrame(x_msc) # pandasデータフレーム形式へ変換
    x_msc.columns = my_feature_names # カラム名を追記
    file_path = os.path.join(target_Yname, 'data_scalerX.csv')
    x_msc.to_csv(file_path, sep=',', index=False, encoding='utf-8', header=True)
    file_path = os.path.join(target_Yname, 'data_describe.csv')
    x_msc.describe().to_csv(file_path, index=True, encoding='utf-8', mode='w', header=True)

    return x_msc

######################################## 線形重回帰分析
######################################## 暫定的に重要因子の抽出(可視化のため横軸にしてグラフ化する)
def my_linear_regression(X_df, Y, target_Yname):
    file_name = target_Yname + '_LinearRegression.png'
    file_path = os.path.join(target_Yname, file_name)

    clf = linear_model.LinearRegression(fit_intercept=True, normalize=False, copy_X=True, n_jobs=1)
    clf.fit(X_df, Y)
    print("LinearRegression")
    df = pd.DataFrame({"Name":X_df.columns, "Coefficients":clf.coef_}).sort_values(by='Coefficients')
    df = round(df, 5)
    print(df)
    print(clf.intercept_) # 切片
    print(clf.score(X_df,Y)) # R^2
    
    plt.figure(dpi=120) 
    #df2 = df.sort_values(by='Coefficients', ascending=False)[:6] # 降順にソートして6つ抽出
    df2 = df.sort_values(by='Coefficients', ascending=False)[:]
    df2 = df2.sort_values(by='Coefficients', ascending=True) # 昇順にソート
    x=df2.Name
    y=df2.Coefficients
    plt.barh(range(len(x)), y, tick_label=x, align="center", color="magenta", height=0.7) # 軸が文字列の場合、ソートされてしまう対策
    plt.title('LinearRegression', fontsize=14)
    plt.xlabel('Coefficients', fontsize = 14)
    plt.tick_params(labelsize=16)
    plt.tight_layout()
    #plt.show()
    plt.savefig(file_path)
    
    print("principal_feature")
    max_value = max(df.Coefficients)
    print(max_value)
    print(df.dtypes)
    df=df.astype(str)
    print(df.dtypes)
    df3 = df[df['Coefficients'].str.contains(str(max_value))]
    print(df3)
    principal_feature = df3.Name.values.tolist()[0]
    
    return principal_feature

######################################## ランダムフォレストによる回帰分析
######################################## 決定係数R^2を指標として、回帰関数を選定する
def my_random_forest(X_df, Y, target_Yname, trees, depth, step, R2judge, pc, inter_factors):
    cnt=1
    cntlist=[]
    scorelist=[]
    judge=0
    n_depth = (depth[1] - depth[0] + step)//step
    n_trees = (trees[1] - trees[0] + step)//step
    for j in range(depth[0], depth[1], step):
        for i in range(trees[0], trees[1], step):
            print("cnt -> " + str(cnt))
            
            # ランダムフォレストの実行(回帰式の作成)
            regr = RandomForestRegressor(n_estimators=i, max_depth=j, random_state=0)
            
            # 設定条件と決定係数の表示
            regr = regr.fit(X_df,Y) # 設定条件全てを出力(default引数はは上記4つの他にもあるため)
            print("### regr")
            print(regr)

            score = regr.score(X_df,Y) # 決定係数R^2
            print("### score")
            print(score)
            scorelist.append(score)
            cntlist.append(cnt)
            
            if (judge==0) & (score>=R2judge):
                # 重要因子の可視化
                # 散布図
                print("### regr.estimators_") 
                estimators = regr.estimators_ 
                print(estimators) 
                print("### regr.feature_importances_" )
                importances = regr.feature_importances_
                print(importances)
                print("### sort")
                num = np.sort(importances)
                print(num)
                print("### element of sorted")
                indices = np.argsort(importances)
                print(indices)
                #fig = plt.figure(num=1, figsize=(8, 6), dpi=100)
                fig = plt.figure(dpi=120)
                ax = fig.add_subplot(1,1,1)
                ax.set_title('Important Factor Num' + str(cnt), fontsize=14)
                ax.barh(range(len(indices)), importances[indices], color='magenta', align='center')
                print(range(len(indices)))
                print(X_df.columns[indices])
                loc = list(range(len(indices)))
                labels = X_df.columns[indices]
                ax.set_yticks(loc)
                ax.set_yticklabels(labels)
                ax.set_xlim([0, 1])
                ax.tick_params(labelsize=16)
                plt.tight_layout()
                file_name = target_Yname + "_RandomForest_important_factor_" + str('{:02g}'.format(cnt)) + '.png'
                file_path = os.path.join(target_Yname, file_name)
                plt.savefig(file_path)
                plt.close() # Close a figure window

                # 横棒グラフ
                select_condition=[score,cnt,i,j]
                if input_factors >= 5:
                    important_factor=X_df.columns[indices][-5:] # 優位上から5因子を抽出
                else:
                    important_factor=X_df.columns[-1*input_factors:]
                judge=1
                print("judge No -> " + str(cnt))
                # 回帰モデルをオブジェクトファイルで保存
                file_name = now + '_' + target_Yname + "_RandomForestRegressor_" + str('{:02g}'.format(cnt)) + '.joblib'
                file_path = os.path.join(target_Yname, file_name)
                dump(regr, file_path) 
            
                # 回帰式にXを代入してYを生成
                pred_Y_np = regr.predict(X_df)
                print(pred_Y_np)
                print(type(pred_Y_np))
                pred_Y = pd.Series(pred_Y_np)
                
                # 再現性を散布図で確認
                plot_scatter(X_df, Y, target_Yname, pc, pred_Y, cnt)
                plot_reg(Y, target_Yname, pc, pred_Y, cnt)
            
            cnt += 1
    
    # 決定係数の変化を可視化
    #my_fontsize = 12
    ax = plt.figure(num=0, dpi=120).gca() #, figsize=(8,8))
    ax.set_title('the evolution of the coefficient of determination') #, fontsize=my_fontsize)
    ax.scatter(cntlist, scorelist, c="red") #, s=20*5)
    ax.plot(cntlist, scorelist, color="red")
    ax.set_xlabel('Number of Cycle') #, fontsize=my_fontsize)
    ax.set_ylabel('R^2') #, fontsize=my_fontsize)
    for i, j in zip(cntlist, scorelist):
        ax.text(i, j, '{:.2f}'.format(j), ha='center', va='bottom', color='b') #, fontsize=my_fontsize)
    ax.set_ylim([0, 1])
    ax.xaxis.set_major_locator(tick.MultipleLocator(1))
    ax.grid(which='both')
    #ax.tick_params(labelsize=my_fontsize) # 目盛りのサイズ
    plt.tight_layout()
    #plt.show()
    file_name = target_Yname + '_R2.png'
    file_path = os.path.join(target_Yname, file_name)
    plt.savefig(file_path)
    plt.close() # Close a figure window

    if judge==0:
        select_condition='N/A: MaxR2=' + str(score) + '<' + str(R2judge)
        print(select_condition)
        print('### scorelist')
        print(scorelist)
        sys.exit()
    
    return select_condition, important_factor

######################################## 散布図
# 相関性の確認1 オリジナル生データを青点で、回帰式によるデータを赤点でプロット
def plot_scatter(X_df, Y, target_Yname, pc, pred_Y, cnt):
    file_name = target_Yname + "scatter_" + str('{:02g}'.format(cnt)) + '.png'
    file_path = os.path.join(target_Yname, file_name)

    #fig = plt.figure(num=2, figsize=(8, 6), dpi=100)
    fig = plt.figure(dpi=120)
    ax = fig.add_subplot(1,1,1)
    ax.set_title('Scatter Num' + str(cnt), fontsize=14)
    ax.set_xlabel(pc, fontsize=16)
    ax.set_ylabel(target_Yname, fontsize=16)
    ax.scatter(X_df.loc[:,pc], Y, facecolors='none', edgecolors='b', label='Raw data')
    ax.scatter(X_df.loc[:,pc], pred_Y, facecolors='none', edgecolors='r', label='RandomForest')
    ax.legend(loc='lower right', fontsize=14)
    ax.tick_params(labelsize=16)
    plt.grid()
    plt.tight_layout()
    #plt.show()
    plt.savefig(file_path)
    plt.close() # Close a figure window

### 近似式 y = ax 用の関数 
def approximation_expression(x, a):
    return a * x

### 近似式 y = ax + b 用の関数 
def approximation_expression_with_y_intercept(x, a, b):
    return a * x + b

# 相関性の確認2 横軸Y:縦軸Pred_Y
def plot_reg(Y, target_Yname, pc, pred_Y, cnt):
    file_name = target_Yname + "_RandomForest_" + "{:02g}".format(cnt) + '_real_vs_pred'
    file_path = os.path.join(target_Yname, file_name)

    # 欠損値を省いたことにより、連番でなくなっている可能性のあるインデックスをリセット
    Y = Y.reset_index(drop=True) # drop=Trueにより、元を削除して、新規インデックスを0から連番で作成
    DF = pd.concat([Y.rename(target_Yname), pred_Y.rename(target_Yname + "_pred")], axis=1)
    DF.to_csv(file_path + ".csv", sep=',', index=False, header=True, encoding='utf-8')
    
    popt, pcov = optimize.curve_fit(approximation_expression, Y, pred_Y)
    
    ax = plt.figure(num=0, dpi=120).gca() 
    #plt.rcParams["axes.labelsize"] = 15
    ax.set_title("pred vs real " + "{:02g}".format(cnt), fontsize=14)
    ax.set_xlabel(target_Yname, fontsize=16)
    ax.set_ylabel("Pred\n" + target_Yname, fontsize=16)
    rp = ax.scatter(x = target_Yname,
                    y = target_Yname + "_pred",
                    data = DF,
                    facecolors="none",
                    edgecolors='black') # purple

    # 生データの最小値と最大値
    y_min = DF[target_Yname].min()
    y_max = DF[target_Yname].max()
    # 予測データの最小値と最大値
    y_pred_min = DF[target_Yname + '_pred'].min()
    y_pred_max = DF[target_Yname + '_pred'].max()
    # プロットするためのxデータの範囲を決める
    x_min = min(y_min, y_pred_min)
    x_max = max(y_max, y_pred_max)
    print(x_min)
    print(x_max)
    # グラフのレンジを決める
    x_range = x_max - x_min # データの範囲が100以下か以上かで分ける
    print("x_range = x_max - x_min = " + str(x_range))
    if x_max > 1:
        print("range A")
        min_lim = 0
        if x_range <= 100:
            max_lim = math.floor(x_max + 1)
        else:
            max_lim = math.floor(x_max + 10)
    elif x_max >= 0:
        print("range B")
        min_lim = -0.1
        max_lim = 1.1
    elif x_min >= -1:
        print("range C")
        min_lim = -1.1
        max_lim = 0.1
    else:
        print("range D")
        max_lim = 0.1
        if x_range <= 100:
            min_lim = math.floor(x_min - 1)
        else:
            min_lim = math.floor(x_min - 10)
    
    print(min_lim, max_lim)
    rp.axes.set_xlim(min_lim, max_lim)
    rp.axes.set_ylim(min_lim, max_lim)

    # 近似式プロットのためのデータを作成
    x_approximation = np.linspace(min_lim, max_lim, 10) # numpyでxデータを作成
    y_approximation = popt[0] * x_approximation # 近似式に代入してyデータを作成
    line_approximation = ax.plot(x_approximation, y_approximation,
                                 linestyle = 'dashed', linewidth = 3, color='r') 
    
    rp.axes.set_aspect('equal', adjustable='box')
    plt.grid(True)
    # 凡例を指定して記入する場合は、リストで指定する
    ax.legend([line_approximation[0]], ["y = {:.2f}x".format(popt[0])],
               loc='upper left',
               numpoints=1,
               fontsize=15)
    plt.tick_params(labelsize=15)
    plt.tight_layout() 
    plt.savefig(file_path + '.png') 
    plt.close()

######################################## 重要因子の上位6つ(important_factor)で作成する。
### 行列散布図
def my_scatter_matrix(X_df, important_factor, *, y=None, n=1): # *を挟むと、以降の変数をキーワード引数で強制する
    file_name = target_Yname + '_2d_scatter_matrix.png'
    file_path = os.path.join(target_Yname, file_name)

    fig = plt.figure(figsize=(8,8))
    ax = fig.add_subplot(1,1,1)
    x = X_df.loc[:,important_factor] # 抽出する列名を指定    
    if y is None:
        xy_df = x
    else:
        xy_df = pd.concat([x,y], axis=1) # 横方向に連結。axis=1   
    sns.pairplot(xy_df,
                 kind="reg",
                 markers=".",
                 diag_kind="kde",
                 diag_kws=dict(shade=True),
                 )
    plt.savefig(file_path)
    plt.close() # Close a figure window

### 特徴量2因子の散布図xy pairplot
def my_scatter_xy_pairplot(X_df, tick_setup, important_factor, *, y=None, n=1): # *を挟むと、以降の変数をキーワード引数で強制する
    file_name = target_Yname + '_2d_scatter_xy_pairplot.png'
    file_path = os.path.join(target_Yname, file_name)

    mySpecie = important_factor[-1]
    fig = plt.figure(figsize=(14,14))
    ax = fig.add_subplot(1,1,1)
    x = X_df.loc[:,important_factor] # 抽出する列名を指定    
    if y is None:
        xy_df = x
    else:
        xy_df = pd.concat([x,y], axis=1) # 横方向に連結。axis=1   
    Yname = xy_df.columns[-1]
    Xnamelist = xy_df.columns[:-1].values.tolist() # 自分自身を含む場合は-1,含まない場合は-2
    sns.set_style("whitegrid") # グラフに格子状を入れる
    g = sns.pairplot(xy_df,
                     hue = mySpecie,
                     palette='bwr',   # 'gray'
                     x_vars=Xnamelist,
                     y_vars=[Yname],
                     )
    if tick_setup:
        g.set(ylim=(tick_setup[0], tick_setup[1])) #目盛り区間
    plt.savefig(file_path)
    plt.close() # Close a figure window
    
### 特徴量2因子の散布図xy lmplot
def my_scatter_xy_lmplot(X_df, target_Yname, tick_setup, important_factor, *, y=None, n=1): # *を挟むと、以降の変数をキーワード引数で強制する
    Yname = target_Yname
    Xname = important_factor[-1]
    mySpecie = important_factor[-2]
    file_name = target_Yname + '_2d_scatter_xy_lmplot_' + Xname +"_"+ mySpecie + ".png"
    file_path = os.path.join(target_Yname, file_name)

    fig, ax = plt.subplots(figsize=(12,10))
    x = X_df.loc[:,important_factor] # 抽出する列名を指定    
    if y is None:
        xy_df = x
    else:
        xy_df = pd.concat([x,y], axis=1) # 横方向に連結。axis=1   

    sns.set('notebook', 'whitegrid', 'dark', font_scale=1.4) # グラフに格子状を入れる
    g = sns.lmplot(Xname,
                   Yname,
                   xy_df,
                   hue = mySpecie,
                   palette='bwr',   # 'Blues_d', # 'Reds_d',
                   fit_reg = False,
                   )
    if tick_setup:
        g.set(ylim=(tick_setup[0], tick_setup[1])) #目盛り区間
        plt.yticks(np.arange(tick_setup[0], tick_setup[1] + 0.01, tick_setup[2])) #目盛り間隔。+0.01としてる理由は0とすると0が表記されないため。
        plt.axhline(y=tick_setup[3], lw=2, color='red', linestyle='dashed') # 判断基準のライン
    #ax.axhspan(ymin=, ymax=, color="lightcyan", alpha=0.3) # 指定範囲を塗りつぶす。縦方向の場合はaxvspan
    plt.savefig(file_path)
    plt.close() # Close a figure window
    
######################################## main関数
def main():
         
    ### 初期化(前回実行時に生成されたファイルを削除)
    if os.path.isdir(target_Yname):
        shutil.rmtree(target_Yname)
        
    # 生成ファイルを保存するフォルダを作成
    os.mkdir(target_Yname)
    
    ### データセットからデータ抽出
    data = my_load_csv(path, check_column, check_duplicates_columns,
                       start_row, input_columns, out_start_column,
                       target_Yname, target_value2ln)
    
    X = data[0]
    Y = data[1]
    feature_names = data[2]
    print('### extraction data')
    print(X)
    print(Y)
    print(feature_names)

    ### 説明変数Xを標準化,正規化する?
    if scalerjudge == 1: # 標準化する場合
        X = my_scaler(X, feature_names)
    elif scalerjudge == 2: # 正規化する場合
        X = my_mscaler(X, feature_names)
    else:
        pass
    print('### scalerX data')
    print(X)

    ### 線形重回帰分析により暫定重要因子を特定(グラフ化のために使用するだけ)
    pc = my_linear_regression(X, Y, target_Yname)
    print("### principal_feature ###")
    print(pc)
    
    ### ランダムフォレストにより回帰関数の作成(指定の決定係数を超えた関数を選定する)
    result = my_random_forest(X, Y, target_Yname, trees, depth, step, R2judge, pc, input_factors)
    print('### select_condition: 0score, 1num, 2trees, 3depth -> '+str(result[0]))
    print('### importnat factor -> '+str(result[1]))
    # 散布図  
    my_scatter_matrix(X, result[1], y=Y, n=1)
    my_scatter_xy_pairplot(X, tick_setup, result[1], y=Y, n=1)
    for contour_x1x2 in list(itertools.permutations(result[1], 2)):
        print("contour_x1x2 -> " + str(contour_x1x2))
        print(tick_setup)
        my_scatter_xy_lmplot(X, target_Yname, tick_setup, contour_x1x2, y=Y, n=1)

###################################################################### メイン関数    
if __name__ == "__main__":
    ### 基本パラメータ ###
    path = "boston.csv" # 読み込む生データcsvファイル
    input_factors = 13
    target_Yname = 'PRICE' # 目的変数Y
    
    ### 生データcsvファイルの読み込み設定
    start_row = 1 # 読み込み開始行。1行目なら1, 2行目なら2, …
    target_value2ln = False # Yを対数変換するか?
    check_flag = True # True:NaNやNoneなどの欠損値を除外する場合。False:指定文字列を残す場合
    check_column = (check_flag, target_Yname, 'ok') # 要素3は、Falseの場合に機能する。指定文字列を残す
    check_duplicates_columns=[] # ダブりを省く列名を指定。複数可。省かない場合は[]と空リストにする
    
    input_columns = (0, input_factors) # 設計因子の列番号(開始, 終了)
    out_start_column = 13 # この列以降のデータについて、欠損値の処理を行う
    
    ### データ分析の設定
    scalerjudge = 0 # データXを標準化する場合は1, 正規化する場合は2, しない場合はその他任意
    R2judge = 0.9 # 決定係数の判断基準。この値を初めて超えた場合の回帰を決定木で視覚化する。
    contour_method = 'linear'  # 'nearest' or 'linear' or 'cubic'
    contour_range = 6
    #tick_setup = (0, 60, 10, 25) # 縦軸Yの目盛り設定で、(最小, 最大, 間隔, 判断基準)の順に入力
    tick_setup = () #オートレンジにする場合は空()
        
    ### ランダムフォレストの設定
    trees = [1, 8] # num_of_trees [min, max]
    depth = [1, 8] # max_depth [min, max]
    step = 3       # num of step

    ###### call function ######################
    main()

    print("finished")

■ランダムフォレストに関する記事

下記リンクは、短いコードですがグラフ化は簡素にしています。単にランダムフォレストのコードを見たい人向け。

hk29.hatenablog.jp

下記リンクは、ランダムフォレストに関する総まとめです。枝葉に分岐した結果も可視化します。dtreevizとgraphvizを使用します。

hk29.hatenablog.jp

以上

<広告>