こんにちは,shun(@datasciencemore)です!!
今回はtidymodelsの{workflows}についてやっていきます.
0.{workflows}ってなに??
{workflows}は,レシピと学習ルールを1つにまとめるためのパッケージだよ!!
{workflows}でレシピと学習ルールを1つにまとめることで,より簡潔に処理を記述できるようになるんだ!!
前回は,学習ルール設定のためのパッケージ{parsnip}と特徴量エンジニアリングのためのパッケージ{recipes}を別々に説明しました.
当然,これらを別々に使用してもいいのですが,これらの機能を1つにまとめたほうが無駄がなく見通しが良くなるのです.
{workflows}の使い方はこんな感じです.
①workflow:workflowの定義
②add_recipe:レシピ(特徴量エンジニアリングの内容)の追加
③add_model:学習ルールの追加
コーディングはこうなります.
1 2 3 |
workflow() %>% add_recipe(rec) add_model(logistic_reg_glm_rule) |
これを実行すると,指定したレシピと学習ルールを示したワークフローが出力されます.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
══ Workflow ════════════════════════════════════════════════════════════════════════════════════════════════════════════════════ Preprocessor: Recipe Model: logistic_reg() ─ Preprocessor ──────────────────────────────────────────────────────── 2 Recipe Steps • step_mutate() • step_zv() ─ Model ──────────────────────────────────────────────────────────── Logistic Regression Model Specification (classification) Computational engine: glm |
1.予測モデリングの流れ(データ分割なし)
{workflows}を使用して,予測モデリングの流れを簡単に確認してみましょう.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
# データの定義 all = tibble(credit_data) initial_split = initial_split(all, prop = 0.80, strata = "Status") train = training(initial_split) test = testing(initial_split) # レシピの定義 rec = recipe(Status ~ ., data = train) %>% step_mutate( new = Income + Assets ) %>% step_zv(all_predictors()) # 学習ルールの定義 logistic_reg_glm_rule <- logistic_reg() %>% set_engine('glm') |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
# worflowf作成 wf = workflow() %>% add_recipe(rec) add_model(logistic_reg_glm_rule) # モデル構築 model_wf = wf %>% fit(data = train) # 予測値算出 pred_wf = model_wf %>% predict(new_data = test) |
こんな感じで予測値を算出することができます.(レシピや学習ルールの内容は適当です笑)
一方,{workflows}を使用しない場合は,このようになります.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
# モデル構築 model_not_wf = logistic_reg_glm_rule %>% fit(Status ~ ., prep(rec) %>% bake(train)) # 予測値算出(これだと学習時のデータと形が違うからエラー) pred_not_wf = model_not_wf %>% predict(new_data = test) # 予測値算出 pred_not_wf = model_not_wf %>% predict(new_data = prep(rec) %>% bake(test)) |
両方のコードを比較すると,{workflows}を使用したほうがすっきり記述できていることが確認できますね!
{workflows}を使用しない場合は,学習データ,評価データに特徴量エンジニアリングを適用する処理の部分が冗長になってしまうため,コードが少し見づらくなってしまいます..
また,予測値を算出するときに評価データに特徴量エンジニアリングを適用しないとエラーとなります.
{workflows}を使用したほうがコードの可読性も高まるため,積極的に{workflows}を使用していきましょう!!
2.予測モデリングの流れ(データ分割あり)
前項では,データ分割をしない場合の一番簡単な例を挙げました.
一般的には,データ分割をする場合のほうが多いですから,今度はデータ分割をしたとき,{workflows}を使用してどのように記述できるか確認しましょう.
といっても変更点はほとんどなく,データ分割をして,モデル構築の部分を少しだけ修正するだけでOKです.
※必要事項の定義は,前項と同じものを使用するので,省略しています.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
# データ分割 stratified_splits = vfold_cv(train, v = 4, strata = "Status") %>% with_seed(1234, .) # モデル構築(各fold) model_fold_wf = wf %>% fit_resamples( stratified_splits, metrics = metric_set(accuracy), control = control_resamples(save_pred = TRUE) ) |
3.補足
データ分割をした場合は,各foldのanalysisで学習し,assessmentで評価します.
作成したレシピは,
1 2 3 4 5 6 |
rec = recipe(Status ~ ., data = train) %>% step_mutate( new = Income + Assets ) %>% step_zv(all_predictors()) |
となっており,trainを指定していますが,{workflows}を使用すると各foldで学習するときに自動的にanalysisで学習をしてくれます.
このことは,以下のように{workflows}を使用しないでコーディングすると確認できます.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
# モデル構築(各fold) model_fold_not_wf = stratified_splits %>% rowwise() %>% mutate( .analysis = list(splits %>% analysis()), .assessment = list((splits %>% assessment())), .rec = list( recipe(Status ~ ., data = .analysis) %>% step_mutate( new = mean(Income) ) %>% step_zv(all_predictors()) ), .rule = list(logistic_reg_glmnet_spec), .analysis_rev = list(prep(.rec) %>% bake(new_data = .analysis)), .assessment_rev = list(prep(.rec) %>% bake(new_data = .assessment)), .model = list(.rule %>% fit(Status ~ ., data = .analysis_rev)), .pred = list( predict(.model, new_data = .assessment_rev) %>% bind_cols(.assessment_rev) ), .metrics = list( .pred %>% accuracy(truth = Status, estimate = .pred_class) ) ) |
model_fold_wfとmodel_fold_not_wfの.metrics 列の内容が全く同じなことが確認できますね!
まとめ
今回は,{workflows}についてやってきました.
{workflows}を使用するとレシピと学習ルールを1つにまとめてくれます.
そのようにすることでコーディングがしやすくなるのでしたね!
{workflows}を使用しなくてもできますが,わかりづらくなるので積極的に{workflows}を使用していきましょう!!