ここでは、内側で選ばれた正則化係数、外側予測と見かけの誤差の差、五つの分割間のばらつきを確認し、生成モデルから計算できる限界の誤差とも比較し、そのうえで、5分割と10分割のどちらを選ぶか、一人ずつ外すLOOCVで何が変わるか、分割をやり直す反復CVで減る変動と残る変動を扱います。実行環境と生成モデルは、見かけの成績と学習外の予測と共通です。
内側の誤差曲線と正則化の選択
外側の第1評価集合を除いた240人で、内側CVの誤差曲線を確認します。この曲線で選んだ値だけが、第1評価集合の60人を予測するモデルへ渡されます。
first_cv <- nested$outer_result[[1]]$cvafit$fits[[1]]
print(round(c(First_min = first_cv$lambda.min, First_1se = first_cv$lambda.1se, Final = nested$final_param["lambda"]), digits = 3))
#> First_min First_1se Final.lambda
#> 0.335 0.677 0.265
ここで、First_minは外側第1分割の内部で選ばれた$\lambda$で、First_1seは同じ内部CVに1-SEルールを使った場合の値です。一方、Final.lambdaは全300人で最終モデルを作るために改めて選ばれた値で、外側第1分割の設定とは異なります。
そのため、Final.lambdaを外側の全分割へ戻して予測を作り直すと、評価対象者も使って選んだ設定を評価に使うことになり、前の記事で定義した式(7)の手順から外れます。
png("cv-inner-tuning.png", width = 1100, height = 800, res = 200, type = "cairo")
par(cex.axis = 0.75)
plot(first_cv, main = "")
dev.off()

1-SEルールの意味
誤差曲線の最小点の近くが平らな場合には、最小点を厳密に追いかけるより、強く正則化した候補を選ぶ方針もあり、glmnetの1-SEルールはその一つです。最小誤差の$\lambda$を$\lambda_{\min}$、その点で計算された標準誤差を$\widehat{\mathrm{SE}}_{\min}$とすると、次の基準になります。
$$\lambda_{\mathrm{1SE}} = \max\left\{\lambda\in\Lambda: \widehat R_{\mathrm{inner}}(\lambda) \leq \widehat R_{\mathrm{inner}}(\lambda_{\min}) + \widehat{\mathrm{SE}}_{\min} \right\} \tag{1}$$
式(1)では、最小誤差に標準誤差を一つ加えた範囲の候補から、最も強い正則化を選んでいます。LASSOでは、誤差が近い候補の中から変数を少なくする方向の選択になりやすい基準です。
ただし、これは最小点との差を検定した結果ではなく、予測性能とモデルの複雑さを折り合わせる選択規則です。一方、Ridgeでは係数が通常0にならないため、1-SEルールと変数数の減少は分けて扱います。
なお、今回の主たる手順では最小誤差の規則を事前に採用しており、1-SEルールでの外側評価との比較は行っていません。両方を比べて良かった方だけを報告するなら、その選択も評価の設計へ含める必要があります。
外側の予測値で計算した誤差
各外側評価集合の予測を集めると、300人全員について、自分を学習に使っていない予測値が得られ、このような予測はout-of-fold予測、OOF予測と呼ばれます。ただし、今回の出力はfoldごとに連結されているため、元の対象者順へ戻してから観測値と対応させます。
この行順を取り違えても計算上のエラーが出ない場合があり、評価指標だけを見て気付くことが難しい誤りです。
outer_prediction <- nested$output$predy[order(unlist(outer_folds))]
apparent_prediction <- as.numeric(predict(nested, newdata = predictors))
print(round(c(Apparent = sqrt(mean((outcome - apparent_prediction)^2)),
Outer = sqrt(mean((outcome - outer_prediction)^2)), Inner = innercv_summary(nested)["RMSE"]), digits = 3))
#> Apparent Outer Inner.RMSE
#> 2.998 3.115 3.131
ここで、Apparentは全300人で学習した最終モデルを同じ300人へ戻したRMSEで、Outerは外側の評価集合だけから得たRMSEです。また、Inner.RMSEは各外側学習集合の内部で、選択された設定の内側予測をまとめたRMSEです。
今回のデータでは、学習内のRMSEが2.998、外側CVが3.115となりましたが、この差の全体をチューニングの楽観性と呼ぶことはできません。学習人数が300人と240人で異なることに加え、学習標本の変動も関わっているためです。
一方、内側のRMSEは3.131で、外側の3.115より僅かに大きくなりましたが、内側では学習人数が192人と少なく、設定選択と偶然の変動も関わります。そのため、この一例から楽観性がない、あるいは内側の誤差は必ず小さいとは判断できません。
png("cv-apparent-outer.png", width = 1100, height = 800, res = 200, type = "cairo")
par(mfrow = c(1, 2), mar = c(4, 4, 3, 1), mgp = c(2.3, 0.7, 0), cex = 0.8)
plot(apparent_prediction, y = outcome, xlim = range(outcome), ylim = range(outcome), pch = 16, col = "#7A7A7A80", xlab = "Predicted outcome", ylab = "Observed outcome", main = "Apparent")
abline(a = 0, b = 1, lty = 2)
plot(outer_prediction, y = outcome, xlim = range(outcome), ylim = range(outcome), pch = 16, col = "#0072B280", xlab = "Predicted outcome", ylab = "Observed outcome", main = "Outer CV")
abline(a = 0, b = 1, lty = 2)
dev.off()

なお、この例のアウトカムには標準偏差3の誤差が加わっているため、条件付き平均を良く予測できても、個々の点が線の上へ完全に並ぶわけではありません。また、予測が良いことと、個別の対象者について必要な精度を満たすことも別の判断です。
foldごとの成績のばらつき
外側の平均だけでは、どの評価集合で誤差が大きかったかは分からないため、各foldのRMSEと、外側学習集合の内部で選ばれた$\lambda$を確認します。
print(round(sqrt(tapply((outcome - outer_prediction)^2, INDEX = fold_id, FUN = mean)), digits = 3))
print(round(vapply(nested$outer_result, FUN = function(result) result$lambda, FUN.VALUE = numeric(1)), digits = 3))
#> 1 2 3 4 5
#> 3.009 3.169 3.314 2.926 3.141
#> [1] 0.335 0.265 0.335 0.298 0.424
実際、第3評価集合のRMSEは3.314、第4評価集合は2.926となり、採用された正則化係数も分割ごとに異なりました。この変動には、学習に使う人の違いと評価に使う人の違いの両方が含まれています。
そこで、RMSEが最小だった第4分割のモデルだけを最終モデルにすると、その評価集合に偶然よく合った結果を選ぶことに加え、残りの対象者を最終学習に使わないことになるため、この選び方は勧めません。
RMSEを平均する際の順序
平方根は線形変換ではないため、foldごとのRMSEの平均と、全OOF予測のMSEを平均してから平方根を取る値は通常一致しません。各foldのMSEを$\widehat M_k$とすると、人数が等しい場合でも次の違いが残ります。
$$\frac{1}{K}\sum_{k=1}^{K}\sqrt{\widehat M_k} \leq \sqrt{\frac{1}{K}\sum_{k=1}^{K}\widehat M_k} \tag{2}$$
式(2)では、foldごとに平方根を取ってから平均した値が、MSEを平均してから平方根を取った値以下になることを表しています。後者が、人数を揃えた場合の全OOF予測に基づくRMSEです。
そのため、この違いは計算ミスではなく、集約する量の違いによって生じます。ただし、研究間で数値を比較する際には、どちらを使ったかを記録しなければ、同じRMSEという名称でも計算の定義が揃いません。
真の生成モデルとの比較
ランダムに生成したデータセットでは、アウトカムの生成過程をこちらで定めているため、実データでは通常分からない母集団の予測リスクも計算できます。今回の母集団では、予測因子の平均は0、分散は1で、予測因子同士は独立です。
そこで、最終モデルの切片を$\widehat\beta_0$、係数を$\widehat{\boldsymbol\beta}$、真の係数を$\boldsymbol\beta_\star=(2,-1.5,1,0,\ldots,0)^\top$とすると、最終モデルを固定した母集団MSEは次の式です。
$$R_{\mathrm{final}} = 9 + (\widehat\beta_0-10)^2 + \sum_{j=1}^{60}(\widehat\beta_j-\beta_{\star j})^2 \tag{3}$$
式(3)では、予測で除けない誤差の分散9に、切片と係数の推定のずれによる誤差を加えています。ここでは予測因子の独立性と平均0を使うことで、交差項の期待値が0になります。
もっとも、この式は、予測因子に相関がある場合や母集団が異なる場合へ、そのまま移せる計算ではありません。また、ここで固定しているのは300人で学習した最終モデルであり、外側の各モデルとは区別して読みます。
final_coef <- as.numeric(coef(nested$final_fit, s = nested$final_param["lambda"]))
population_rmse <- sqrt(9 + (final_coef[1] - 10)^2 + sum((final_coef[-1] - c(2, -1.5, 1, rep(0, times = 57)))^2))
print(round(c(Oracle = 3, Final_population = population_rmse), digits = 3))
#> Oracle Final_population
#> 3.000 3.021
ここで、Oracleは真の条件付き平均が分かっている予測関数の母集団RMSEで、Final_populationは学習した最終モデルを固定した母集団RMSEです。後者は3.021となり、今回の外側CVの3.115とは一致しませんでした。
ただし、CVは有限標本から推定されるうえ、外側CVと最終モデルでは学習人数も異なるため、誤差が真の値と一致しないだけで失敗とは判断できません。反対に、今回近い値だったことを別のデータへ一般化することもできません。
平均誤差の背後に残るずれ
同じRMSEでも、全域で同程度にばらつく予測と、特定の予測値の範囲で偏っている予測では、同じ使い方にはなりません。そこで、外側の予測値に対して、観測値から予測値を引いた残差を描きます。
png("cv-outer-residuals.png", width = 1100, height = 800, res = 200, type = "cairo")
plot(outer_prediction, y = outcome - outer_prediction, pch = 16, col = "#0072B280", xlab = "Outer-fold prediction", ylab = "Observed minus predicted", main = "Residuals from held-out participants")
abline(h = 0, lty = 2)
lines(lowess(outer_prediction, y = outcome - outer_prediction), col = "#D55E00", lwd = 2)
dev.off()

実際、今回の図では、予測値が低い範囲で平滑線が0より下へ寄る部分があり、予測値が中間の範囲では0付近から上側へ動いています。ただし、両端は対象者が少ないため、線の曲がり方を細かく説明しすぎない方がよいでしょう。
ここで、この図を読んで予測式を変更するなら、変更後の手順を同じ外側の成績だけで最終評価したことにはできません。図3では誤差の構造を確認できますが、この診断から生まれた新しいモデルを評価するデータまで自動的に用意されるわけではないためです。
5分割と10分割の選び方
5分割と10分割のどちらを使うかは、CVの相談で迷いやすい点であり、分割数を増やすと各回の学習人数は全体に近付きますが、その分だけ各評価集合は小さくなります。その一例として、独立した300人では、5分割なら240人で学習して60人で評価し、10分割なら270人で学習して30人で評価するため、この人数差が学習と指標計算へ別々に影響します。
学習人数と指標の安定性
学習データが少ないことで性能が大きく変わる手順なら、学習人数の多い分割を選ぶ意味があります。一方、二値アウトカムでイベントが少ない場合には、評価集合が小さくなることでAUCや感度などを計算しにくくなります。
そのため、独立した対象者の予測では5分割または10分割を候補とし、各学習集合と評価集合に残る人数やイベント数から、指標を計算できる構成かを判断します。ただし、5や10が普遍的な最適値という意味ではなく、ArlotとCelisseはCVの選択を、損失、学習手順、バイアスや分散の性質と結び付けて論じています。
分割数を結果から選ばない方針
5分割より成績が良かったという理由だけで10分割を採用すると、結果が良くなるように評価手順を選ぶことになるため、この決め方は勧めません。
もっとも、比較を目的として両方を確認することはありますが、その場合は変更した理由と両方の結果を報告します。また、性能の差が学習人数によるものか、分割の偶然によるものかを、一度の比較だけで分離できるとは限りません。
一人ずつ外すLOOCVの特徴
leave-one-out CV、LOOCVでは、対象者を一人ずつ外して予測し、対象者数が300人なら299人で学習する操作を300回行って、全対象者の学習外誤差を集めます。また、学習人数が最終モデルに近く、独立した行を一人ずつ外す通常のLOOCVには、K-foldのようなランダムな分割の選び方がありません。
ただし、学習アルゴリズム自体に乱数がある場合にはその変動が残り、学習集合も大部分が重なります。そのため、不安定な手順では特定の対象者を外した影響が大きくなるうえ、計算量も増えるため、LOOCVが常に最も安定するとは判断できません。
一人の評価集合とAUC
AUCにはイベント例と非イベント例の比較が必要なため、各評価集合に一人しかいないLOOCVでは、集合ごとのAUCを計算できません。そこで全員のOOF予測を集めれば数値としてAUCを計算できる場合がありますが、その比較には異なる学習モデルから得たスコア同士が含まれます。
したがって、全OOF予測から計算したAUCをfoldごとのAUCの平均と同じ量として説明することはできず、モデル間でスコアの尺度が揃っているかも確認が必要です。また、患者が複数の記録を持つデータで行を一つずつ外すことは患者を一人ずつ外すこととは異なるため、LOOCVという名称だけでは学習から何を外したかは分かりません。
反復CVで減る変動と残る変動
一度の5分割CVの結果が分割の偶然に左右されているかを調べるには、分割を変えてCVを繰り返す方法があり、これは反復CV、repeated CVと呼ばれます。反復番号を$r$、反復数を$B$、各反復の平均損失を$\widehat R_{\mathrm{CV},r}$とすると、その平均は次の量です。
$$\widehat R_{\mathrm{repeated}} = \frac{1}{B}\sum_{r=1}^{B}\widehat R_{\mathrm{CV},r} \tag{4}$$
式(4)では、同じデータの分け方を変えて得た成績を平均しており、新しい患者を$B$倍集めた場合の評価ではありません。つまり、手元の標本を固定したまま、分割に伴う変動をならす操作です。
このため、反復数を増やすと分割の偶然による変動を小さくできる場合がありますが、元の患者数が少ないことで生じる母集団への不確実性は、分割を繰り返すだけでは消えません。
この点について、Varoquauxは、小標本の予測研究ではCVの成績に大きな不確実性が残り、fold間の単純な標準誤差ではそれを小さく見積もり得ることを報告しています。そのため、特定の論文の誤差幅を、あらゆる医療データへ共通する数値基準として使うことは避けます。
反復とネストの違い
通常のCVを何度繰り返しても、各反復で最良の設定を選び、その最小誤差を最終性能として報告しているなら、選択と評価を分けたことにはなりません。一方、ネストしたCVは内側と外側の役割を分け、反復CVは分割の割り当てを変える操作であり、両方を組み合わせることはできますが同じ意味ではありません。
なお、今回の掲載例は、外側5分割、内側5分割を一組として行っており、分割全体を変える反復は行っていません。したがって、今回の5個のRMSEから、反復CVによってどの程度安定するかまで確認したとは記述できません。
誤差の数字と一緒に読むもの
外側の予測から得たRMSE3.115は、見かけの2.998より大きく、真の生成モデルで到達できる3.000よりも大きい値でした。この三つを並べることで、見かけと外側CVとの差と、生成モデル上の下限からどれだけ離れているかを分けて読めます。
ここで、反復回数を増やして小さくできるのは、主として分割の偶然に由来する変動です。一方、分割数を変えると各回の学習人数も変わるため、単なる分割変動の調整ではなく、評価している学習条件そのものも変わります。
また、学習手順そのものの弱さや、評価対象者へ情報が漏れている構造は、反復回数を増やしても解消しません。次の記事では、その漏れが起きやすい場所を順に見ます。
標準化、変数選択、欠測値の補完のいずれも、分割の前に済ませてしまうと、外側の成績が楽観的になります。
参考文献
Bates S, Hastie T, Tibshirani R. Cross-validation: what does it estimate and how well does it do it? Journal of the American Statistical Association. 2024;119(546):1434-1445.
Arlot S, Celisse A. A survey of cross-validation procedures for model selection. Statistics Surveys. 2010;4:40-79.
Varoquaux G. Cross-validation failure: small sample sizes lead to large error bars. NeuroImage. 2018;180(Pt A):68-77.
Varma S, Simon R. Bias in error estimation when using cross-validation for model selection. BMC Bioinformatics. 2006;7(1):91.
Bengio Y, Grandvalet Y. No unbiased estimator of the variance of K-fold cross-validation. Journal of Machine Learning Research. 2004;5:1089-1105.


