randomForest
モデルを実行すると、モデルに基づいて予測を行うことができます。各予測の予測間隔を取得する方法はありますか。その結果、モデルがその答えをどの程度「保証」しているのかがわかります。これが可能である場合、単にモデル全体の従属変数の変動性に基づいているのでしょうか、それとも特定の予測に従ってた特定の決定木に応じて、より広い間隔とより狭い間隔を持っていますか?
randomForest
モデルを実行すると、モデルに基づいて予測を行うことができます。各予測の予測間隔を取得する方法はありますか。その結果、モデルがその答えをどの程度「保証」しているのかがわかります。これが可能である場合、単にモデル全体の従属変数の変動性に基づいているのでしょうか、それとも特定の予測に従ってた特定の決定木に応じて、より広い間隔とより狭い間隔を持っていますか?
回答:
これは、@ Sashikanth Dareddyへの応答(コメントに収まらないため)と、元の投稿への応答です。
予測間隔とは何かを思い出してください。これは、将来の観測が存在すると予測する間隔または値のセットです。一般に、予測区間には、その幅を決定する2つの主要な部分があります。これは、信頼区間部分である予測平均(または他のパラメーター)についての不確実性を表す部分と、その平均周辺の個々の観測値の変動性を表す部分です。信頼区間は、中央極限定理により非常に堅牢であり、ランダムフォレストの場合、ブートストラップも役立ちます。ただし、予測変数は、予測変数が与えられた場合のデータの分布方法に関する仮定に完全に依存します。CLTとブートストラップはその部分に影響を与えません。
対応する信頼区間も広くなる場合、予測区間は広くする必要があります。予測間隔の幅に影響を与える他の事柄は、等分散に関する仮定です。これは、ランダムフォレストモデルではなく、研究者の知識に基づいている必要があります。
予測間隔は、カテゴリの結果には意味がありません(間隔ではなく予測セットを実行できますが、ほとんどの場合、おそらくあまり有益ではありません)。
正確な真実がわかっているデータをシミュレートすることで、予測間隔に関する問題のいくつかを確認できます。次のデータを考慮してください。
set.seed(1)
x1 <- rep(0:1, each=500)
x2 <- rep(0:1, each=250, length=1000)
y <- 10 + 5*x1 + 10*x2 - 3*x1*x2 + rnorm(1000)
この特定のデータは線形回帰の仮定に従っており、ランダムフォレストフィットではかなり単純です。「真の」モデルから、両方の予測子が0の場合、平均が10であることがわかります。また、個々のポイントは標準偏差1の正規分布に従うことがわかります。これらのポイントは8から12です(実際には8.04から11.96ですが、丸めにより簡単になります)。推定される予測間隔は、これよりも広く(完全な情報がない場合は幅を追加して補正する)、この範囲を含める必要があります。
回帰の間隔を見てみましょう。
fit1 <- lm(y ~ x1 * x2)
newdat <- expand.grid(x1=0:1, x2=0:1)
(pred.lm.ci <- predict(fit1, newdat, interval='confidence'))
# fit lwr upr
# 1 10.02217 9.893664 10.15067
# 2 14.90927 14.780765 15.03778
# 3 20.02312 19.894613 20.15162
# 4 21.99885 21.870343 22.12735
(pred.lm.pi <- predict(fit1, newdat, interval='prediction'))
# fit lwr upr
# 1 10.02217 7.98626 12.05808
# 2 14.90927 12.87336 16.94518
# 3 20.02312 17.98721 22.05903
# 4 21.99885 19.96294 24.03476
推定平均(信頼区間)には不確実性があり、8から12の範囲よりも広い(ただし含む)予測区間が得られることがわかります。
ここで、個々のツリーの個々の予測に基づいて間隔を見てみましょう(ランダムフォレストは線形回帰の仮定(このデータに当てはまることがわかっている)の恩恵を受けないため、これらの予測はより広くなるはずです):
library(randomForest)
fit2 <- randomForest(y ~ x1 + x2, ntree=1001)
pred.rf <- predict(fit2, newdat, predict.all=TRUE)
pred.rf.int <- apply(pred.rf$individual, 1, function(x) {
c(mean(x) + c(-1, 1) * sd(x),
quantile(x, c(0.025, 0.975)))
})
t(pred.rf.int)
# 2.5% 97.5%
# 1 9.785533 13.88629 9.920507 15.28662
# 2 13.017484 17.22297 12.330821 18.65796
# 3 16.764298 21.40525 14.749296 21.09071
# 4 19.494116 22.33632 18.245580 22.09904
間隔は回帰予測間隔よりも広いですが、範囲全体をカバーしていません。これらには真の値が含まれているため、信頼区間として正当である可能性がありますが、平均(予測値)がどこにあるかを予測するだけで、その平均周辺の分布に追加される部分はありません。x1とx2が両方とも0である最初のケースでは、間隔は9.7未満になりません。これは、8まで下がる真の予測間隔とは大きく異なります。新しいデータポイントを生成する場合、いくつかのポイントがあります5%未満)は、真の間隔と回帰間隔にありますが、ランダムフォレスト間隔に該当しません。
予測区間を生成するには、予測された平均の周りの個々の点の分布についていくつかの強い仮定を行う必要があります。その後、個々のツリー(ブートストラップされた信頼区間部分)から予測を取得し、仮定されたそのセンターとの配布。生成されたこれらのピースの分位数が予測間隔を形成する場合があります(ただし、それでもテストします。プロセスをさらに数回繰り返して結合する必要がある場合があります)。
これは、そのツリーからの推定MSEに基づいた標準偏差を使用して、予測に標準偏差(元のデータは標準を使用していることがわかっているため)を追加してこれを行う例です。
pred.rf.int2 <- sapply(1:4, function(i) {
tmp <- pred.rf$individual[i, ] + rnorm(1001, 0, sqrt(fit2$mse))
quantile(tmp, c(0.025, 0.975))
})
t(pred.rf.int2)
# 2.5% 97.5%
# [1,] 7.351609 17.31065
# [2,] 10.386273 20.23700
# [3,] 13.004428 23.55154
# [4,] 16.344504 24.35970
これらの間隔には完全な知識に基づいた間隔が含まれているため、合理的に見えます。しかし、それらは行われた仮定に大きく依存します(データがどのようにシミュレートされたかについての知識を使用したため、ここでの仮定は有効です。実際のデータの場合は有効でない場合があります)。この方法を完全に信頼する前に、実際のデータのように見える(ただし、真実を知っているようにシミュレートされた)データに対して、シミュレーションを数回繰り返します。
これは古い投稿であることに気づきましたが、これについていくつかのシミュレーションを実行しており、自分の発見を共有すると思いました。
@GregSnowはこれについて非常に詳細な投稿をしましたが、個々のツリーからの予測を使用して間隔を計算するとき、彼は70%の予測間隔であるを見ていました。95%の予測間隔を取得するには、を調べる必要があります。[ μ + 1.96 * σ 、μ - 1.96 * σ ]
@GregSnowコードにこの変更を加えると、次の結果が得られます
set.seed(1)
x1 <- rep( 0:1, each=500 )
x2 <- rep( 0:1, each=250, length=1000 )
y <- 10 + 5*x1 + 10*x2 - 3*x1*x2 + rnorm(1000)
library(randomForest)
fit2 <- randomForest(y~x1+x2)
pred.rf <- predict(fit2, newdat, predict.all=TRUE)
pred.rf.int <- t(apply( pred.rf$individual, 1, function(x){
c( mean(x) + c(-1.96,1.96)*sd(x), quantile(x, c(0.025,0.975)) )}))
pred.rf.int
2.5% 97.5%
1 7.826896 16.05521 9.915482 15.31431
2 11.010662 19.35793 12.298995 18.64296
3 14.296697 23.61657 14.749248 21.11239
4 18.000229 23.73539 18.237448 22.10331
@GregSnowのようなMSEが示すように、これらを標準偏差の予測に標準偏差を追加することで生成された間隔と比較します。
pred.rf.int2 <- sapply(1:4, function(i) {
tmp <- pred.rf$individual[i,] + rnorm(1000, 0, sqrt(fit2$mse))
quantile(tmp, c(0.025, 0.975))
})
t(pred.rf.int2)
2.5% 97.5%
[1,] 7.486895 17.21144
[2,] 10.551811 20.50633
[3,] 12.959318 23.46027
[4,] 16.444967 24.57601
これら両方のアプローチによる間隔は、現在非常に近づいています。この場合のエラー分布に対する3つのアプローチの予測間隔をプロットすると、次のようになります。
次に、シミュレーションを再実行しますが、今回は誤差項の分散を増やします。予測間隔の計算が適切であれば、上記よりも広い間隔で終了するはずです。
set.seed(1)
x1 <- rep( 0:1, each=500 )
x2 <- rep( 0:1, each=250, length=1000 )
y <- 10 + 5*x1 + 10*x2 - 3*x1*x2 + rnorm(1000,mean=0,sd=5)
fit1 <- lm(y~x1+x2)
newdat <- expand.grid(x1=0:1,x2=0:1)
predict(fit1,newdata=newdat,interval = "prediction")
fit lwr upr
1 10.75006 0.503170 20.99695
2 13.90714 3.660248 24.15403
3 19.47638 9.229490 29.72327
4 22.63346 12.386568 32.88035
set.seed(1)
fit2 <- randomForest(y~x1+x2,localImp=T)
pred.rf.int <- t(apply( pred.rf$individual, 1, function(x){
c( mean(x) + c(-1.96,1.96)*sd(x), quantile(x, c(0.025,0.975)) )}))
pred.rf.int
2.5% 97.5%
1 7.889934 15.53642 9.564565 15.47893
2 10.616744 18.78837 11.965325 18.51922
3 15.024598 23.67563 14.724964 21.43195
4 17.967246 23.88760 17.858866 22.54337
pred.rf.int2 <- sapply(1:4, function(i) {
tmp <- pred.rf$individual[i,] + rnorm(1000, 0, sqrt(fit2$mse))
quantile(tmp, c(0.025, 0.975))
})
t(pred.rf.int2)
2.5% 97.5%
[1,] 1.291450 22.89231
[2,] 4.193414 25.93963
[3,] 7.428309 30.07291
[4,] 9.938158 31.63777
これにより、2番目のアプローチによる予測間隔の計算がはるかに正確になり、線形回帰の予測間隔に非常に近い結果が得られることが明らかになりました。
正規性を仮定すると、ランダムフォレストから予測間隔を計算する別の簡単な方法があります。個々のツリーのそれぞれから、予測値()と平均二乗誤差()が得られます。したがって、個々のツリーからの予測はと考えることができます。正規分布のプロパティを使用すると、ランダムフォレストからの予測の分布はます。これを上記の例に適用すると、以下の結果が得られます M S E I N (μ I、R M S E I)N (Σ μ I / N 、Σ R M S E I / N )
mean.rf <- pred.rf$aggregate
sd.rf <- mean(sqrt(fit2$mse))
pred.rf.int3 <- cbind(mean.rf - 1.96*sd.rf, mean.rf + 1.96*sd.rf)
pred.rf.int3
1 1.332711 22.09364
2 4.322090 25.08302
3 8.969650 29.73058
4 10.546957 31.30789
これらは、線形モデルの間隔および@GregSnowが提案したアプローチと非常によく一致しています。ただし、ここで説明したすべての方法の基本的な前提は、誤差が正規分布に従うことであることに注意してください。
あなたはRを使用する場合は、簡単にランダムな森林回帰の予測のための予測区間を生成することができます:ちょうどパッケージを使用quantregForest
(で利用可能CRANを)読みN. Meinshausenの論文分位回帰森林とどのように推測することができる方法、条件付き分位のを彼ら予測間隔を構築するために使用できます。Rを使用していなくても、非常に有益です!
これはrandomForestで簡単に解決できます。
最初に回帰タスクを処理します(フォレストに1000本のツリーがあると仮定します)。predict
機能は、個々の木から結果を返すためのオプションを持っています。これは、1000列の出力を受け取ることを意味します。各行の平均1000列を取得できます。これは、RFが何らかの方法で生成した通常の出力です。予測間隔を取得するには、+ /-2 stdとしましょう。必要な偏差は、各行について、1000の値から+/- 2 stdを計算することだけです。偏差を計算し、これらを予測の上限および下限にします。
次に、分類の場合、各ツリーは1または0(デフォルト)を出力し、1000で除算された1000のツリーすべての合計がクラスの確率(バイナリ分類の場合)になることを忘れないでください。確率に予測間隔を設定するには、最小値を変更する必要があります。nodesizeオプション(そのオプションの正確な名前についてはrandomForestドキュメントを参照)に値>> 1を設定すると、個々のツリーは1〜0の数値を出力します。ここからは、上記と同じプロセスを繰り返すことができます回帰タスク。
それが理にかなっていることを願っています。
私はいくつかのオプションを試しました(これはすべてWIPです):
実際、従属変数を、単一の値ではなく、結果を範囲とする分類問題にしました。私が得た結果は、単純な値を使用した場合に比べて劣っていました。私はこのアプローチをあきらめました。
次に、それを複数の分類問題に変換しました。それぞれが範囲の下限(モデルが下限を超えるかどうかの結果)で、すべてのモデルを実行し(〜20)、その後結果を組み合わせて、最終的な回答を範囲として取得しました。これは上記の1よりもうまく機能しますが、必要なほどには機能しません。私はまだこのアプローチの改善に取り組んでいます。
OOBとleave-one-outの見積もりを使用して、モデルの良し悪しを判断しました。
ランダムフォレスト予測の予測間隔を構築する問題は、次のペーパーで対処されています。
Zhang、Haozhe、Joshua Zimmerman、Dan Nettleton、Daniel J.Nordman。「ランダムフォレストの予測間隔」。アメリカの統計学者、2019。
Rパッケージ「rfinterval」は、CRANで利用可能な実装です。
Rパッケージrfintervalをインストールするには:
#install.packages("devtools")
#devtools::install_github(repo="haozhestat/rfinterval")
install.packages("rfinterval")
library(rfinterval)
?rfinterval
クイックスタート:
train_data <- sim_data(n = 1000, p = 10)
test_data <- sim_data(n = 1000, p = 10)
output <- rfinterval(y~., train_data = train_data, test_data = test_data,
method = c("oob", "split-conformal", "quantreg"),
symmetry = TRUE,alpha = 0.1)
### print the marginal coverage of OOB prediction interval
mean(output$oob_interval$lo < test_data$y & output$oob_interval$up > test_data$y)
### print the marginal coverage of Split-conformal prediction interval
mean(output$sc_interval$lo < test_data$y & output$sc_interval$up > test_data$y)
### print the marginal coverage of Quantile regression forest prediction interval
mean(output$quantreg_interval$lo < test_data$y & output$quantreg_interval$up > test_data$y)
データの例:
oob_interval <- rfinterval(pm2.5 ~ .,
train_data = BeijingPM25[1:1000, ],
test_data = BeijingPM25[1001:2000, ],
method = "oob",
symmetry = TRUE,
alpha = 0.1)
str(oob_interval)
score
、パフォーマンスを評価するための何らかの機能があります。出力はフォレスト内のツリーの多数決に基づいているため、分類の場合、投票の分布に基づいて、この結果が真になる確率が得られます。ただし、回帰についてはわかりません。どのライブラリを使用していますか?