
の続きです。前回までの分析で、株式公募や債券発行での資金調達には季節性があること、株式公募と債券発行には相関があることが確認できました。
今回は、趣向を変えて、機械学習で株式公募の件数を予測してみます。
採用するモデルは、線形モデル、Elastic-Netモデル、決定木モデル、ランダムフォレストモデルの4つです。
まず、tidymodelsパッケージの読み込みをします。

トレーニング用のデータとテスト用データを作成します。

レシピを作成します。

eqy_numをターゲット変数にして、eqY_val, bond_num, bond_val, monthを説明変数にします。step_dummy()関数でmonthをダミー変数にして、step_zv()関数で0分散の変数を削除し、step_normalize()関数で数値型変数を標準化しています。
各モデルを作成します。

線形モデルはlm, Elastic-Netモデルはglmnet, 決定木モデルはrpart, ランダムフォレストモデルはrangerをエンジンに採用しました。
ワークフローを作成します。

クロスバリデーションの設定をします。

チューニング・グリッドを作成します。grid_regula()関数を使いました。線形モデルはチューニングは不要です。

grid_tune()関数でチューニングを実行します。
決定木モデルとランダムフォレストモデルはチューニングに少し時間がかかりました。

select_best()関数で最適なパラメータを取り出します。

この最適なパラメータで最終ワークフローを作成します。finalize_workflow()関数を使います。

fit()関数でトレーニング用のデータを使って学習します。

predict()関数でテスト用のデータの予測をします。

metrics()関数でRMSEなどの評価指標を算出します。

それでは各モデルの評価指標を比較します。

ランダムフォレストモデルがRMSE、R2、MAEの3つの指標全てで一番良い結果でした。monthによってeqy_numの値がけっこう違うので、線形モデルは成績が悪かったですね。
最後にそれぞれの予測値と実際のeqy_numの散布図を描いてみます。


今回は以上です。
次回は、
です。
はじめから読むには、
です。
今回のコードは以下になります。
#
# tidymodelsの読み込み
library(tidymodels)
#
# eqy_numを被説明変数に、eqy_val, bond_num, bond_val, monthを説明変数
#
# 1. トレーニング用のデータ、テスト用のデータの作成(全モデル共通)
set.seed(9911)
split <- df |>
select(eqy_num:month) |>
initial_split(prop = 0.7)
train_data <- training(split)
test_data <- testing(split)
train_data |> summary()
test_data |> summary()
#
# 2. レシピ作成(全モデル共通)
rec <- recipe(eqy_num ~ ., data = train_data) |>
step_dummy(month) |>
step_zv(all_predictors()) |>
step_normalize(all_numeric_predictors())
#
# 3. モデル設定(各モデル)
# 3-1. 線形モデル(lm)
lm_mod <- linear_reg() |>
set_engine("lm")
#
# 3-2. Elastic-Netモデル(glmnet)
glmnet_mod <- linear_reg(
penalty = tune(),
mixture = tune()
) |>
set_engine("glmnet")
#
# 3-3. 決定木モデル(rpart)
rpart_mod <- decision_tree(
cost_complexity = tune(),
tree_depth = tune(),
min_n = tune()
) |>
set_engine("rpart") |>
set_mode("regression")
#
# 3-4. ランダムフォレストモデル(ranger)
ranger_mod <- rand_forest(
mtry = tune(),
min_n = tune(),
trees = 1000
) |>
set_engine("ranger") |>
set_mode("regression")
#
# 4. ワークフロー作成(各モデル)
# 4-1. 線形モデル(lm)
lm_wf <- workflow() |>
add_model(lm_mod) |>
add_recipe(rec)
#
# 4-2 Elastic-Netモデル(glmnet)
glmnet_wf <- workflow() |>
add_model(glmnet_mod) |>
add_recipe(rec)
#
# 4-3. 決定木モデル(rpart)
rpart_wf <- workflow() |>
add_model(rpart_mod) |>
add_recipe(rec)
#
# 4-4. ランダムフォレストモデル(ranger)
ranger_wf <- workflow() |>
add_model(ranger_mod) |>
add_recipe(rec)
#
# 5. クロスバリデーションの設定(全モデル共通)
set.seed(2929)
folds <- vfold_cv(train_data, v = 10)
#
# 6. チューングリッドの作成(各モデル)
# 6-1. 線形モデル(glm)
# 線形モデルはチューニングは不要
#
# 6-2. Elastic-Netモデル(glmnet)
glmnet_grid <- grid_regular(
penalty(range = c(-4, 0)),
mixture(range = c(0.2, 0.8)),
levels = c(penalty = 20, mixture = 7)
)
#
# 6-3. 決定木モデル(rpart)
rpart_grid <- grid_regular(
cost_complexity(range = c(-4, -1)),
tree_depth(range = c(2, 9)),
min_n(range = c(2, 20)),
levels = c(cost_complexity = 5, tree_depth = 4, min_n = 10)
)
#
# 6-4. ランダムフォレストモデル(ranger)
ranger_grid <- grid_regular(
mtry(range = c(1, 4)),
min_n(range = c(2, 30)),
levels = c(mtry = c(4, min_n = 29))
)
#
# 7. チューニング(各モデル)
# 7-1. 線形モデルは不要
#
# 7-2. Elastic-Netモデル(glmnet)
glmnet_tuned <- tune_grid(
glmnet_wf,
resamples = folds,
grid = glmnet_grid,
metrics = metric_set(rmse, rsq, mae),
control = control_grid(save_pred = TRUE)
)
#
# 7-3. 決定木モデル(rpart)
rpart_tuned <- tune_grid(
rpart_wf,
resamples = folds,
grid = rpart_grid,
metrics = metric_set(rmse, rsq, mae),
control = control_grid(save_pred = TRUE)
)
#
# 7-4. ランダムフォレストモデル(ranger)
ranger_tuned <- tune_grid(
ranger_wf,
resamples = folds,
grid = ranger_grid,
metrics = metric_set(rmse, rsq, mae),
control = control_grid(save_pred = TRUE)
)
#
# 8. 最適なパラメータ(各モデル)
# 8-1. 線形モデルは不要
# 8-2. Elastic-Netモデル(glmnet)
glmnet_params <- select_best(glmnet_tuned, metric = "rmse")
glmnet_params
#
# 8-3. 決定木モデル(rpart)
rpart_params <- select_best(rpart_tuned, metric = "rmse")
rpart_params
#
# 8-4. ランダムフォレストモデル(ranger)
ranger_params <- select_best(ranger_tuned, metric = "rmse")
ranger_params
#
# 9. 最終ワークフロー作成(各モデル)
# 9-1. 線形モデル(lm)
lm_wf_f <- lm_wf
#
# 9-2. Elastic-Netモデル(glmnet)
glmnet_wf_f <- finalize_workflow(glmnet_wf, glmnet_params)
#
# 9-3. 決定木モデル(rpart)
rpart_wf_f <- finalize_workflow(rpart_wf, rpart_params)
#
# 9-4. ランダムフォレストモデル(ranger)
ranger_wf_f <- finalize_workflow(ranger_wf, ranger_params)
#
# 10. train_dataで学習(各モデル)
# 10-1. 線形モデル(lm)
lm_fit <- fit(lm_wf_f, train_data)
#
# 10-2. Elastic-Netモデル(glmnet)
glmnet_fit <- fit(glmnet_wf_f, train_data)
#
# 10-3. 決定木モデル(rpart)
rpart_fit <- fit(rpart_wf_f, train_data)
#
# 10-4. ランダムフォレストモデル(ranger)
ranger_fit <- fit(ranger_wf_f, train_data)
#
# 11. test_dataで予測(各モデル)
# 11-1. 線形モデル(lm)
lm_pred <- test_data |>
select(eqy_num) |>
bind_cols(predict(lm_fit, test_data)) |>
mutate(model = "linear")
#
# 11-2. Elastic-Netモデル(glmet)
glmnet_pred <- test_data |>
select(eqy_num) |>
bind_cols(predict(glmnet_fit, test_data)) |>
mutate(model = "elastic_net")
#
# 11-3. 決定木モデル(rpart)
rpart_pred <- test_data |>
select(eqy_num) |>
bind_cols(predict(rpart_fit, test_data)) |>
mutate(model = "decision_tree")
#
# 11-4. ランダムフォレストモデル(ranger)
ranger_pred <- test_data |>
select(eqy_num) |>
bind_cols(predict(ranger_fit, test_data)) |>
mutate(model = "random_forest")
#
# 12. 評価(各モデル)
# 12-1. 線形モデル(lm)
lm_results <- lm_pred |>
metrics(truth = eqy_num, estimate = .pred) |>
mutate(model = "linear")
#
# 12-2. Elastic-Netモデル(glmnet)
glmnet_results <- glmnet_pred |>
metrics(truth = eqy_num, estimate = .pred) |>
mutate(model = "elastic_net")
#
# 12-3. 決定木モデル(rpart)
rpart_results <- rpart_pred |>
metrics(truth = eqy_num, estimate = .pred) |>
mutate(model = "decision_tree")
#
# 12-4. ランダムフォレストモデル(ranger)
ranger_results <- ranger_pred |>
metrics(truth = eqy_num, estimate = .pred) |>
mutate(model = "random_forest")
#
# 13. 評価の比較
# 13-1. 評価を合体
all_results <- lm_results |>
bind_rows(glmnet_results, rpart_results, ranger_results)
#
# 13-2. RMSEが一番小さいのは?
all_results |>
filter(.metric == "rmse") |>
arrange(.estimate)
# ランダムフォレストモデルが一番
#
# 13-3. R2が一番大きいのは?
all_results |>
filter(.metric == "rsq") |>
arrange(desc(.estimate))
# ランダムフォレストモデルが一番
#
# 13-4. MAEが一番小さいのは
all_results |>
filter(.metric == "mae") |>
arrange(.estimate)
# ランダムフォレストモデルが一番
#
# 14. 実際の値と予測値のグラフ
# 14-1. 予測値を統合
all_pred <- lm_pred |>
bind_rows(glmnet_pred, rpart_pred, ranger_pred)
#
# 14-2. グラフ
all_pred |>
ggplot(aes(x = .pred, y = eqy_num)) +
geom_point(aes(color = model), alpha = 0.5, size = 3) +
geom_abline(linewidth = 1) +
theme_minimal()
#
(冒頭の画像は、Bing Image Creator で生成しました。プロンプトは、Landscape, beautiful long wide view of natural green fields, running a small creek, close up of blue Amaryllis flower, photo です。)