井出草平の研究ノート

反復交差検証 Repeated Cross-Validationを用いたLassoの安定性のシミュレーション[R]

反復交差検証 Repeated Cross-Validationの安定性のシミュレーションを行った。 反復交差検証については以下のエントリを参照。

ides.hatenablog.com

ides.hatenablog.com

安定性のシミュレーションはLOOCVやnーfolds CVの場合と同様に異なった乱数シードを使い、50回推定して、各変数が選ばれた回数と推定値の平均・標準偏差を計算した

ides.hatenablog.com

データの読み込みと前処理

library(haven)
library(tidyr)
auto <- haven::read_dta("http://www.stata-press.com/data/r9/auto.dta")
auto <- auto %>% drop_na()  # 全カラムに対してNAがない行を抽出
auto$foreign <- as.integer(auto$foreign)

並列計算の準備

doParallelパッケージを用いて1コアではなく複数コアで計算するようにして、計算時間を短縮させるようにした。

library(doParallel)
# 並列処理の設定
num_cores <- detectCores() - 2  # システム全体のコア数から2つを引いた数を使用
cl <- makeCluster(num_cores)
registerDoParallel(cl)

Lasso回帰の安定性を調べる

反復交差検証の反復回数はこちらで調べたように14回に設定した。

ides.hatenablog.com

library(caret)
library(glmnet)
library(dplyr)

# 結果を格納するリスト
selected_variables <- list()
coefficients <- list()

# 50回のシミュレーション
for (i in 1:50) {
  set.seed(i)
  train_control <- trainControl(method = "repeatedcv", 
                                number = 10,  # 10-fold CV
                                repeats = 14,  # 14回繰り返す
                                savePredictions = "final")
  
  model <- train(price ~ mpg + rep78 + headroom + trunk + weight + length + turn + displacement + gear_ratio + foreign, 
                 data = auto, 
                 method = "glmnet",  # Lasso回帰
                 trControl = train_control,
                 tuneLength = 10)  # チューニングするλの数
  
  # 最適なモデルの係数を取得
  best_lambda <- model$bestTune$lambda
  coef_best <- coef(model$finalModel, s = best_lambda)
  
  # 選ばれた変数とその係数を保存
  non_zero_coefs <- as.matrix(coef_best)
  non_zero_coefs <- non_zero_coefs[non_zero_coefs[, 1] != 0, , drop = FALSE]
  
  selected_variables[[i]] <- rownames(non_zero_coefs)
  coefficients[[i]] <- non_zero_coefs
}

# 並行処理の停止
stopCluster(cl)

# 選ばれた変数の回数をカウント
variable_counts <- table(unlist(selected_variables))

# 選ばれた変数の推定値の平均と標準偏差を計算
variable_stats <- lapply(names(variable_counts), function(var) {
  coefs <- unlist(lapply(coefficients, function(coef) if (var %in% rownames(coef)) coef[var, 1] else NA))
  coefs <- coefs[!is.na(coefs)]  # NAを除外
  mean_coef <- mean(coefs)
  sd_coef <- sd(coefs)
  data.frame(variable = var, mean = mean_coef, sd = sd_coef)
})

variable_stats <- do.call(rbind, variable_stats)

変数が選ばれた回数

variable_counts_df <- as.data.frame(variable_counts)
colnames(variable_counts_df) <- c("Variable", "Count")
print(variable_counts_df)
       Variable Count
1   (Intercept)    50
2  displacement    50
3       foreign    50
4    gear_ratio    32
5      headroom    50
6        length    12
7           mpg    16
8         rep78    50
9         trunk    12
10         turn    49
11       weight    50

推定値の平均と標準偏差

print(variable_stats)
       variable       mean           sd
1   (Intercept)  349.73377 2330.9384052
2  displacement   13.57817    0.3616850
3       foreign 2839.84030  124.6804858
4    gear_ratio -203.81945  189.8846262
5      headroom -464.11233   54.2174071
6        length  -12.02154   10.8404136
7           mpg  -29.14755    8.0687846
8         rep78  159.76717   47.6848193
9         trunk   19.99706   10.3307869
10         turn  -42.77568   22.0358426
11       weight    1.92157    0.2248898