是否可以改变 randomForest 中使用的引导和/或子采样方案?

gen*_*ser 5 statistics r classification machine-learning random-forest

我正在将随机森林训练为多级数据,本质上将其视为非参数回归模型。我将未观察到的组级异质性视为随机森林训练过程之外的修正。但在随机森林训练过程中,我希望每棵树都是从横截面单元的随机引导样本(或子样本)而不是观察中生长出来的。因此,假设我的数据是对许多个体的多次观察,我想引导个体,而不是对个体的观察。

下面的虚拟示例表明这并strata不能解决我的问题。

> N <- 1000
> p <- 100
> A <- matrix(rnorm(p^2),p)
> library(MASS)
> X <- mvrnorm(N, rep(0,p), A %*%t(A))
> B <- rnorm(p)
> fac <- sample(1:1000 %% 10 +1)
> y <- log(fac + exp(X%*%B)^{1/fac}) + rnorm(N, sd = 10)
> fac <- as.factor(fac)
> library(randomForest)
> forest <- randomForest(y = y, x = cbind(X, fac), ntree = 1, keep.inbag = TRUE, replace = FALSE
+  , strata = fac                        #Stratify by the factor
+ )
> sum(forest$inbag[fac == '1'])
[1] 62
> sum(forest$inbag[fac == '2'])
[1] 60
> sum(forest$inbag[fac == '3'])
[1] 60
> sum(forest$inbag[fac == '4'])
[1] 64
> sum(forest$inbag[fac == '5'])
[1] 64
> sum(forest$inbag[fac == '6'])
[1] 65
> sum(forest$inbag[fac == '7'])
[1] 54
> sum(forest$inbag[fac == '8'])
[1] 72
> sum(forest$inbag[fac == '9'])
[1] 62
> sum(forest$inbag[fac == '10'])
[1] 69
Run Code Online (Sandbox Code Playgroud)

或者,我可以将单个随机子空间树种植到我自己选择的样本中,然后手动组合这些树。这是下面的。

"%ni%" <- Negate("%in%")
library(foreach)
rf_cluster_bootstrap <- foreach(j = 1:10) %do% {
  set.seed(j)
  sampfac <- sample(unique(fac), replace = TRUE)
  unsampfac <-unique(fac[fac %ni% sampfac])
  Xt <- foreach(i = sampfac, .combine = rbind) %do% {Xmat[Xmat$fac == i,]}
  Xt$fac <- NULL
  fj <- randomForest(y = y, x = Xt, ntree = 1, sampsize = nrow(Xt), replace = FALSE, keep.inbag = TRUE)
  Xnt <- foreach(i = unsampfac, .combine = rbind) %do% {Xmat[Xmat$fac == i,]}
  Xnt$fac <- NULL
  pred <- predict(fj, newdata = Xnt)
  oob_outvec <- rep(NA, N)
  oob_outvec[as.numeric(names(pred))] <- pred
  return(list(fj = fj, oob = oob_outvec))
}
Run Code Online (Sandbox Code Playgroud)

虽然这似乎可行,但我需要编写自己的预测函数,跟踪行名称等。可能会出现编码错误和其他意外的事情。例如,这是一个组合输出的函数:

combineFunc <- function(x){
  rflist <- lapply(x, `[[`, 'fj')
  # rf <- randomForest::combine(rflist)#I don't know why this doesn't work
  rf <- foreach(i = 1:10, .combine = randomForest::combine) %do% {rflist[[i]]}
  return(rf)
}

xx <- combineFunc(rf_cluster_bootstrap)
head(xx$inbag)
    [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
101    0    1    0    3    1    0    0    0    0     0
102    3    0    1    0    2    2    1    3    2     1
103    0    1    0    2    1    1    0    1    0     1
104    0    2    1    0    3    0    1    0    2     0
105    1    0    0    1    1    0    0    1    1     0
106    0    0    3    1    1    0    1    1    2     1
Run Code Online (Sandbox Code Playgroud)

矩阵之类的基本东西inbag都是乱码。我可以解决它,但我不太可能抓住一切。

在我从头开始做这件事之前,我想知道是否有一些已经实现的东西可以实现我想要做的事情?或者更简单/更优雅的方式来做到这一点?

此线程类似,但它使用rpart,它无法处理随机子空间)

小智 1

我本想将此作为评论,但我还没有足够的声誉。这不是一个明确的答案,但我想为像我一样在类似搜索中看到这篇文章的其他人留下一些东西。

我还没有亲自尝试过,但这是 RI 中遇到的随机森林的阻塞引导的相对较新的实现(blockForest https://rdrr.io/cran/blockForest/),它似乎正在实现您想做的事情。

引用:https://bmcbioinformatics.biomedcentral.com/articles/10.1186/s12859-019-2942-y