随机森林模型的预测是否具有预测间隔?


52

如果运行randomForest模型,则可以基于该模型进行预测。有没有一种方法可以获取每个预测的预测间隔,以使我知道模型如何“确定”其答案。如果可能的话,是仅仅基于整个模型的因变量的可变性,还是根据特定预测所遵循的特定决策树,其间隔会变宽还是变窄?


3
AFAIK,所有RF库都具有某种score用于评估性能的功能。由于输出基于森林中树木的多数票,因此在分类的情况下,基于票数分配,您将有可能获得该结果为真。但是我不确定回归...。您使用哪个库?
sashkello

Answers:


40

这部分是对@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。这意味着基于完美知识的95%预测区间这些点将是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

这些时间间隔包含基于完美知识的时间间隔,因此看起来很合理。但是,它们将在很大程度上取决于所做的假设(这些假设在这里是有效的,因为我们使用的是如何模拟数据的知识,在实际数据情况下它们可能不那么有效)。在完全信任此方法之前,我仍将对看起来更像您的真实数据的数据重复进行几次模拟(但模拟后才知道真相)。


11

我意识到这是一篇过时的文章,但是我已经对此进行了一些模拟,并认为我会分享我的发现。

@GregSnow对此发表了非常详细的文章,但是我相信,当使用来自单个树的预测来计算间隔时,他所查看的仅是70%的预测间隔。我们需要查看以获得95%的预测间隔。[ μ + 1.96 σ μ - 1.96 σ ][μ+σ,μσ][μ+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

这两种方法的间隔现在看起来非常接近。在这种情况下,针对误差分布绘制三种方法的预测间隔如下图所示

在此处输入图片说明

  • 黑线=线性回归的预测间隔,
  • 红线=根据个别预测计算的随机森林间隔,
  • 蓝线=通过将正态偏差添加到预测中来计算的随机森林间隔

现在,让我们重新运行仿真,但是这次增加了误差项的方差。如果我们的预测间隔计算结果很好,那么最终的间隔应该比上面得到的间隔宽。

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

在此处输入图片说明

现在,这清楚地表明,通过第二种方法计算预测间隔的准确性要高得多,并且所产生的结果与线性回归的预测间隔非常接近。

以正常性为假设,还有另一种更容易的方法来从随机森林中计算预测间隔。从单独的树中,我们都有预测值()和均方误差()。因此,可以将来自每个单独树的预测视为。使用正态分布属性,我们对随机森林的预测将具有分布。将其应用到我们上面讨论的示例中,我们得到以下结果中号小号ë Ñ μ - [R 中号小号ë Ñ Σ μ / Ñ Σ [R 中号小号ë / Ñ μiMSEiN(μi,RMSEi)N(μi/n,RMSEi/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建议的方法非常吻合。但是请注意,在我们讨论的所有方法中,基本假设是误差遵循正态分布。


10

如果使用R,则可以轻松地为随机森林回归的预测生成预测间隔:只需使用该软件包quantregForest(可在CRAN处获得),并阅读N. Meinshausen论文,了解如何利用分位数回归森林推断条件分位数以及它们如何可用于建立预测间隔。即使您不使用R,也非常有用!



2
这似乎是适当的答案,并且不需要关于预测间隔的分布假设。这里是如何做到这一点在Python这里的教程:blog.datadive.net/prediction-intervals-for-random-forests
科林

6

使用randomForest很容易解决。

首先让我处理回归任务(假设您的森林有1000棵树)。在predict函数中,您可以选择从单个树返回结果。这意味着您将收到1000列的输出。我们可以取每一行1000列的平均值-这是常规RF输出会以任何方式产生的结果。现在,要获得预测间隔,可以说+/- 2 std。偏差您需要做的是,对于每一行,从1000个值中计算+/- 2 std。偏差,并将其作为预测的上限和下限。

其次,在分类的情况下,请记住,每棵树都输出1或0(默认情况下),并且所有1000棵树的总和除以1000得出类的概率(在二进制分类的情况下)。为了对概率设置预测间隔,您需要修改最小值。设置节点大小选项(有关该选项的确切名称,请参阅randomForest文档),一旦将其设置为值>> 1,则各个树将输出1到0之间的数字。现在,从此处开始,您可以重复上述步骤回归任务。

我希望这是有道理的。


我没有尝试过,但这似乎很有意义。感谢您回答我的旧问题。
Dean MacGregor 2013年

1
我认为这种方法将给出比置信区间更多的置信区间。应将结果与线性模型进行比较,在线性模型中预测间隔的理论已得到很好的建立。最好在一些已知真相且所有假设成立的模拟数据上。
格雷格·斯诺

1
@GregSnow:从我上面描述的内容中您将得到的肯定是预测间隔。请注意,预测间隔通常比置信区间宽得多,因为置信区间实际上指定了量化平均值的统计位置在哪里,因为预测仅涉及一个观测值,因此不确定性更大,间隔也更大。您可以从1000棵树中获得1000个预测作为自举样本,您无需在此处应用正态性假设。甚至简单的十分位数分析也可以得出良好的结果。

5
@SashikanthDareddy,您从描述中得到的绝对不是预测间隔。预测间隔不仅仅取决于更宽。是的,单个树形成一个引导程序,但是引导程序估计参数,而不是单个值。预测间隔非常取决于各个点的分布。您的方法给出了具有分类结果而不是类别的比例区间的事实表明了这一点。请参阅添加的答案中的示例。
格雷格·斯诺

0

我尝试了一些选项(所有WIP):

  1. 我实际上使因变量成为分类问题,其结果作为范围而不是单个值。与使用普通值相比,我得到的结果很差。我放弃了这种方法。

  2. 然后,我将其转换为多个分类问题,每个问题都是该范围的下界(模型的结果是是否会越过下界),然后运行所有模型(〜20),然后结合结果以得出最终答案。这比上面的1更好,但是没有我需要的那么好。我仍在努力改善这种方法。

我使用OOB和一劳永逸的估算值来确定模型的优劣。


0

在以下论文中已经解决了为随机森林预测构建预测间隔的问题:

张浩哲,约书亚·齐默尔曼,丹·内特尔顿和丹尼尔·诺德曼。“随机森林预测间隔。” 美国统计学家,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)

1
欢迎来到该站点@xiaolongmao。您可能想参加我们的游览。请不要将相同的答案发布到多个线程。尝试在每个线程上自定义对特定问题的答案。如果您确实相信完全相同的答案可以完全回答问题,则表明该问题是重复的。当您的声望达到50时,您可以向OP发布评论。在此期间,您可以将要关闭的Q标记为重复项。
gung-恢复莫妮卡
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.