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

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

都道府県別の商業動態統計調査のデータの分析7 - tidymodelによるチューニング - 勾配ブースティング回帰モデルは向いてなかった

www.crosshyou.info

の続きです。前回はチューニング・グリッドを作成しましたから、今回は tune_grid()関数で実際にチューニングをしていきます。

線形モデルは、fit_resample()関数を使います。

futureパッケージとtuneパッケージを読み込み、plan()関数で並列処理をしています。チューニングの計算時間を少しでも短くするためです。

ペナルティ付き線形モデル(glmnet)以降は、tune_grid()関数を使います。

警告メッセージが表示されていますが、気にしなくていいです。Fold06のデータで、推定値が定数になってしまった、という意味ですが、他のFoldでは推定できているので大丈夫です。

勾配ブースティング回帰モデル(xgboost)でたくさん警告メッセージが出てしまいました。Copilotに相談したら、レシピとチューニング・グリッドがダメだったようです。

レシピは

xgboost_rec <- recipe(target ~ ., data = train_data) |>
  step_zv(all_predictors()) |>        # ゼロ分散の列を削除
  step_dummy(all_nominal_predictors()) |>  # カテゴリ変数をダミー化
  step_normalize(all_numeric_predictors())  # 数値を標準化

チューニンググリッドは、

xgboost_grid <- grid_space_filling(
  mtry(range = c(1L, 8L)),
  min_n(range = c(2L, 20L)),
  tree_depth(range = c(3L, 8L)),
  learn_rate(range = c(-1.5, -0.5)),   # 0.03〜0.3
  loss_reduction(range = c(0, 5)),     # gamma >= 0 が安定
  sample_size(range = c(0, 1)),        # 0〜1 の実数を自動生成
  size = 20
)

このように変えたらいいらしいです。

変えてやってみます。

変えてもだめでした。。。

さらにCopilotに相談したら、train_dataのglimpse()を見せて、ということだったので、見せたら、

ということでした。

そして、ここでは割愛しますが、さらに調整したコードを走らせたのですが、結果は改善しませんでした。

そして、最終的なCopilotの結論は、

でした。

ということなので、勾配ブースティング回帰モデルはあきらめます。

Copilotによる詳しい説明は、以下のようでした。

🔍 なぜこのデータで xgboost が木を作れないのか
① 特徴量が 8 列しかない(低次元)
xgboost は本来:
- 数百〜数千の特徴量
- 非線形な関係
- カテゴリ変数の大量の dummy
- ノイズの多いデータ
で威力を発揮します。
しかし今回のデータは:
- 数値 8 列
- 112 行
- 分布も比較的素直
→ 木が分割する余地がほとんどない

② v3, v4, v7, v8 に “0 が大量に含まれる”
例:
- v4: 0 が多い
- v8: 0 が多い
- v3, v7: 負の値が多く偏りが強い
fold によっては:
- ほぼ 0 しかない
- ほぼ負の値しかない
- 分散が極端に小さい
→ xgboost は「分割しても意味がない」と判断
→ 定数予測

③ 112 行 × 5-fold CV → fold が小さすぎる
1 fold あたり 22 行。
この規模だと:
- 目的変数の分布が fold ごとに大きく変わる
- 特徴量の分散も fold ごとに変わる
- → 分割が成立しない fold が大量に発生
- → 全部同じ値を返す

④ このデータは “ほぼ線形” の可能性が高い
あなたのデータを見る限り:
- v1〜v8 が target と線形関係に見える
- 変数間の相関も高そう
- 非線形性が弱い
xgboost は非線形を掘りに行くモデルなので、
線形に近いデータでは 木が成長しない → 定数予測 が起きます。

🔥 つまり、xgboost が悪いのではなく、
このデータが xgboost に向いていない

今回のデータは、勾配ブースティング回帰モデルのような高性能モデルは必要ない、ということですね。

今回は以上です。

次回は、

www.crosshyou.info

です。

 

はじめから読むには、

www.crosshyou.info

です。

今回のコードは以下になります。

#
# 6. 各モデルのチューニング
# 6-1. 線形モデル(lm)
library(future)
library(tune)
plan(multisession, workers = parallel::detectCores() - 1) # 並列処理スタート

set.seed(123)
lm_tuned <- fit_resamples(
  lm_wf,
  resamples = folds,
  control = control_resamples(save_pred = TRUE)
)
#
# 6-2. ペナルティ付き線形モデル(glmnet)
set.seed(123)
glmnet_tuned <- tune_grid(
  glmnet_wf,
  grid = glmnet_grid,
  resamples = folds,
  control = control_grid(save_pred = TRUE)
)
# 6-3. 決定木モデル(rpart)
set.seed(123)
rpart_tuned <- tune_grid(
  rpart_wf,
  grid = rpart_grid,
  resamples = folds,
  control = control_grid(save_pred = TRUE)
)
#
# 6-4. ランダムフォレストモデル(ranger)
set.seed(123)
ranger_tuned <- tune_grid(
  ranger_wf,
  grid = ranger_grid,
  resamples = folds,
  control = control_grid(save_pred = TRUE)
)
# 6-5. サポートベクター回帰(SVR)モデル(kernlab)
library(kernlab)
set.seed(123)
kernlab_tuned <- tune_grid(
  kernlab_wf,
  grid = kernlab_grid,
  resamples = folds,
  control = control_grid(save_pred = TRUE)
)
#
# 6-6. k-NN回帰モデル(kknn)
set.seed(123)
kknn_tuned <- tune_grid(
  kknn_wf,
  grid = kknn_grid,
  resamples = folds,
  control = control_grid(save_pred = TRUE)
)
#
# 6-7. ニューラルネットワークモデル(nnet)
set.seed(123)
nnet_tuned <- tune_grid(
  nnet_wf,
  grid = nnet_grid,
  resamples = folds,
  control = control_grid(save_pred = TRUE)
)
#
# 6-8. 勾配ブースティング回帰モデル(xgboost)
set.seed(123)
xgboost_tuned <- tune_grid(
  xgboost_wf,
  grid = xgboost_grid,
  resamples = folds,
  control = control_grid(save_pred = TRUE)
)

plan(sequential) # 並列処理エンド
#
# 勾配ブースティング回帰モデルのレシピを再定義
xgboost_rec <- recipe(target ~ ., data = train_data) |>
  step_zv(all_predictors()) |>        # ゼロ分散の列を削除
  step_dummy(all_nominal_predictors()) |>  # カテゴリ変数をダミー化
  step_normalize(all_numeric_predictors())  # 数値を標準化
#
# 勾配ブースティング回帰モデルのワークフローを再定義
xgboost_wf <- workflow() |> 
  add_model(xgboost_mod) |> 
  add_recipe(xgboost_rec)
#
# 勾配ブースティング回帰モデルのチューニンググリッドを再定義
xgboost_grid <- grid_space_filling(
  mtry(range = c(1L, 8L)),
  min_n(range = c(2L, 20L)),
  tree_depth(range = c(3L, 8L)),
  learn_rate(range = c(-1.5, -0.5)),   # 0.03〜0.3
  loss_reduction(range = c(0, 5)),     # gamma >= 0 が安定
  sample_size(range = c(0, 1)),        # 0〜1 の実数を自動生成
  size = 20
)
#
# 勾配ブースティング回帰モデルの再チューニング
plan(multisession, workers = parallel::detectCores() - 1) # 並列処理スタート

set.seed(123)
xgboost_tuned <- tune_grid(
  xgboost_wf,
  grid = xgboost_grid,
  resamples = folds,
  control = control_grid(save_pred = TRUE)
)

plan(sequential) # 並列処理エンド
#
# さらに再定義
xgboost_rec <- recipe(target ~ ., data = train_data) %>%
  step_normalize(all_numeric_predictors())

xgboost_wf <- workflow() |> 
  add_model(xgboost_mod) |> 
  add_recipe(xgboost_rec)

folds <- vfold_cv(train_data, v = 5, repeats = 3)

xgboost_grid <- grid_space_filling(
  tree_depth(range = c(3L, 6L)),
  learn_rate(range = c(-1.3, -0.7)),  # 0.05〜0.2
  min_n(range = c(2L, 10L)),
  loss_reduction(range = c(0, 2)),
  sample_size(range = c(0, 1)),
  mtry(range = c(1L, 8L)),
  size = 20
)

plan(multisession, workers = parallel::detectCores() - 1) # 並列処理スタート

set.seed(123)
xgboost_tuned <- tune_grid(
  xgboost_wf,
  grid = xgboost_grid,
  resamples = folds,
  control = control_grid(save_pred = TRUE)
)

plan(sequential) # 並列処理エンド
#

 

 

(冒頭の画像は、Bing Image Creator で生成しました。プロンプトは、Natural scene landscape, close up rainbow color flowers, green grass fields, one tall tree, blue sky, photo です。)