我是R的新手(使用第二天),被分配了构建一个随机森林集合的任务。每个单独的随机森林将使用不同的训练集构建,我们将在最后将所有森林组合起来进行预测。我正在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 arraysIn addition: Warning message:In rf$oob.times + rflist[[i]]$oob.times :longer object length is not a multiple of shorter object length
我在网上搜索了很长时间,试图找到解决这个问题的线索,但至今没有成功。任何帮助都将不胜感激。
回答:
啊。这要么是combine
函数的一个疏忽,要么是你试图做的事情本身没有意义,这取决于你的观点。
投票矩阵记录了森林中每个训练数据案例对每个响应类别的投票数。自然,它的行数与你的训练数据的行数相同。
combine
函数假设你对同一组数据运行了两次随机森林,因此这些矩阵的维度将相同。它这样做是因为它想为组合后的森林提供一些“总体”错误估计。
但如果两个数据集是不同的,那么组合投票矩阵就变得毫无意义。你可以通过简单地从较大的训练数据集中删除一行来让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)
显然,这完全没有保修!:)