Rで何かをしたり、読書をするブログ

政府統計の総合窓口のデータや、OECDやUCIやのデータを使って、Rの練習をしています。ときどき、読書記録も載せています。

tidymodelsのワークフローに沿った回帰とクラシフィケーションの方法のサンプルコード

自分の忘備録として残しておきます。(最終更新日: 2025-08-24)

###################################################
####                                                                                             ####
####         tidymodelsで回帰分析・2値の分類をする方法         ####
####                                                                                             ####
###################################################
#
#########################################
#         glmnetエンジンでする方法(LASSO回帰)           #
#         rpartエンジンでする方法(決定木モデル)           #
#         kknnエンジンでする方法(k-NN法)                    #
#########################################
#
###########################################
#                                                                                        #
#         第1部: 被独立変数が数値の場合の回帰問題         #
#                                                                                        #
###########################################
#
# Step 1. 必要なパッケージの読み込み
library(tidyverse)
library(tidymodels)
library(glmnet)
library(rpart)
library(rpart.plot)
library(kknn)
tidymodels_prefer()
#
# Step 2. データの読み込み
data(iris)
#
# Step 3. トレーニング用とテスト用に分ける
set.seed(18)
iris_split <- initial_split(iris, prop = 0.8, strata = Sepal.Length)
iris_train <- training(iris_split)
iris_test <- testing(iris_split)
#
# Step 4. レシピ作成
iris_rec <- recipe(Sepal.Length ~ ., data = iris_train) |> 
  step_dummy(all_nominal_predictors()) |> 
  step_normalize(all_numeric_predictors())
#
# Step 5. モデル作成
# Step 5a, glmnetエンジンのモデル
glmnet_mod <- linear_reg(
  penalty = tune(),
  mixture = 1
) |> 
  set_engine("glmnet") |> 
  set_mode("regression")
#
# Step 5b. rpartエンジンのモデル
rpart_mod <- decision_tree(
  cost_complexity = tune(),
  tree_depth = tune(),
  min_n = tune()
) |> 
  set_engine("rpart") |> 
  set_mode("regression")
#
# Step 5c. kknnエンジンのモデル
kknn_mod <- nearest_neighbor(
  neighbors = tune()
) |> 
  set_engine("kknn") |> 
  set_mode("regression")
#
# Step 6. ワークフローの構築
# Step 6a. glmnetのワークフロー
glmnet_wf <- workflow() |> 
  add_recipe(iris_rec) |> 
  add_model(glmnet_mod)
#
# Step 6b. rpartのワークフロー
rpart_wf <- workflow() |> 
  add_recipe(iris_rec) |> 
  add_model(rpart_mod)
#
# Step 6c. kknnのワークフロー
kknn_wf <- workflow() |> 
  add_recipe(iris_rec) |> 
  add_model(kknn_mod)
#
# Step 7. クロスバリデーションデータの構築
set.seed(73)
cv_folds <- vfold_cv(iris_train, v = 10)
#
# Step 8. チューングリッドの作成
# Step 8a. glmnet用のチューングリッド
glmnet_grid <- grid_regular(
  penalty(range = c(-5, 0)),
  levels = 20
)
#
# Step 8b. rpart用のチューングリッド
rpart_grid <- grid_regular(
  cost_complexity(range = c(-4, -1)),
  tree_depth(range = c(1, 6)),
  min_n(range = c(3, 8)),
  levels = 3
)
#
# Step 8c. kknn用のグリッド
kknn_grid <- grid_regular(
  neighbors(range = c(3, 30)),
  levels = 15
)
#
# Step 9. チューニングの実行
# Step 9a. glmnetのチューニング実行
glmnet_tune <- tune_grid(
  glmnet_wf,
  resamples = cv_folds,
  grid = glmnet_grid,
  metrics = metric_set(rmse)
)
#
# Step 9b. rpartのチューニング実行
rpart_tune <- tune_grid(
  rpart_wf,
  resamples = cv_folds,
  grid = rpart_grid,
  metrics = metric_set(rmse)
)
#
# Step 9c. kknnのチューニング実行
kknn_tune <- tune_grid(
  kknn_wf,
  resamples = cv_folds,
  grid = kknn_grid,
  metrics = metric_set(rmse)
)
#
# Step 10. 最適なパラメータの抽出
# Step 10a. glmnetの最適なパラメータ
glmnet_best_params <- select_best(glmnet_tune, "rmse")
#
# Step 10b. rpartの最適なパラメータ
rpart_best_params <- select_best(rpart_tune, "rmse")
rpart_best_params
#
# Step 10c. kknnの最適なパラメータ
kknn_best_params <- select_best(kknn_tune, "rmse")
#
# Step 11. 最終ワークフロー構築
# Step 11a. glmnetの最終ワークフロー
glmnet_final_wf <- finalize_workflow(
  glmnet_wf,
  glmnet_best_params
)
#
# Step 11b. rpartの最終ワークフロー
rpart_final_wf <- finalize_workflow(
  rpart_wf,
  rpart_best_params
)
#
# Step 11c. kknnの最終ワークフロー
kknn_final_wf <- finalize_workflow(
  kknn_wf,
  kknn_best_params
)
#
# Step 12. 最終モデルをfit
# Step 12a. glmnetの最終モデルfit
glmnet_fit <- fit(glmnet_final_wf, data = iris_train)
#
# Step 12b. rpartの最終モデルをfit
rpart_fit <- fit(rpart_final_wf, data = iris_train)
#
# Step 12c. kknnの最終モデルをfit
kknn_fit <- fit(kknn_final_wf, data = iris_train)
#
# Step 13. テストデータで予測
# Step 13a. glmnetの予測
glmnet_pred <- predict(glmnet_fit, new_data = iris_test) |> 
  bind_cols(iris_test |> select(Sepal.Length))
#
# Step 13b. rpartの予測
rpart_pred <- predict(rpart_fit, new_data = iris_test) |> 
  bind_cols(iris_test |> select(Sepal.Length))
#
# Step 13c. kknnの予測
kknn_pred <- predict(kknn_fit, new_data = iris_test) |> 
  bind_cols(iris_test |> select(Sepal.Length))
#
# Step 14. 評価
# Step 14a. glmnetの評価
metrics(glmnet_pred, truth = Sepal.Length, estimate = .pred)
#
# Step 14b. rpartの評価
metrics(rpart_pred, truth = Sepal.Length, estimate = .pred)
#
# Step 14c. kknnの評価
metrics(kknn_pred, truth = Sepal.Length, estimate = .pred)
#
# Step 15. 予測値と実際の値の散布図
tibble(
  glmnet = glmnet_pred$.pred,
  rpart = rpart_pred$.pred,
  kknn = kknn_pred$.pred,
  Sepal.Length = iris_test$Sepal.Length
) |> 
  ggplot(aes(x = Sepal.Length)) +
  geom_point(aes(y = glmnet), color = "black") +
  geom_point(aes(y = rpart), color = "red") +
  geom_point(aes(y = kknn), color = "green") +
  geom_abline(intercept = 0, slope = 1)
#
# Step 16. glmnetモデルの係数
glmnet_fit |> extract_fit_parsnip() |> tidy()
#
# Step 17. rpartの決定木
rpart_tree <- rpart_fit |> 
  extract_fit_parsnip()
rpart_tree$fit |> rpart.plot(roundint = FALSE)
#
#################################################
#                                                                                                      #
#           第2部: 被独立変数がファクターの場合の分類問題           #
#                                                                                                      #
#################################################
#
# Step 1. 必要なパッケージの読み込み
library(tidyverse)
library(tidymodels)
library(glmnet)
library(rpart)
library(rpart.plot)
library(kknn)
library(ISLR)
tidymodels_prefer()
#
# Step 2. データの読み込み
data(Default)
glimpse(Default) # 10,000 x 4, defaultがターゲット
#
# Step 3. トレーニング用とテスト用に分ける
set.seed(225)
default_split <- initial_split(Default, prop = 0.8, strata = default)
default_train <- training(default_split)
default_test <- testing(default_split)
#
# Step 4. レシピ作成
default_rec <- recipe(default ~ ., data = default_train) |> 
  step_dummy(all_nominal_predictors()) |> 
  step_normalize(all_numeric_predictors())
#
# Step 5. モデル作成
# Step5a. glmnetのモデル
glmnet_mod <- logistic_reg(
  penalty = tune(),
  mixture = 1 # LASSO回帰にした
) |> 
  set_engine("glmnet") |> 
  set_mode("classification")
#  
# Step 5b. rpartのモデル
rpart_mod <- decision_tree(
  cost_complexity = tune(),
  tree_depth = tune(),
  min_n = tune()
) |> 
  set_engine("rpart") |> 
  set_mode("classification")
#

# Step 5c. kknnのモデル
kknn_mod <- nearest_neighbor(
  neighbors = tune()
) |> 
  set_engine("kknn") |> 
  set_mode("classification")
#
# Step 6. ワークフロー構築
# Step 6a. glmnetのワークフロー
glmnet_wf <- workflow() |> 
  add_recipe(default_rec) |> 
  add_model(glmnet_mod)
#
# Step 6b. rpartのワークフロー
rpart_wf <- workflow() |> 
  add_recipe(default_rec) |> 
  add_model(rpart_mod)
#
# Step 6c. kknnのワークフロー
kknn_wf <- workflow() |> 
  add_recipe(default_rec) |> 
  add_model(kknn_mod)
#
# Step 7. クロスバリデーションの構築
set.seed(268)
cv_folds <- vfold_cv(default_train, v = 10)
#
# Step 8. チューングリッドの作成
# Step 8a. glmnetのチューングリッド
glmnet_grid <- grid_regular(
  penalty(range = c(-4, 0)),
  levels = 20
)
#
# Step 8b. rpartのチューングリッド
rpart_grid <- grid_regular(
  cost_complexity(range = c(-4, 0)),
  tree_depth(range = c(2, 10)),
  min_n(range = c(5, 30)),
  levels = 3
)
#
# Step 8c. kknnのチューングリッド
kknn_grid <- grid_regular(
  neighbors(range = c(1, 20)),
  levels = 20
)
#
# Step 9. チューニングの実行
# Step 9a. glmnetのチューニング実行
glmnet_tuned <- tune_grid(
  glmnet_wf,
  resamples = cv_folds,
  grid = glmnet_grid,
  metrics = metric_set(roc_auc)
)
#
# Step 9b. rpartのチューニング実行
rpart_tuned <- tune_grid(
  rpart_wf,
  resamples = cv_folds,
  grid = rpart_grid,
  metrics = metric_set(roc_auc)
)
#
# Step 9c. kknnのチューニング実行
kknn_tuned <- tune_grid(
  kknn_wf,
  resamples = cv_folds,
  grid = kknn_grid,
  metrics = metric_set(roc_auc)
)
#
# Step 10. 最適なパラメータの抽出
# Step 10a. glmnetの最適なパラメータ
glmnet_params <- select_best(glmnet_tuned, metric = "roc_auc")
#
# Step 10b. rpartの最適なパラメータ
rpart_params <- select_best(rpart_tuned, metric = "roc_auc")
#
# Step 10c. kknnの最適なパラメータ
kknn_params <- select_best(kknn_tuned, metric = "roc_auc")
#
# Step 11. 最終ワークフロー構築
# Step 11a. glmnetの最終ワークフロー
glmnet_final_wf <- finalize_workflow(
  glmnet_wf,
  glmnet_params
)
#
# Step 11b. rpartの最終ワークフロー
rpart_final_wf <- finalize_workflow(
  rpart_wf,
  rpart_params
)
#
# Step 11c. kknnの最終ワークフロー
kknn_final_wf <- finalize_workflow(
  kknn_wf,
  kknn_params
)
#
# Step 12. 最終モデルをfit
# Step 12a. glmnetの最終モデルfit
glmnet_fit <- fit(glmnet_final_wf, data = default_train)
#
# Step 12b. rpartの最終モデルfit
rpart_fit <- fit(rpart_final_wf, data = default_train)
#
# Step 12c. kknnの最終モデルfit
kknn_fit <- fit(kknn_final_wf, data = default_train)
#
# Step 13. テストデータで予測
# Step 13a. glmnetで予測
glmnet_pred <- predict(glmnet_fit, new_data = default_test) |> 
  bind_cols(predict(glmnet_fit, new_data = default_test, type = "prob")) |> 
  bind_cols(default_test |> select(default))
#
# Step 13b. rpartで予測
rpart_pred <- predict(rpart_fit, new_data = default_test) |> 
  bind_cols(predict(rpart_fit, new_data = default_test, type = "prob")) |> 
  bind_cols(default_test |> select(default))
#
# Step 13c. kknnで予測
kknn_pred <- predict(kknn_fit, new_data = default_test) |> 
  bind_cols(predict(kknn_fit, new_data = default_test, type = "prob")) |> 
  bind_cols(default_test |> select(default))
#
# Step 14. 評価
# Step 14a. glmnetの評価
metrics(glmnet_pred, truth = default, estimate = .pred_class)
#
# Step 14b. rpartの評価
metrics(rpart_pred, truth = default, estimate = .pred_class)
#
# Step 14c. kknnの評価
metrics(kknn_pred, truth = default, estimate = .pred_class)
#
# Step 15. AUCスコア
# Step 15a. glmnetのAUCスコア
roc_auc(glmnet_pred, truth = default, .pred_No)
#
# Step 15b. rpartのAUCスコア
roc_auc(rpart_pred, truth = default, .pred_No)
#
# Step 15c. kknnのAUCスコア
roc_auc(kknn_pred, truth = default, .pred_No)
#
# Step 16. ROC曲線
glmnet_roc <- roc_curve(glmnet_pred, truth = default, .pred_No) |> 
  mutate(model = "glmnet")
rpart_roc <- roc_curve(rpart_pred, truth = default, .pred_No) |> 
  mutate(model = "rpart")
kknn_roc <- roc_curve(kknn_pred, truth = default, .pred_No) |> 
  mutate(model = "kknn")
#
bind_rows(glmnet_roc, rpart_roc, kknn_roc) |> 
  ggplot(aes(x = 1 - specificity, y = sensitivity, color = model)) +
  geom_path(linewidth = 1.2) +
  geom_abline(lty = 3) +
  theme_minimal()
#
# Step 17. Confusion Matrix
# Step 17a. glmnetのConfusion Matrix
conf_mat(glmnet_pred, truth = default, estimate = .pred_class)
#
# Step 17b. rpartのConfusion Matrix
conf_mat(rpart_pred, truth = default, estimate = .pred_class)
#
# Step 17c. kknnのConfusion Matrix
conf_mat(rpart_pred, truth = default, estimate = .pred_class)
#
# step 18. glmnetの係数を確認
glmnet_fit |> extract_fit_parsnip() |> tidy()
#
# Step19. rpartの決定木を描く
rpart_tree <- rpart_fit |> 
  extract_fit_parsnip()
rpart_tree$fit |> rpart.plot(roundint = FALSE)