【问题标题】:Combining random forests built with different training sets in R在 R 中结合使用不同训练集构建的随机森林
【发布时间】:2013-10-10 19:07:51
【问题描述】:

我是 R 新手(第 2 天),我的任务是构建一个随机森林森林。每个单独的随机森林都将使用不同的训练集构建,最后我们将结合所有森林进行预测。我在 R 中实现了这一点,并且在组合两个不是使用同一组构建的森林时遇到了一些困难。我的尝试如下:

d1 = read.csv("../data/rr/train/10/chunk0.csv",header=TRUE)
d2 = read.csv("../data/rr/train/10/chunk1.csv",header=TRUE)

rf1 = randomForest(A55~., data=d1, ntree=10)
rf2 = randomForest(A55~., data=d2, ntree=10)

rf = combine(rf1,rf2)

这当然会产生错误:

Error in rf$votes + ifelse(is.na(rflist[[i]]$votes), 0, rflist[[i]]$votes) : 
non-conformable arrays
In addition: Warning message:
In rf$oob.times + rflist[[i]]$oob.times :
longer object length is not a multiple of shorter object length

我已经浏览网页一段时间了,寻找线索,但还没有成功。这里的任何帮助将不胜感激。

【问题讨论】:

  • 这两个数据集的具体结构是什么? (使用str查看)。它们是否具有完全相同的变量,都以相同的方式命名?
  • @joran 他们这样做了。它们都是我手动拆分的更大训练集的子集。当我运行str 时,第一行是:'data.frame': 38735 obs. of 55 variables: 用于 d1,'data.frame': 38734 obs. of 55 variables: 用于 d2。后跟每个数据集的相同名称。
  • 检查每个 rf 对象的 votes 对象的尺寸。可能并非所有因子水平都出现在您的训练数据的每个子集中。
  • @joran 所以虽然我不太明白这意味着什么,但还是有区别的:> length(rf1$votes) [1] 271145>length(rf2$votes) [1] 271138。首先你所说的因子水平是什么意思?其次,我在文档中读到投票是“一个矩阵,每个输入数据点一行,每个类一列,给出随机森林中(OOB)“投票”的分数或数量。这是有道理的,因为数据是不平衡的,但是这些大长度是从哪里来的?
  • 我相信我有一个解决方案。但是,如果您对围绕因素的术语(R 中的一种基本数据类型)感到困惑,那么您将很快就试图用随机森林做一些严肃的事情。在您进一步了解之前,我会非常熟悉 this 的第 2-6 节。

标签: r statistics machine-learning random-forest


【解决方案1】:

啊。这要么是 combine 的疏忽,要么是您尝试做的事情是荒谬的,这取决于您的观点。

投票矩阵记录每个响应类别的训练数据中每个案例在森林中的投票数。自然,它将具有与训练数据中的行数相同的行数。

combine 假设您在 same 数据集上运行了两次随机森林,因此这些矩阵的维度将相同。它这样做是因为它想为您提供组合林的一些“整体”误差估计值。

但如果两个数据集不同,组合投票矩阵就变得毫无意义。您可以通过简单地从较大的训练数据集中删除一行来运行 combine,但组合森林中生成的投票矩阵会是乱码,因为每一行都是两个不同训练案例的投票组合。

所以也许这只是一个可以在combine 中关闭的选项。因为在结果对象上应该结合实际的树和predict 仍然有意义。但是combine 输出中的一些“组合”错误估计将毫无意义。

长话短说,让每个训练数据集大小相同,它就会运行。但如果你这样做了,除了做出新的预测之外,我不会将结果对象用于其他任何事情。任何总结森林表现的组合都是无稽之谈。

然而,我认为打算使用combine的方法是在完整数据集上拟合多个随机森林,但减少了树,然后将这些森林组合起来。

编辑

我继续修改 combine 以“处理”不相等的训练集大小。这实际上意味着我删除了一大块试图将不匹配的东西拼接在一起的代码。但是结合森林的部分我保留了,所以你仍然可以使用predict

my_combine <- function (...) 
{
    pad0 <- function(x, len) c(x, rep(0, len - length(x)))
    padm0 <- function(x, len) rbind(x, matrix(0, nrow = len - 
        nrow(x), ncol = ncol(x)))
    rflist <- list(...)
    areForest <- sapply(rflist, function(x) inherits(x, "randomForest"))
    if (any(!areForest)) 
        stop("Argument must be a list of randomForest objects")
    rf <- rflist[[1]]
    classRF <- rf$type == "classification"
    trees <- sapply(rflist, function(x) x$ntree)
    ntree <- sum(trees)
    rf$ntree <- ntree
    nforest <- length(rflist)
    haveTest <- !any(sapply(rflist, function(x) is.null(x$test)))
    vlist <- lapply(rflist, function(x) rownames(importance(x)))
    numvars <- sapply(vlist, length)
    if (!all(numvars[1] == numvars[-1])) 
        stop("Unequal number of predictor variables in the randomForest objects.")
    for (i in seq_along(vlist)) {
        if (!all(vlist[[i]] == vlist[[1]])) 
            stop("Predictor variables are different in the randomForest objects.")
    }
    haveForest <- sapply(rflist, function(x) !is.null(x$forest))
    if (all(haveForest)) {
        nrnodes <- max(sapply(rflist, function(x) x$forest$nrnodes))
        rf$forest$nrnodes <- nrnodes
        rf$forest$ndbigtree <- unlist(sapply(rflist, function(x) x$forest$ndbigtree))
        rf$forest$nodestatus <- do.call("cbind", lapply(rflist, 
            function(x) padm0(x$forest$nodestatus, nrnodes)))
        rf$forest$bestvar <- do.call("cbind", lapply(rflist, 
            function(x) padm0(x$forest$bestvar, nrnodes)))
        rf$forest$xbestsplit <- do.call("cbind", lapply(rflist, 
            function(x) padm0(x$forest$xbestsplit, nrnodes)))
        rf$forest$nodepred <- do.call("cbind", lapply(rflist, 
            function(x) padm0(x$forest$nodepred, nrnodes)))
        tree.dim <- dim(rf$forest$treemap)
        if (classRF) {
            rf$forest$treemap <- array(unlist(lapply(rflist, 
                function(x) apply(x$forest$treemap, 2:3, pad0, 
                  nrnodes))), c(nrnodes, 2, ntree))
        }
        else {
            rf$forest$leftDaughter <- do.call("cbind", lapply(rflist, 
                function(x) padm0(x$forest$leftDaughter, nrnodes)))
            rf$forest$rightDaughter <- do.call("cbind", lapply(rflist, 
                function(x) padm0(x$forest$rightDaughter, nrnodes)))
        }
        rf$forest$ntree <- ntree
        if (classRF) 
            rf$forest$cutoff <- rflist[[1]]$forest$cutoff
    }
    else {
        rf$forest <- NULL
    }
    #
    #Tons of stuff removed here...
    #
    if (classRF) {
        rf$confusion <- NULL
        rf$err.rate <- NULL
        if (haveTest) {
            rf$test$confusion <- NULL
            rf$err.rate <- NULL
        }
    }
    else {
        rf$mse <- rf$rsq <- NULL
        if (haveTest) 
            rf$test$mse <- rf$test$rsq <- NULL
    }
    rf
}

然后你可以像这样测试它:

data(iris)
d <- iris[sample(150,150),]
d1 <- d[1:70,]
d2 <- d[71:150,]
rf1 <- randomForest(Species ~ ., d1, ntree=50, norm.votes=FALSE)
rf2 <- randomForest(Species ~ ., d2, ntree=50, norm.votes=FALSE)

rf.all <- my_combine(rf1,rf2)
predict(rf.all,newdata = iris)

显然,这绝对没有保修! :)

【讨论】:

  • 感谢@joran 的详细回复。我想知道如果组合和预测是否有意义,投票矩阵的大小是否相同,因为正如您所说,每一行都是两个不同训练案例的组合。也感谢您的链接,我会检查一下。可悲的是,在我的情况下,使每个训练集的大小相同不是一种选择,因为我想看到的一件事是倾斜数据如何影响该系统的整体性能。最重要的是更大和(希望)更好的想法!
  • 再次感谢,真的很棒。我最终做的是创建一堆森林并分别对每个森林进行预测。然后我将这些矩阵组合成一个更大的预测矩阵。再次感谢!
  • @joran :我们可以结合两个森林,每个森林都适合不同的预测变量集吗?我有 5 个预测变量……当我使用 2 个预测变量来预测类时,拟合模型的准确率大约为 70%……当我使用另外 3 个时,我得到大约 65% 的准确率。但是当我使用所有 5 个时,准确率保持在 65%
  • 非常棒的解决方案@joran。这可以添加到包中吗?我的意思是这真的很有帮助。
猜你喜欢
  • 2013-02-13
  • 2019-07-20
  • 2018-06-13
  • 2020-10-31
  • 2017-01-22
  • 2014-08-04
  • 2016-04-13
  • 2012-10-25
  • 1970-01-01
相关资源
最近更新 更多