UPDATE: 2022-12-25 11:54:23
tidymodels
パッケージの使い方をいくつかのノートに分けてまとめている。tidymodels
パッケージは、統計モデルや機械学習モデルを構築するために必要なパッケージをコレクションしているパッケージで、非常に色んなパッケージがある。ここでは、今回はtune/dials
というパッケージの使い方をまとめていく。モデルの数理的な側面や機械学習の用語などは、このノートでは扱わない。
下記の公式ドキュメントやtidymodels
パッケージに関する書籍を参考にしている。
tune
とdials
パッケージの目的tune
パッケージは、tidymodels
パッケージを利用したモデリングにおいて、ハイパーパラメーターのチューニングを効率よく実行するためのパッケージで、dials
パッケージは、同じくチューニングパラメーターの値を作成および管理することを目的としている。tidymodels
パッケージでモデリングする際は、これらのパッケージを利用することで効率よくハイパーパラメーターのチューニングを行える。
公式ドキュメントは下記の通り。
パッケージやモデリングの作業と関連づけるために色々してたせいで、変数名がワケワカメなのはご愛嬌…。
tune/dials
パッケージの実行例tune/dials
パッケージの基本的な利用方法を確認する前に、必要なオブジェクトを定義しておく。関数の使い方をまとめることが目的なので、ここでは動けば良い程度にレシピを作成しておく。
library(tidymodels)
library(tidyverse)
<- read_csv("https://raw.githubusercontent.com/SugiAki1989/statistical_note/main/note_TidyModels00/df_past.csv")
df_past
# rsample
set.seed(1989)
<- df_past %>% initial_split(prop = 0.8, strata = "Status")
df_initial <- df_initial %>% training()
df_train <- df_initial %>% testing()
df_test
set.seed(1989)
<-
df_train_stratified_splits vfold_cv(df_train, v = 5, strata = "Status")
# recipes
<- recipe(Status ~ ., data = df_train) %>%
recipe step_impute_bag(Income, impute_with = imp_vars(Marital, Expenses)) %>%
step_impute_bag(Assets, impute_with = imp_vars(Marital, Expenses, Income)) %>%
step_impute_bag(Debt, impute_with = imp_vars(Marital, Expenses, Income, Assets)) %>%
step_impute_bag(Home, impute_with = imp_vars(Marital, Expenses, Income, Assets, Debt)) %>%
step_impute_bag(Marital, impute_with = imp_vars(Marital, Expenses, Income, Assets, Debt, Home)) %>%
step_impute_bag(Job, impute_with = imp_vars(Marital, Expenses, Income, Assets, Debt, Home, Marital))
ハイパーパラメータのチューニングを行う場合、モデルの設定段階で、パラメタを定数で設定するのではなく、tune
関数を利用してモデル設定を行う必要がある。ランダムフォレストの各パラメタの簡単な説明は下記のとおり。
mtry
:
各決定木が使用する特徴量の数を指定する。ランダムフォレストでは、各決定木を作成する際に、特徴量をランダムに選択して使用するため、mtry
で指定された数の中から、ランダムに選択される特徴量の数を決定する。
min_n
:
各決定木が分割する前に保持する最小サンプルサイズを指定する。min_n
を小さくすることで、各決定木の複雑度を増やすことができる一方で、min_n
を小さくすると、各決定木が少ないサンプルで訓練されるため、過学習の可能性が増える。
trees
:
ランダムフォレストに含まれる決定木の数を指定する。trees
を増やすことで、ランダムフォレストの汎化性能を高めることができる一方で、trees
を増やすと、訓練時間が長くなる。
# parsnip
<- rand_forest(mtry = tune(), trees = tune(), min_n = tune()) %>%
model set_engine("ranger", importance = "permutation") %>%
set_mode("classification")
<- workflow() %>%
workflow add_recipe(recipe) %>%
add_model(model)
次は探索グリッドを作成する。ワークフローをモデル設定とレシピを利用して作成し、追加でパラメタ関連の設定を行なうが、モデルに対してデフォルトで探索範囲が決まっていることもある。extract_parameter_set_dials
関数で確認できる。
%>%
workflow extract_parameter_set_dials()
## Collection of 3 parameters for tuning
##
## identifier type object
## mtry mtry nparam[?]
## trees trees nparam[+]
## min_n min_n nparam[+]
##
## Model parameters needing finalization:
## # Randomly Selected Predictors ('mtry')
##
## See `?dials::finalize` or `?dials::update.parameters` for more information.
3つのパラメタがチューニング対象になっており、object
列を見ると、?
や+
が表示されている。各詳細を確認するためには、extract_parameter_dials
関数でパラメタ名を指定する。
mtry
は[1,?]
となっており、各決定木が使用する特徴量の数の上限が決まっていないことを表している。他のパラメタは下限と上限がデフォルトで定まっている。つまり、mtry
の上限はデータセットの内容に応じて変化するので、デフォルトでは設定されていない。
map(
.x = c("mtry", "trees", "min_n"),
.f = function(x){
%>%
workflow extract_parameter_set_dials() %>%
extract_parameter_dials(x)
} )
## [[1]]
## # Randomly Selected Predictors (quantitative)
## Range: [1, ?]
##
## [[2]]
## # Trees (quantitative)
## Range: [1, 2000]
##
## [[3]]
## Minimal Node Size (quantitative)
## Range: [2, 40]
デフォルトで設定されていないパラメタの範囲を決める必要がある。パラメタの範囲を更新する際はupdate
関数を利用すればよい。
map(
.x = c("mtry", "trees", "min_n"),
.f = function(x){
%>%
workflow extract_parameter_set_dials() %>%
update(
mtry = mtry(range = c(5, 10)),
trees = trees(range = c(500, 1000)),
min_n = min_n(range = c(50, 100)),
%>%
) extract_parameter_dials(x)}
)
## [[1]]
## # Randomly Selected Predictors (quantitative)
## Range: [5, 10]
##
## [[2]]
## # Trees (quantitative)
## Range: [500, 1000]
##
## [[3]]
## Minimal Node Size (quantitative)
## Range: [50, 100]
今回のmtry
のようなデータに合わせてパラメタを設定したいときは、finalize
関数と訓練データを渡すことで、よしなに設定してくれる。
finalize
関数の中の部分では、ターゲットの目的変数を除外して、レシピで設定している前処理を実行して、カラム数を確定させている。ここではカラム数だけわかればよいので、slice
関数でレコードを減らしている。前処理が重たいと、bake
関数の処理に時間がかかることを避けるために行った(1行とかにすると、前処理で使用している関数によっては警告やエラーが出るかも)。
map(
.x = c("mtry", "trees", "min_n"),
.f = function(x){
%>%
workflow extract_parameter_set_dials() %>%
update(
trees = trees(range = c(500, 1000)),
min_n = min_n(range = c(50, 100)),
%>%
) finalize(
%>%
recipe prep() %>%
bake(df_train %>% select(-Status) %>% dplyr::slice(1:3))
%>%
) extract_parameter_dials(x)}
)
## [[1]]
## # Randomly Selected Predictors (quantitative)
## Range: [1, 13]
##
## [[2]]
## # Trees (quantitative)
## Range: [500, 1000]
##
## [[3]]
## Minimal Node Size (quantitative)
## Range: [50, 100]
パラメタグリッドを作成するときは、grid_regular
関数を利用する。levels
引数は各パラメタが取れる値の数を決めるもので、今回の場合であれば、パラメタが3つで、取れるレベルが2つなので、2^3=8
のグリッド作成される。
%>%
workflow extract_parameter_set_dials() %>%
update(
mtry = mtry(range = c(5, 10)),
trees = trees(range = c(500, 1000)),
min_n = min_n(range = c(50, 100)),
%>%
) grid_regular(levels = 2)
## # A tibble: 8 × 3
## mtry trees min_n
## <int> <int> <int>
## 1 5 500 50
## 2 10 500 50
## 3 5 1000 50
## 4 10 1000 50
## 5 5 500 100
## 6 10 500 100
## 7 5 1000 100
## 8 10 1000 100
グリッドの作成方法を変える場合は下記の関数を利用できる。
grid_random(size = n)
関数grid_latin_hypercube(size = n)
関数grid_max_entropy(size = n)
関数ではグリッドを作成してハイパーパラメータのチューニングを行う。モデルとレシピがまとまっているワークフローを利用して、モデル情報を使ってグリッドを作成する。
set.seed(1989)
<- workflow %>%
hyper_parameter_grid extract_parameter_set_dials() %>%
update(
mtry = mtry(range = c(5, 10)),
trees = trees(range = c(500, 1000)),
min_n = min_n(range = c(50, 100)),
%>%
) grid_regular(levels = 2)
hyper_parameter_grid
## # A tibble: 8 × 3
## mtry trees min_n
## <int> <int> <int>
## 1 5 500 50
## 2 10 500 50
## 3 5 1000 50
## 4 10 1000 50
## 5 5 500 100
## 6 10 500 100
## 7 5 1000 100
## 8 10 1000 100
前回までのようにパラメタが固定されていれば、fit_resamples
関数でクロスバリデーションを行うことができたが、今回はモデル設定でパラメタにはtune
関数を指定しているため、fit_resamples
関数を使うことはできない。
%>%
workflow fit_resamples(
resamples = df_train_stratified_splits,
metrics = metric_set(accuracy),
control = control_resamples(save_pred = TRUE)
)
:
Error! 3 arguments have been tagged for tuning in these components: model_spec.
functions (e.g. `tune_grid()`) to optimize them.
Please use one of the tuning `rlang::last_error()` to see where the error occurred. Run
そのため、エラー文にもあるように、tune_grid
関数を利用する。
<-
workflow_tuned %>%
workflow tune_grid(
resamples = df_train_stratified_splits,
grid = hyper_parameter_grid,
metrics = metric_set(accuracy),
control = control_resamples(
extract = extract_model, # 出力の.extractsに対応
save_pred = TRUE # 出力の.predictionsに対応
) )
中身を確認すると、いくつかのカラムができており、内容は下記の通り。
splits
:
クロスバリデーションのために分割されたデータid
: 分割されたデータのフォールド番号.metrics
: 評価指標の値.notes
: エラー、ワーニングなどの情報.extracts
:
各パラメタのグリッドに応じたモデルの情報.predictions
:
評価指標を計算するために利用したデータの観測値とモデルの予測値ハイパーパラメータチューニング(grid = 8
)のグリッド数と5フォールドクロスバリデーション(cv = 5
)を利用しているので少し出力が複雑ではあるが、合計40行が出力されることになる。
つまり、1つのパラメタの組み合わせを5つのフォールドに対して行なうため、評価指標は5レコード分作成される。これをパラメタの組み合わせ分として8回繰り返す。pluck(".metrics", 1)
で表示されるのは8つのパラメタ組み合わせの1つ目のフォールの評価結果。
%>%
workflow_tuned pluck(".metrics", 1)
## # A tibble: 8 × 7
## mtry trees min_n .metric .estimator .estimate .config
## <int> <int> <int> <chr> <chr> <dbl> <chr>
## 1 5 500 50 accuracy binary 0.796 Preprocessor1_Model1
## 2 10 500 50 accuracy binary 0.785 Preprocessor1_Model2
## 3 5 1000 50 accuracy binary 0.793 Preprocessor1_Model3
## 4 10 1000 50 accuracy binary 0.787 Preprocessor1_Model4
## 5 5 500 100 accuracy binary 0.794 Preprocessor1_Model5
## 6 10 500 100 accuracy binary 0.794 Preprocessor1_Model6
## 7 5 1000 100 accuracy binary 0.799 Preprocessor1_Model7
## 8 10 1000 100 accuracy binary 0.801 Preprocessor1_Model8
.extracts
にはモデルの情報が格納されている。
%>%
workflow_tuned pluck(".extracts", 1)
## # A tibble: 8 × 5
## mtry trees min_n .extracts .config
## <int> <int> <int> <list> <chr>
## 1 5 500 50 <ranger> Preprocessor1_Model1
## 2 10 500 50 <ranger> Preprocessor1_Model2
## 3 5 1000 50 <ranger> Preprocessor1_Model3
## 4 10 1000 50 <ranger> Preprocessor1_Model4
## 5 5 500 100 <ranger> Preprocessor1_Model5
## 6 10 500 100 <ranger> Preprocessor1_Model6
## 7 5 1000 100 <ranger> Preprocessor1_Model7
## 8 10 1000 100 <ranger> Preprocessor1_Model8
.predictions
の中身は、予測結果が記録されている。.predictions
の中身は、予測値.pred_class
、行番号.row
、観測値Status
、何番目のフォールドのモデルなのか.config
が記録されている。
5136行あるのは、1つのフォールドの評価データは642行だが、8つのパラメタの組み合わせ分が計算されているので、642 × 8 = 5136
レコードとなる。
%>%
workflow_tuned pluck(".predictions", 1)
## # A tibble: 5,136 × 7
## .pred_class .row mtry trees min_n Status .config
## <fct> <int> <int> <int> <int> <fct> <chr>
## 1 bad 2 5 500 50 bad Preprocessor1_Model1
## 2 bad 11 5 500 50 bad Preprocessor1_Model1
## 3 bad 14 5 500 50 bad Preprocessor1_Model1
## 4 bad 18 5 500 50 bad Preprocessor1_Model1
## 5 good 19 5 500 50 bad Preprocessor1_Model1
## 6 good 24 5 500 50 bad Preprocessor1_Model1
## 7 good 26 5 500 50 bad Preprocessor1_Model1
## 8 good 30 5 500 50 bad Preprocessor1_Model1
## 9 good 35 5 500 50 bad Preprocessor1_Model1
## 10 bad 43 5 500 50 bad Preprocessor1_Model1
## # … with 5,126 more rows
評価結果をまとめると、さきほほどの話はわかりよい。
map_dfr(
.x = 1:nrow(df_train_stratified_splits),
.f = function(x){workflow_tuned %>% pluck(".metrics", x)}
%>%
) arrange(.config) %>%
print(n = 50)
## # A tibble: 40 × 7
## mtry trees min_n .metric .estimator .estimate .config
## <int> <int> <int> <chr> <chr> <dbl> <chr>
## 1 5 500 50 accuracy binary 0.796 Preprocessor1_Model1
## 2 5 500 50 accuracy binary 0.801 Preprocessor1_Model1
## 3 5 500 50 accuracy binary 0.777 Preprocessor1_Model1
## 4 5 500 50 accuracy binary 0.774 Preprocessor1_Model1
## 5 5 500 50 accuracy binary 0.766 Preprocessor1_Model1
## 6 10 500 50 accuracy binary 0.785 Preprocessor1_Model2
## 7 10 500 50 accuracy binary 0.801 Preprocessor1_Model2
## 8 10 500 50 accuracy binary 0.769 Preprocessor1_Model2
## 9 10 500 50 accuracy binary 0.780 Preprocessor1_Model2
## 10 10 500 50 accuracy binary 0.764 Preprocessor1_Model2
## 11 5 1000 50 accuracy binary 0.793 Preprocessor1_Model3
## 12 5 1000 50 accuracy binary 0.802 Preprocessor1_Model3
## 13 5 1000 50 accuracy binary 0.775 Preprocessor1_Model3
## 14 5 1000 50 accuracy binary 0.775 Preprocessor1_Model3
## 15 5 1000 50 accuracy binary 0.767 Preprocessor1_Model3
## 16 10 1000 50 accuracy binary 0.787 Preprocessor1_Model4
## 17 10 1000 50 accuracy binary 0.804 Preprocessor1_Model4
## 18 10 1000 50 accuracy binary 0.774 Preprocessor1_Model4
## 19 10 1000 50 accuracy binary 0.783 Preprocessor1_Model4
## 20 10 1000 50 accuracy binary 0.767 Preprocessor1_Model4
## 21 5 500 100 accuracy binary 0.794 Preprocessor1_Model5
## 22 5 500 100 accuracy binary 0.790 Preprocessor1_Model5
## 23 5 500 100 accuracy binary 0.764 Preprocessor1_Model5
## 24 5 500 100 accuracy binary 0.774 Preprocessor1_Model5
## 25 5 500 100 accuracy binary 0.764 Preprocessor1_Model5
## 26 10 500 100 accuracy binary 0.794 Preprocessor1_Model6
## 27 10 500 100 accuracy binary 0.798 Preprocessor1_Model6
## 28 10 500 100 accuracy binary 0.766 Preprocessor1_Model6
## 29 10 500 100 accuracy binary 0.780 Preprocessor1_Model6
## 30 10 500 100 accuracy binary 0.769 Preprocessor1_Model6
## 31 5 1000 100 accuracy binary 0.799 Preprocessor1_Model7
## 32 5 1000 100 accuracy binary 0.790 Preprocessor1_Model7
## 33 5 1000 100 accuracy binary 0.766 Preprocessor1_Model7
## 34 5 1000 100 accuracy binary 0.772 Preprocessor1_Model7
## 35 5 1000 100 accuracy binary 0.766 Preprocessor1_Model7
## 36 10 1000 100 accuracy binary 0.801 Preprocessor1_Model8
## 37 10 1000 100 accuracy binary 0.799 Preprocessor1_Model8
## 38 10 1000 100 accuracy binary 0.764 Preprocessor1_Model8
## 39 10 1000 100 accuracy binary 0.780 Preprocessor1_Model8
## 40 10 1000 100 accuracy binary 0.767 Preprocessor1_Model8
この評価データを平均すれば、各パラメタで学習したモデルの評価が得られる。
map_dfr(
.x = 1:nrow(df_train_stratified_splits),
.f = function(x){workflow_tuned %>% pluck(".metrics", x)}
%>%
) # .configだけでもよいが、パラメタの数字を明示するために下記を利用
group_by(.config, mtry, trees, min_n) %>%
summarise(mean_accuracy = mean(.estimate), n = n())
## # A tibble: 8 × 6
## # Groups: .config, mtry, trees [8]
## .config mtry trees min_n mean_accuracy n
## <chr> <int> <int> <int> <dbl> <int>
## 1 Preprocessor1_Model1 5 500 50 0.783 5
## 2 Preprocessor1_Model2 10 500 50 0.780 5
## 3 Preprocessor1_Model3 5 1000 50 0.783 5
## 4 Preprocessor1_Model4 10 1000 50 0.783 5
## 5 Preprocessor1_Model5 5 500 100 0.777 5
## 6 Preprocessor1_Model6 10 500 100 0.781 5
## 7 Preprocessor1_Model7 5 1000 100 0.779 5
## 8 Preprocessor1_Model8 10 1000 100 0.782 5
手計算しなくてもcollect_metrics
関数を使うことで、各パラメタのクロスバリデーションの結果を集計して表示してくれる。今回であれば、データを5つに分割しており、その各フォールドの結果がまとめられている。結果を見るとPreprocessor1_Model4
のaccuracy
が高いので、ベターなパラメタの組み合わせはmtry = 10 & trees = 1000 & min_n = 50
である。
%>%
workflow_tuned collect_metrics() %>%
arrange(desc(mean))
## # A tibble: 8 × 9
## mtry trees min_n .metric .estimator mean n std_err .config
## <int> <int> <int> <chr> <chr> <dbl> <int> <dbl> <chr>
## 1 10 1000 50 accuracy binary 0.783 5 0.00624 Preprocessor1_Model4
## 2 5 1000 50 accuracy binary 0.783 5 0.00645 Preprocessor1_Model3
## 3 5 500 50 accuracy binary 0.783 5 0.00671 Preprocessor1_Model1
## 4 10 1000 100 accuracy binary 0.782 5 0.00765 Preprocessor1_Model8
## 5 10 500 100 accuracy binary 0.781 5 0.00643 Preprocessor1_Model6
## 6 10 500 50 accuracy binary 0.780 5 0.00642 Preprocessor1_Model2
## 7 5 1000 100 accuracy binary 0.779 5 0.00675 Preprocessor1_Model7
## 8 5 500 100 accuracy binary 0.777 5 0.00632 Preprocessor1_Model5
自分で並び替えずとも、show_best
関数を利用すると集計後の結果を上位順で表示してくれる。
%>%
workflow_tuned show_best(n = 5, metric = "accuracy")
## # A tibble: 5 × 9
## mtry trees min_n .metric .estimator mean n std_err .config
## <int> <int> <int> <chr> <chr> <dbl> <int> <dbl> <chr>
## 1 10 1000 50 accuracy binary 0.783 5 0.00624 Preprocessor1_Model4
## 2 5 1000 50 accuracy binary 0.783 5 0.00645 Preprocessor1_Model3
## 3 5 500 50 accuracy binary 0.783 5 0.00671 Preprocessor1_Model1
## 4 10 1000 100 accuracy binary 0.782 5 0.00765 Preprocessor1_Model8
## 5 10 500 100 accuracy binary 0.781 5 0.00643 Preprocessor1_Model6
パラメタチューニングの結果を可視化したいときは、autoplot
関数を利用する。自分で作成せず、autoplot
関数で作成するので、ぱっと見てもよくわからないが、縦軸はaccuracy
、横軸はmtry
である。まずは色分けに着目する。緑がtrees = 1000
の場合で、赤がtrees = 500
の場合なので、これは緑のほうが良い。左の赤線をのぞいて、mtry
は高いほうが良い。一方で、min_n
が小さく、trees
も少ないが、mtry
を大きくすると、性能が悪くなることがわかる。
autoplot(workflow_tuned) + theme_bw()
良き評価指標のモデルを取り出すにはselect_best
関数を利用する。ベターなパラメタの組み合わせであるmtry = 10 & trees = 1000 & min_n = 50
が取り出されている。
<- workflow_tuned %>%
better_paramters select_best(metric = "accuracy")
better_paramters
## # A tibble: 1 × 4
## mtry trees min_n .config
## <int> <int> <int> <chr>
## 1 10 1000 50 Preprocessor1_Model4
パラメタチューニングまで終わったので、ここではベターなモデルで訓練データ全体を使って学習し直す方法でモデルを再学習する。先程のパラメタを使ってモデル設計をし直す必要はなく、finalize_workflow
関数をすれば、ベターモデルでワークフローを更新できる。
<- workflow %>%
better_workflow finalize_workflow(parameters = better_paramters)
better_workflow
## ══ Workflow ════════════════════════════════════════════════════════════════════
## Preprocessor: Recipe
## Model: rand_forest()
##
## ── Preprocessor ────────────────────────────────────────────────────────────────
## 6 Recipe Steps
##
## • step_impute_bag()
## • step_impute_bag()
## • step_impute_bag()
## • step_impute_bag()
## • step_impute_bag()
## • step_impute_bag()
##
## ── Model ───────────────────────────────────────────────────────────────────────
## Random Forest Model Specification (classification)
##
## Main Arguments:
## mtry = 10
## trees = 1000
## min_n = 50
##
## Engine-Specific Arguments:
## importance = permutation
##
## Computational engine: ranger
ワークフローでは、1つのパラメタに固定値を2つ以上設定することはできないので、複数のモデルからアンサンブルする場合などはワークフローに別々のパラメタを設定する必要がある。
%>%
workflow finalize_workflow(
parameters = workflow_tuned %>% show_best(n = 2, metric = "accuracy") %>% select(mtry, trees, min_n)
)
in `check_final_param()`:
Error ! The parameter tibble should have a single row.
:
Backtrace1. workflow %>% ...
2. tune::finalize_workflow(...)
3. tune:::check_final_param(parameters)
ベターなパラメタを用いてワークフローを更新したので、そのワークフローで訓練データを使って再学習を行なう。
set.seed(1989)
<-
model_trained_better_workflow %>%
better_workflow fit(df_train)
model_trained_better_workflow
## ══ Workflow [trained] ══════════════════════════════════════════════════════════
## Preprocessor: Recipe
## Model: rand_forest()
##
## ── Preprocessor ────────────────────────────────────────────────────────────────
## 6 Recipe Steps
##
## • step_impute_bag()
## • step_impute_bag()
## • step_impute_bag()
## • step_impute_bag()
## • step_impute_bag()
## • step_impute_bag()
##
## ── Model ───────────────────────────────────────────────────────────────────────
## Ranger result
##
## Call:
## ranger::ranger(x = maybe_data_frame(x), y = y, mtry = min_cols(~10L, x), num.trees = ~1000L, min.node.size = min_rows(~50L, x), importance = ~"permutation", num.threads = 1, verbose = FALSE, seed = sample.int(10^5, 1), probability = TRUE)
##
## Type: Probability estimation
## Number of trees: 1000
## Sample size: 3206
## Number of independent variables: 13
## Mtry: 10
## Target node size: 50
## Variable importance mode: permutation
## Splitrule: gini
## OOB prediction error (Brier s.): 0.1458116
再学習されたモデルでテストデータの値を予測する。ここでは予測クラスと予測確率を計算する。
<-
model_predicted_better_workflow tibble(
%>% predict(df_test, type = "class"),
model_trained_better_workflow %>% predict(df_test, type = "prob")
model_trained_better_workflow %>%
) bind_cols(obs = factor(df_test$Status, c(levels(.$.pred_class))))
model_predicted_better_workflow
## # A tibble: 802 × 4
## .pred_class .pred_bad .pred_good obs
## <fct> <dbl> <dbl> <fct>
## 1 bad 0.757 0.243 bad
## 2 bad 0.631 0.369 bad
## 3 bad 0.709 0.291 bad
## 4 good 0.488 0.512 bad
## 5 good 0.477 0.523 bad
## 6 bad 0.659 0.341 bad
## 7 bad 0.932 0.0681 bad
## 8 good 0.393 0.607 bad
## 9 bad 0.758 0.242 bad
## 10 good 0.257 0.743 bad
## # … with 792 more rows
最終的なテストデータに対する、accuracy
の数値は下記の通り。
%>%
model_predicted_better_workflow ::accuracy(truth = obs, estimate = .pred_class) yardstick
## # A tibble: 1 × 3
## .metric .estimator .estimate
## <chr> <chr> <dbl>
## 1 accuracy binary 0.802
再学習したモデルの変数重要度はこちら。
library(vip)
%>%
model_trained_better_workflow extract_fit_parsnip() %>%
vip(aesthetics = list(alpha = 0.8, fill = "#006E4F")) + theme_bw()
ここまでの例では、下記の通りパラメタグリッドを用意してからチューニングを行っていたが、グリッドを用意しない場合、どのようになるのか。
hyper_parameter_grid
## # A tibble: 8 × 3
## mtry trees min_n
## <int> <int> <int>
## 1 5 500 50
## 2 10 500 50
## 3 5 1000 50
## 4 10 1000 50
## 5 5 500 100
## 6 10 500 100
## 7 5 1000 100
## 8 10 1000 100
現状のワークフローは、mtry
は上限がきまってなく、trees
とmin_n
は下限、上限が決まっている状態。
map(
.x = c("mtry", "trees", "min_n"),
.f = function(x){
%>%
workflow extract_parameter_set_dials() %>%
extract_parameter_dials(x)
} )
## [[1]]
## # Randomly Selected Predictors (quantitative)
## Range: [1, ?]
##
## [[2]]
## # Trees (quantitative)
## Range: [1, 2000]
##
## [[3]]
## Minimal Node Size (quantitative)
## Range: [2, 40]
ドキュメントによると、どうやらグリッドが提供されない場合、ラテンハイパーキューブによってグリッドが作成されるとのこと。
A data frame of tuning combinations or a positive integer. The data frame should have columns for each parameter being tuned and rows for tuning parameter candidates. An integer denotes the number of candidate parameter sets to be created automatically. チューニングの組み合わせのデータフレーム、または正の整数。データフレームは,調整中の各パラメータの列と,調整パラメータ候補の行を持つ必要がある。整数は,自動的に作成されるパラメータセット候補の数を表す.
Parameter Grids If no tuning grid is provided, a semi-random grid (via dials::grid_latin_hypercube()) is created with 10 candidate parameter combinations. 調整用グリッドが提供されない場合、半ランダムグリッド (dials::grid_latin_hypercube() による) が、10個のパラメータ候補の組み合わせで作成されます。
set.seed(1989)
<-
workflow_tuned_no_grid %>%
workflow tune_grid(
resamples = df_train_stratified_splits,
metrics = metric_set(accuracy),
grid = 10,
control = control_resamples(
extract = extract_model, # 出力の.extractsに対応
save_pred = TRUE # 出力の.predictionsに対応
)
)
%>%
workflow_tuned_no_grid pluck(".extracts", 1) %>%
arrange(mtry)
## # A tibble: 10 × 5
## mtry trees min_n .extracts .config
## <int> <int> <int> <list> <chr>
## 1 2 1238 25 <ranger> Preprocessor1_Model10
## 2 3 715 37 <ranger> Preprocessor1_Model02
## 3 4 553 34 <ranger> Preprocessor1_Model06
## 4 5 216 3 <ranger> Preprocessor1_Model08
## 5 6 1583 11 <ranger> Preprocessor1_Model05
## 6 8 1170 30 <ranger> Preprocessor1_Model03
## 7 9 81 15 <ranger> Preprocessor1_Model09
## 8 10 934 9 <ranger> Preprocessor1_Model01
## 9 12 1742 21 <ranger> Preprocessor1_Model04
## 10 13 1901 19 <ranger> Preprocessor1_Model07