モデルの精度向上と検証方法

1. はじめに

本章を通して、ユーザーは精度の高いモデルを得るために、多様なハイパーパラメーターのモデルを大量かつ手軽に作成できるようになります。
さらに、作成したモデルの中から精度の高いモデルを選択できるようになります。

具体的な達成目標は、以下の通りです。

  • 「テンプレート構文を用いたSPDとSRCの作成ができる」

  • 「パラメーターチューニングとランダムリスタートを理解し、テンプレート構文を活用してSPDとSRCの実装ができる」

  • 「モデルの検証方法を理解した上でモデルの検証を実行し、検証結果として予測精度を確認できる」

2. データの準備

本節では、以下のデータ準備の手順について示します。学習・予測の実行と結果確認の2. データの準備と同様ですが、本章ではテンプレート構文を用いるので、CSVとASDはファイル出力は行いません。

  1. 分析対象データに _sid (sample ID) を追加

  2. ASD(属性スキーマ)の作成

  3. 分析対象データから学習用と予測用を作成

本章では、分析対象データをPandas Dataframeのまま扱うため、カテゴリ型の属性の型はnp.objectまたはnp.boolでなければなりません。 そのため、数値型のカテゴリを持つ属性はnp.objectに変換する必要があり、read_csv()関数を実行する際に、originの型をnp.objectとして読み込みます。

以下のコードで、自動車の燃料消費量予測の分析対象データを示します。

データは、UCIのオープンデータである Auto MPG Data Set (https://archive.ics.uci.edu/ml/datasets/auto+mpg) を属性名car_nameを削除して、利用しています。

[1]:
import pandas as pd
import numpy as np

input_data = pd.read_csv('./data/auto-mpg.csv', na_values='?', dtype={'origin': np.object})

input_data.dropna(inplace=True)
input_data.insert(0, '_sid', list(range(input_data.shape[0])))

input_data.head()
[1]:
_sid mpg cylinders displacement horsepower weight acceleration model_year origin
0 0 18.0 8 307.0 130 3504 12.0 70 1
1 1 15.0 8 350.0 165 3693 11.5 70 1
2 2 18.0 8 318.0 150 3436 11.0 70 1
3 3 16.0 8 304.0 150 3433 12.0 70 1
4 4 17.0 8 302.0 140 3449 10.5 70 1

上記の分析対象データからASDを作成します。

学習・予測の実行と結果確認の2. データの準備で示していますが、ASDのweightを正しいデータ型に修正します。 originは、np.objectとしてread_csv()関数で読み込んだのでカテゴリ型として認識されています。

[2]:
from sampotools.api import gen_asd_from_pandas_df
import pandas as pd
import yaml

# ASD作成
asd = gen_asd_from_pandas_df(input_data)

# 修正
asd['weight'] = {'scale': 'REAL'}

# 確認
pd.DataFrame(asd).T[['scale', 'domain']]
[2]:
scale domain
_sid INTEGER NaN
mpg REAL NaN
cylinders INTEGER NaN
displacement REAL NaN
horsepower INTEGER NaN
weight REAL NaN
acceleration REAL NaN
model_year INTEGER NaN
origin NOMINAL [1, 3, 2]

分析対象データを学習用と予測用に分けます。

以下のコードを実行し、全体の90%にあたる件数を learn_data、残り10%の件数を predict_data としてPandas DataFrameに格納します。

[3]:
n_all = len(input_data)
n_predict = n_all // 10
n_learn = n_all - n_predict

learn_data = input_data.iloc[0:n_learn,:]
predict_data = input_data.iloc[n_learn:n_all,:]

本節の具体的な説明は、学習・予測の実行と結果確認の2. データの準備 を参照してください。

3. より精度の高いモデルの作成方法

より精度の高いモデルを作成するため、以下について説明します。 - テンプレート構文 - パラメーターサーチ - ランダムリスタート

3.1. テンプレート構文を用いたSPDとSRCの定義

本節では、テンプレート構文を用いたSPDとSRCの定義について示します。

テンプレート構文は、{{ <テンプレート変数名> }} というプレースホルダーを用いることで、SPDまたはSRCのプレースホルダーに動的にPythonコード上の変数の値を入力することが可能です。

テンプレート構文は、次節以降で利用されます。

テンプレート構文を用いるSPDの記述例を以下で示します。 記述例では、tree_depthの値にテンプレート構文を適用しています。

[4]:
spd_content_templ = '''
dl -> std  -> rg
   -> bexp -> rg

---

components:
    dl:
        component: DataLoader

    std:
        component: StandardizeFDComponent
        features: scale == 'real' or scale == 'integer'

    bexp:
        component: BinaryExpandFDComponent
        features: scale == 'nominal'

    rg:
        component: FABHMEBernGateLinearRgComponent
        features: name != 'mpg'
        target: name == 'mpg'
        standardize_target: True
        tree_depth: {{ tree_depth }}

global_settings:
    keep_attributes:
        - mpg
    feature_exclude:
        - mpg
'''

テンプレート構文は、gen_spd()関数で生成する時にプレースホルダーに値が入力されます。値はテンプレート変数名をキー値とした辞書で与えます。

[5]:
from sampo.api import gen_spd

spd_param = {'tree_depth': 3}
spd = gen_spd(template=spd_content_templ, params=spd_param)

上記で生成したSPDを出力し、{{ tree_depth }}の値が入力されていることを確認します。

[6]:
print(spd) #確認
dl -> std -> rg
dl -> bexp -> rg

---

components:
    dl:
        component: DataLoader

    bexp:
        component: BinaryExpandFDComponent
        features: scale == 'nominal'

    std:
        component: StandardizeFDComponent
        features: scale == 'real' or scale == 'integer'

    rg:
        component: FABHMEBernGateLinearRgComponent
        features: name != 'mpg'
        standardize_target: true
        target: name == 'mpg'
        tree_depth: 3

global_settings:
    keep_attributes:
    - mpg

    feature_exclude:
    - mpg

以下に、テンプレート構文を用いるSRCの記述例を示します。 テンプレート構文を学習用と予測用でプロセス名や分析対象データ、ASDの格納先の指定に適用しています。

テンプレート構文を用いることで、Pandas DataFrameのようなPythonオブジェクトもSRCに指定することができます。

[7]:
# 学習用SRC
learn_src_templ = '''
fabhmerg_learn_{{ run_times }}:
    type: learn

    data_sources:
        dl:
            df: {{ learn_data }}
            attr_schema: {{ asd }}
'''

# 予測用SRC
predict_src_templ = '''
fabhmerg_predict_{{ run_times }}:
    type: predict

    data_sources:
        dl:
            df: {{ predict_data }}
            attr_schema: {{ asd }}

    model_process: fabhmerg_learn_{{ run_times }}
'''

SPDと同様に、SRCをgen_src()関数で生成する時に、src_paramも渡すことでプレースホルダーに値が入力されます。

[8]:
from sampo.api import gen_src

src_param = {'run_times': 0 ,'learn_data':learn_data ,'predict_data':predict_data, 'asd': asd}
learn_src = gen_src(template=learn_src_templ, params=src_param)
predict_src = gen_src(template=predict_src_templ, params=src_param)

値を確認するため、gen_src()関数で生成したSRCをそれぞれ出力します。

[9]:
# 確認
print(learn_src)
fabhmerg_learn_0:
    type: learn

    data_sources:
        dl:
            df:      _sid   mpg  cylinders   ...    acceleration  model_year  origin
                0       0  18.0          8   ...            12.0          70       1
                1       1  15.0          8   ...            11.5          70       1
                2       2  18.0          8   ...            11.0          70       1
                ..    ...   ...        ...   ...             ...         ...     ...
                350   350  33.7          4   ...            14.4          81       3
                351   351  32.4          4   ...            16.8          81       3
                352   352  32.9          4   ...            14.8          81       3

                [353 rows x 9 columns]
            attr_schema:
                [('_sid', {'scale': 'INTEGER'}),
                 ('mpg', {'scale': 'REAL'}),
                 ('cylinders', {'scale': 'INTEGER'}),
                 ('displacement', {'scale': 'REAL'}),
                 ('horsepower', {'scale': 'INTEGER'}),
                 ...]

                [Displaying 5 out of 9 attributes.]

[10]:
print(predict_src)
fabhmerg_predict_0:
    type: predict

    data_sources:
        dl:
            df:      _sid   mpg  cylinders   ...    acceleration  model_year  origin
                353   353  31.6          4   ...            18.3          81       3
                354   354  28.1          4   ...            20.4          81       2
                355   355  30.7          6   ...            19.6          81       2
                ..    ...   ...        ...   ...             ...         ...     ...
                389   389  32.0          4   ...            11.6          82       1
                390   390  28.0          4   ...            18.6          82       1
                391   391  31.0          4   ...            19.4          82       1

                [39 rows x 9 columns]
            attr_schema:
                [('_sid', {'scale': 'INTEGER'}),
                 ('mpg', {'scale': 'REAL'}),
                 ('cylinders', {'scale': 'INTEGER'}),
                 ('displacement', {'scale': 'REAL'}),
                 ('horsepower', {'scale': 'INTEGER'}),
                 ...]

                [Displaying 5 out of 9 attributes.]
    model_process: fabhmerg_learn_0

3.2. パラメーターチューニングの実行方法

パラメーターチューニングの例として、グリッドサーチを実行する例を示します。
グリッドサーチは、ユーザーが指定したハイパーパラメーターから全ての組み合わせで学習を実施し、最適なパラメーターの組み合わせを探すことです。
下記のSPDのtree_depthstandardize_targetにテンプレート構文を適用し、グリッドサーチを行います。
SAMPO/FABでグリッドサーチを行う場合は、ハイパーパラメーターの組み合わせの数だけSPDを作成します。
[11]:
spd_content_para_tuning = '''
dl -> std  -> rg
   -> bexp -> rg

---

components:
    dl:
        component: DataLoader

    std:
        component: StandardizeFDComponent
        features: scale == 'real' or scale == 'integer'

    bexp:
        component: BinaryExpandFDComponent
        features: scale == 'nominal'

    rg:
        component: FABHMEBernGateLinearRgComponent
        features: name != 'mpg'
        target: name == 'mpg'
        standardize_target: {{ standardize_target }}
        tree_depth: {{ tree_depth }}

global_settings:
    keep_attributes:
        - mpg
    feature_exclude:
        - mpg
'''

下記では、ハイパーパラメーターの各組み合わせをリストで持つspd_paramsが作成されます。

[12]:
from sklearn.model_selection import ParameterGrid

spd_param_combination = {
    'standardize_target': [True, False],
    'tree_depth': [3, 4, 5]
}

spd_params = list(ParameterGrid(spd_param_combination))

SRCの記述例を示します。

[13]:
# 学習用SRC
learn_src_para_tuning = '''
fabhmerg_learn_{{ parameter_pattern }}:
    type: learn

    data_sources:
        dl:
            df: {{ learn_data }}
            attr_schema: {{ input_asd }}
'''

# 予測用SRC
predict_src_para_tuning = '''
fabhmerg_predict_{{ parameter_pattern }}:
    type: predict

    data_sources:
        dl:
            df: {{ predict_data }}
            attr_schema: {{ input_asd }}

    model_process: fabhmerg_learn_{{ parameter_pattern }}
'''

上記で作成したSPD、spd_params、SRCを用いて、グリッドサーチを実行します。

[14]:
import logging
from sampo.api import sampo_logging
from sampo.api import gen_spd, gen_src
from sampotools.api import gen_asd_from_pandas_df

sampo_logging.configure(logging.INFO, filename='./fabhmerg_para.log')

process_list = []  # 並列実行するプロセスを保存するリスト

for grid_id, spd_param in enumerate(spd_params):
    spd = gen_spd(template=spd_content_para_tuning, params=spd_param)
    src_param = {'parameter_pattern': grid_id, 'learn_data': learn_data, 'predict_data': predict_data, 'input_asd': asd}
    learn_src = gen_src(template=learn_src_para_tuning, params=src_param)
    predict_src = gen_src(template=predict_src_para_tuning, params=src_param)
    process_list.append((learn_src, spd))  # 学習用の分析プロセスの追加
    process_list.append((predict_src, None))  # 予測用の分析プロセスの追加

[15]:
from sampo.api import process_runner, process_store

pstore_url = './parallel_pstore_tuning'
process_store.create(pstore_url)

#グリッドサーチ実行
process_runner.session_run(process_list, pstore_url=pstore_url, max_workers=3)
[15]:
[('fabhmerg_learn_0.f495addd-ab93-4952-aff5-40a6327812d9', None),
 ('fabhmerg_learn_2.28b9d7d4-3310-4708-aa7c-76fe9f126979', None),
 ('fabhmerg_learn_1.5171862b-1406-4df7-a542-e8c8325f34c1', None),
 ('fabhmerg_learn_3.86f3c015-dc4d-4306-9bf3-7fa3dac69680', None),
 ('fabhmerg_learn_4.e79f0543-d244-4858-b22a-81c4b66826ed', None),
 ('fabhmerg_predict_0.a1db32c2-c9b0-4591-a5be-d33d7d90d7d7', None),
 ('fabhmerg_learn_5.f66267e2-5117-4adc-ad7d-2096ec4d5850', None),
 ('fabhmerg_predict_1.6decfd04-c14f-4982-bb02-e607dda16f6b', None),
 ('fabhmerg_predict_3.257d52fd-7069-4b35-a5f2-918bd618d269', None),
 ('fabhmerg_predict_2.dd03f131-4b9e-4aca-937a-888355b7fa0c', None),
 ('fabhmerg_predict_4.03063d1d-d030-41f3-8c1d-aa6d4d299895', None),
 ('fabhmerg_predict_5.362e7401-9426-4ceb-95ee-0601950cb419', None)]

プロセスストアから実行済プロセスを開き、算出された予測精度を表示します。

[16]:
import re
import pandas as pd
from sampo.api import process_store

result = []
predict_proc_names = [src.name for src, _ in process_list if re.match('fabhmerg_predict.*', src.name)]
for predict_proc_name in predict_proc_names:
    row = {}
    with process_store.open_process(pstore_url, predict_proc_name) as prl:
        evaluation = prl.load_comp_output_evaluation('rg')
        row['process_name'] = predict_proc_name
        row['rmse'] = evaluation['root_mean_squared_error'][0]
        result.append(row)

pd.DataFrame(result).sort_values(by='rmse')
[16]:
process_name rmse
1 fabhmerg_predict_1 3.682181
3 fabhmerg_predict_3 3.804716
5 fabhmerg_predict_5 3.860132
0 fabhmerg_predict_0 3.916196
2 fabhmerg_predict_2 4.140845
4 fabhmerg_predict_4 4.152079

上記の表から、rmseの値が低いプロセス名の番号から、パラメーターの組み合わせを確認します。

[17]:
best_model = result[0]['process_name']
num_best_model = int(best_model[-1:])
spd_params[num_best_model]
[17]:
{'standardize_target': True, 'tree_depth': 3}

3.3. ランダムリスタートの目的と設計・実行方法

SAMPO/FABの異種混合学習コンポーネント(FABHMEBernGateLinearRgComponent)で作成するモデルは、ランダムに決定される初期状態から学習を開始します。 これは同じ分析対象データとハイパーパラメーターで学習を実行しても、実行するたびに異なるモデルが作成されることを示します。

そのため、より精度の高いモデルを選択するために分析プロセスを複数回実行することをランダムリスタートと言います。

ランダムリスタートでは、SRCのプロセス名が一意になるようにテンプレート構文を適用します。

下記のSPDとSRCを用いて、ランダムリスタートの実行例を示します。

[18]:
spd_content_random = '''
dl -> std  -> rg
   -> bexp -> rg

---

components:
    dl:
        component: DataLoader

    std:
        component: StandardizeFDComponent
        features: scale == 'real' or scale == 'integer'

    bexp:
        component: BinaryExpandFDComponent
        features: scale == 'nominal'

    rg:
        component: FABHMEBernGateLinearRgComponent
        features: name != 'mpg'
        target: name == 'mpg'
        standardize_target: True
        tree_depth: 3

global_settings:
    keep_attributes:
        - mpg
    feature_exclude:
        - mpg
'''
[19]:
# 学習用SRC
learn_src_random = '''
fabhmerg_learn_{{ run_times }}:
    type: learn

    data_sources:
        dl:
            df: {{ learn_data }}
            attr_schema: {{ asd }}
'''

# 予測用SRC
predict_src_random = '''
fabhmerg_predict_{{ run_times }}:
    type: predict

    data_sources:
        dl:
            df: {{ predict_data }}
            attr_schema: {{ asd }}

    model_process: fabhmerg_learn_{{ run_times }}
'''

SAMPO/FABが読み込めるように、SPDをgen_spd()関数で、学習用SRCをgen_src()関数で生成します。

[20]:
import logging
from sampo.api import sampo_logging
from sampo.api import gen_spd, gen_src
from sampotools.api import gen_asd_from_pandas_df

sampo_logging.configure(logging.INFO, filename='./fabhmerg_randomrestart.log')

process_list = []  # 並列実行するプロセスを保存するリスト
num_random_restarts = 5

for idx in range(num_random_restarts):
    src_param = {'run_times': idx , 'learn_data': learn_data, 'predict_data': predict_data, 'asd': asd}
    spd = gen_spd(template=spd_content_random)
    learn_src = gen_src(template=learn_src_random, params=src_param)
    predict_src = gen_src(template=predict_src_random, params=src_param)
    process_list.append((learn_src, spd))  # 学習用の分析プロセスの追加
    process_list.append((predict_src, None))  # 予測用の分析プロセスの追加

ランダムリスタートを実行します。

[21]:
from sampo.api import process_runner, process_store

pstore_url = './parallel_pstore'
process_store.create(pstore_url)

#ランダムリスタート実行
process_runner.session_run(process_list, pstore_url=pstore_url, max_workers=3)
[21]:
[('fabhmerg_learn_1.0555f2e3-ced0-4ed6-a5f9-0fd87a0d977a', None),
 ('fabhmerg_learn_0.c061ee34-5bfe-4cf4-a020-4abf274ef9f1', None),
 ('fabhmerg_learn_2.13a26f3b-bc8a-4bd3-86f9-2eac0384c398', None),
 ('fabhmerg_learn_3.eb000f49-c8f4-4197-a200-cb40ad2da087', None),
 ('fabhmerg_learn_4.d219f3dc-c390-4e81-bead-36cd48ad5565', None),
 ('fabhmerg_predict_1.c2c6c0c2-9366-4db2-ba7e-c5072796b82f', None),
 ('fabhmerg_predict_0.ace6592c-6b99-434a-b029-e702d46ac270', None),
 ('fabhmerg_predict_3.ec6dcfc1-e402-4282-bcc2-d27ae10586a1', None),
 ('fabhmerg_predict_2.ce690cf7-0a84-4ee9-8e12-254887703da3', None),
 ('fabhmerg_predict_4.ffc42403-a93d-4254-8207-d293e1641f0a', None)]
[22]:
import re
import pandas as pd
from sampo.api import process_store

result = []
predict_proc_names = [src.name for src, _ in process_list if re.match('fabhmerg_predict.*', src.name)]
for predict_proc_name in predict_proc_names:
    row = {}
    with process_store.open_process(pstore_url, predict_proc_name) as prl:
        evaluation = prl.load_comp_output_evaluation('rg')
        row['process_name'] = predict_proc_name
        row['rmse'] = evaluation['root_mean_squared_error'][0]
        result.append(row)

pd.DataFrame(result).sort_values(by='rmse')
[22]:
process_name rmse
3 fabhmerg_predict_3 3.632642
1 fabhmerg_predict_1 3.726962
4 fabhmerg_predict_4 3.798683
2 fabhmerg_predict_2 3.818484
0 fabhmerg_predict_0 4.227888

上記の結果から、作成したモデルの中から、RMSEが最小のモデルを選択することができます。

4. モデルの検証方法

本節では、複数存在するモデルの検証方法からSAMPO/FABでよく用いられる下記の例を示します。

  • ホールドアウト検証

  • 交差検証

4.1. ホールドアウト検証

 ホールドアウト検証は、学習用データでモデルを作成して検証用データでモデルの評価を行う検証方法です。

SPDは、3.2節のパラメーターチューニングの実行方法を流用します。

[23]:
spd_content_ho = '''
dl -> std  -> rg
   -> bexp -> rg

---

components:
    dl:
        component: DataLoader

    std:
        component: StandardizeFDComponent
        features: scale == 'real' or scale == 'integer'

    bexp:
        component: BinaryExpandFDComponent
        features: scale == 'nominal'

    rg:
        component: FABHMEBernGateLinearRgComponent
        features: name != 'mpg'
        target: name == 'mpg'
        standardize_target: {{ standardize_target }}
        tree_depth: {{ tree_depth }}

global_settings:
    keep_attributes:
        - mpg
    feature_exclude:
        - mpg
'''

SRCは、下記のテンプレート構文を用いた学習用と検証用を使用します。

[24]:
# 学習用SRC
learn_src_ho = '''
fabhmerg_learn_ho{{ run_times }}:
    type: learn

    data_sources:
        dl:
            df: {{ input_df }}
            attr_schema: {{ asd }}
            filters:
                 - k_split(3, 0, True)
'''

# 検証用SRC
predict_src_ho = '''
fabhmerg_predict_ho{{ run_times }}:
    type: predict

    data_sources:
        dl:
            df: {{ input_df }}
            attr_schema: {{ asd }}
            filters:
                 - k_split(3, 0, False)

    model_process: fabhmerg_learn_ho{{ run_times }}
'''

分析対象データをSRCに記述されているk_split()関数で学習用と検証用に分割します。

k_split()関数は、以下の内容を引数にて指定します。 - 第一引数 : 分析対象データを分割する数 k - 第二引数 : 分割したデータのindex (0 から k-1まで) - 第三引数 : Trueの場合、第二引数で指定したデータ以外を返す

上記のSRCでは、分析対象データを3分割にし、1つ目を検証用、残りを学習用に使用する指定にしています。

k_split()関数の詳細については、Analytics ReferenceSRC (SAMPO Run Configuration) Specificationを参照してください。

[25]:
import logging
from sampo.api import sampo_logging
import pandas as pd
from sampo.api import gen_spd, gen_src
from sampotools.api import gen_asd_from_pandas_df

sampo_logging.configure(logging.INFO, filename='./fabhmerg_ho.log')

process_list = []  # 並列実行するプロセスを保存するリスト
num_random_restarts = 5

for n in range(num_random_restarts):
    spd_param = {'tree_depth': 3 , 'standardize_target':True }
    src_param = {'run_times': n , 'input_df': input_data , 'asd': asd}
    spd = gen_spd(template=spd_content_ho, params=spd_param)
    learn_src = gen_src(template=learn_src_ho, params=src_param)
    predict_src = gen_src(template=predict_src_ho, params=src_param)
    process_list.append((learn_src, spd))  # 学習用の分析プロセスの追加
    process_list.append((predict_src, None))  # 予測用の分析プロセスの追加
[26]:
from sampo.api import process_runner, process_store

pstore_url = './parallel_pstore_hold_out'
process_store.create(pstore_url)

#ホールドアウト検証実行
process_runner.session_run(process_list, pstore_url=pstore_url, max_workers=3)
[26]:
[('fabhmerg_learn_ho0.dfd413c1-8d98-45d8-b47e-7bbd1bae63d4', None),
 ('fabhmerg_learn_ho2.949da768-90da-4eab-b98b-8433f79617aa', None),
 ('fabhmerg_learn_ho1.841cf70d-95f6-45a9-b7f2-7744bfa0a325', None),
 ('fabhmerg_predict_ho0.0bd40baa-a5d0-40c6-8e1d-878df3b50512', None),
 ('fabhmerg_predict_ho2.86d00f75-1c2b-46af-8c44-83cbb2c583c1', None),
 ('fabhmerg_learn_ho4.6f4da795-8a43-4fdf-855a-984c12e5a6d3', None),
 ('fabhmerg_learn_ho3.a7c1c0d6-c3c0-470a-939b-64d8b91cd681', None),
 ('fabhmerg_predict_ho4.bdf53cf5-3b9c-4a85-8eac-730ad73af60a', None),
 ('fabhmerg_predict_ho1.3cfe4864-e9cf-4c66-a139-d3150c253eae', None),
 ('fabhmerg_predict_ho3.e7052729-b760-4aad-9c17-bd3eba68e2ca', None)]
[27]:
import re
import pandas as pd
from sampo.api import process_store

result = []
predict_proc_names = [src.name for src, _ in process_list if re.match('fabhmerg_predict.*', src.name)]
for predict_proc_name in predict_proc_names:
    row = {}
    with process_store.open_process(pstore_url, predict_proc_name) as prl:
        evaluation = prl.load_comp_output_evaluation('rg')
        row['process_name'] = predict_proc_name
        row['rmse'] = evaluation['root_mean_squared_error'][0]
        result.append(row)

pd.DataFrame(result).sort_values(by='rmse')
[27]:
process_name rmse
2 fabhmerg_predict_ho2 3.539923
3 fabhmerg_predict_ho3 4.184492
1 fabhmerg_predict_ho1 4.382446
4 fabhmerg_predict_ho4 4.596399
0 fabhmerg_predict_ho0 4.791177

上記から、ホールドアウト検証を行った検証結果として予測精度のRMSEが確認できます。

4.2. 交差検証

 交差検証は、分析対象データを分割し、学習用と検証用の組み合わせを入れ替えながら実行する検証方法です。 ホールドアウト検証と比べて、1度の検証回数が多くなることで実行時間が長くなりますが、全パターンの評価結果の平均値をとるので信頼が高くなります。

交差検証にはいくつか種類があり、以下でK分割交差検証の実行例を示します。

[28]:
spd_content_cv = '''
dl -> std  -> rg
   -> bexp -> rg

---

components:
    dl:
        component: DataLoader

    std:
        component: StandardizeFDComponent
        features: scale == 'real' or scale == 'integer'

    bexp:
        component: BinaryExpandFDComponent
        features: scale == 'nominal'

    rg:
        component: FABHMEBernGateLinearRgComponent
        features: name != 'mpg'
        target: name == 'mpg'
        standardize_target: {{ standardize_target }}
        tree_depth: {{ tree_depth }}

global_settings:
    keep_attributes:
        - mpg
    feature_exclude:
        - mpg
'''

以下のSRCでは、プロセス名のrrがランダムリスタートの回数、splitが指定したデータのindexを示しています。

[29]:
# 学習用SRC
learn_src_cv = '''
fabhmerg_learn_rr{{ run_times }}_split{{ split_position }}:
    type: learn

    data_sources:
        dl:
            df: {{ input_df }}
            attr_schema: {{ asd }}
            filters:
                 - k_split({{ k_split }}, {{ split_position }}, True)
'''

# 検証用SRC
predict_src_cv = '''
fabhmerg_predict_rr{{ run_times }}_split{{ split_position }}:
    type: predict

    data_sources:
        dl:
            df: {{ input_df }}
            attr_schema: {{ asd }}
            filters:
                 - k_split({{ k_split }}, {{ split_position }}, False)

    model_process: fabhmerg_learn_rr{{ run_times }}_split{{ split_position }}
'''

上記のSPDとSRCを用いて、3-分割交差検証をランダムリスタートで3回実行します。

[30]:
import logging
from sampo.api import sampo_logging
from sampo.api import gen_spd, gen_src
from sampotools.api import gen_asd_from_pandas_df

sampo_logging.configure(logging.INFO, filename='./fabhmerg_cv.log')

process_list = []  # 並列実行するプロセスを保存するリスト
num_random_restarts = 3
num_split = 3      #分割する数

# 交差検証実行
for rr in range(num_random_restarts):
    for k in range(num_split):
        spd_param = {'tree_depth': 3, 'standardize_target': True }
        src_param = {'run_times': rr ,  'input_df': input_data, 'k_split': num_split, 'split_position': k , 'asd': asd}
        spd = gen_spd(template=spd_content_cv, params=spd_param)
        learn_src = gen_src(template=learn_src_cv, params=src_param)
        predict_src = gen_src(template=predict_src_cv, params=src_param)
        process_list.append((learn_src, spd))  # 学習用の分析プロセスの追加
        process_list.append((predict_src, None))  # 予測用の分析プロセスの追加
[31]:
from sampo.api import process_runner, process_store

pstore_url = './parallel_pstore_cv'
process_store.create(pstore_url)

process_runner.session_run(process_list, pstore_url=pstore_url, max_workers=3)
[31]:
[('fabhmerg_learn_rr0_split2.a6854723-bb24-42c0-a297-5ebfc1a3c9cd', None),
 ('fabhmerg_learn_rr0_split0.24e3c4b7-8989-49c8-895c-6e35618b788b', None),
 ('fabhmerg_learn_rr0_split1.7422ae74-82cd-490e-ba56-a632335ed504', None),
 ('fabhmerg_learn_rr1_split0.92eb3f1a-e732-476f-86fb-62bad71a84c6', None),
 ('fabhmerg_learn_rr1_split1.16dc4ff2-7b96-4846-94c7-e073bad03486', None),
 ('fabhmerg_learn_rr1_split2.e5d37eba-5510-4a7b-9c06-7d36feced671', None),
 ('fabhmerg_learn_rr2_split1.852c4344-5a58-4d37-8aa7-cb1263f5131b', None),
 ('fabhmerg_learn_rr2_split0.ae895fcd-7b09-4d7f-b89f-1bd6c258c223', None),
 ('fabhmerg_learn_rr2_split2.e465bcd3-d1f5-4cc3-94bc-06c26e445fa4', None),
 ('fabhmerg_predict_rr0_split2.eaf65065-8c8c-48e7-b610-0688d492045d', None),
 ('fabhmerg_predict_rr0_split0.606e8a9e-62df-4356-bc53-0728a5b64ca7', None),
 ('fabhmerg_predict_rr1_split0.d38f5a79-bc1a-4d3a-a76f-610d836ce545', None),
 ('fabhmerg_predict_rr1_split1.0719da35-12a7-4767-921e-8297f37f7a6e', None),
 ('fabhmerg_predict_rr0_split1.6f254508-14a6-48f9-b295-1a189f61c063', None),
 ('fabhmerg_predict_rr2_split1.3814e0b8-38a7-4db9-8544-6d7a18a29435', None),
 ('fabhmerg_predict_rr1_split2.356964d1-a644-429f-b82e-e7edfb3da1c0', None),
 ('fabhmerg_predict_rr2_split0.fb026f46-8192-4321-b1be-f3b54b26bf57', None),
 ('fabhmerg_predict_rr2_split2.c30218aa-ebdb-4cfa-94d2-a6067938a9ec', None)]
[32]:
import re
import pandas as pd
from sampo.api import process_store

result = []
predict_proc_names = [src.name for src, _ in process_list if re.match('fabhmerg_predict.*', src.name)]
for predict_proc_name in predict_proc_names:
    row = {}
    with process_store.open_process(pstore_url, predict_proc_name) as prl:
        evaluation = prl.load_comp_output_evaluation('rg')
        row['process_name'] = predict_proc_name
        row['rmse'] = evaluation['root_mean_squared_error'][0]
        result.append(row)

pd.DataFrame(result).sort_values('process_name')
[32]:
process_name rmse
0 fabhmerg_predict_rr0_split0 4.532768
1 fabhmerg_predict_rr0_split1 4.638185
2 fabhmerg_predict_rr0_split2 5.321502
3 fabhmerg_predict_rr1_split0 4.156640
4 fabhmerg_predict_rr1_split1 2.355842
5 fabhmerg_predict_rr1_split2 5.546513
6 fabhmerg_predict_rr2_split0 3.592213
7 fabhmerg_predict_rr2_split1 2.406080
8 fabhmerg_predict_rr2_split2 5.186844

上記から交差検証を行った結果が確認できます。

ページトップへ