美文网首页
RFCV函数

RFCV函数

作者: 皮尔洛_dys | 来源:发表于2022-08-30 14:44 被阅读0次
    # function
    rfcv1 <- function(trainx, trainy, cv.fold = 5, scale = "log", step = 0.5, mtry = function(p) max(1, floor(sqrt(p))), recursive = FALSE, 
                      ipt = NULL, ...) {
      #判断标签值是否为因子类型
      classRF <- is.factor(trainy)#结果为True
      #获取整个数据的行数和列数,其中行数=n(样本数),列数=p(特征数量)
      n <- nrow(trainx)
      p <- ncol(trainx)
      #以step的倒数为底对特征数量求对数得到k,然后再用特征数量乘以step的k次方(实际上就是用特征数量连续的除以step,得到一个从满特征到1的等比数列)
      #这一步实际上在不断地削减特征数量,以便于最终精简构建模型所需要的特征数量,以达到用尽量少的特征但得到精良精确模型的目的。
      #最终得到的等比数列存储在n.var中
      #711 474 316 211 140  94  62  42  28  18  12   8   5   4   2   1   0
      if (scale == "log") {
        k <- floor(log(p, base = 1/step))
        n.var <- round(p * step^(0:(k - 1)))
        same <- diff(n.var) == 0
        if (any(same)) 
          n.var <- n.var[-which(same)]
        if (!1 %in% n.var) 
          n.var <- c(n.var, 1)
      } else {
        n.var <- seq(from = p, to = 1, by = step)
      }
      #计算等比数列的长度
      k <- length(n.var)
      #构建一个向量cv.pred,其长度与等比数列相等但每一个元素都是一个列表
      cv.pred <- vector(k, mode = "list")
      #先将整个数据的标签填入cv.pred
      for (i in 1:k) cv.pred[[i]] <- trainy
      #
      if (classRF) {
        f <- trainy#将标签复制给f
        if (is.null(ipt)) 
          ipt <- nlevels(trainy) + 1#ipt复制标签的种类加1
      } else {
        f <- factor(rep(1:5, length = length(trainy))[order(order(trainy))])
        if (is.null(ipt)) 
          ipt <- 1
      }
      nlvl <- table(f)#将分类标签的table复制给nlvl
      idx <- numeric(n)#idx=样本数
      #整个数据中有两种样本标签A,B,其中A有100个B有103个,根据cv.fold的值不断重复1-cv.fold得到两个循环列表,列表长度分别等于A和B的个数
      #然后将循环列表的顺序打乱分别填写在idx的对应A和B的位置上
      #这样A和B的样本就被大致均等的标记为5份,以便于后期的交叉验证
      for (i in 1:length(nlvl)) {
        idx[which(f == levels(f)[i])] <- sample(rep(1:cv.fold, length = nlvl[i]))
      }
      
      res = list()
      #循环cv.fold次,即进行cv.fold次交叉验证
      for (i in 1:cv.fold) {
        #当循环进入第i次时,将没有被i标记的样本作为训练集,用被i标记过的样本作为测试集进行随机森林建模及验证
        all.rf <- randomForest(trainx[idx != i, , drop = FALSE], trainy[idx != i], trainx[idx == i, , drop = FALSE], trainy[idx == 
                                                                                                                              i], mtry = mtry(p), importance = TRUE)
        #将测试集预测得到的结果复制给cv.pred的对应位置,idx==1说明使用的是非i标记数据所构成训练集的全部特征的预测结果
        cv.pred[[1]][idx == i] <- all.rf$test$predicted
        #随机森林模型会根据预测结果给出训练集所使用特征的importance,将这些特征的importance进行排序(从高到低)并记录其索引,以方便
        #后续模型精简过程中提取前n个重要的特征进行建模
        impvar <- (1:p)[order(all.rf$importance[, ipt], decreasing = TRUE)]
        res[[i]] <- impvar
        #开始从第二数量特征遍历
        for (j in 2:k) {
          imp.idx <- impvar[1:n.var[j]]#挑选出按照重要性从高到低排列的前n个importance的索引
          #用五分之一的数据验证模型,用其他数据的前n个特征训练模型
          sub.rf <- randomForest(trainx[idx != i, imp.idx, drop = FALSE], trainy[idx != i], trainx[idx == i, imp.idx, drop = FALSE], 
                                 trainy[idx == i], mtry = mtry(n.var[j]), importance = recursive)
          #将预测结果存储在对应位置上
          cv.pred[[j]][idx == i] <- sub.rf$test$predicted
          if (recursive) {
            impvar <- (1:length(imp.idx))[order(sub.rf$importance[, ipt], decreasing = TRUE)]
          }
          NULL
        }
        NULL
      }
      #经历上述循环后,会得到一个预测见过的向量,其中不仅包含了k折交叉验证的的结果,每次交叉验证还包含了使用不同数量特征预测得到的结果
      #共k.fold*(等比数列长度)个结果
      if (classRF) {
        error.cv <- sapply(cv.pred, function(x) mean(trainy != x))#计算不同数量特征建模五次交叉验证的平均错误率
      } else {
        error.cv <- sapply(cv.pred, function(x) mean((trainy - x)^2))
      }
      names(error.cv) <- names(cv.pred) <- n.var
      #n.var=存储的是特征数量除以step的等比数列,error.cv是不同特征五次交叉验证的平均错误率,predicted是不同数量特征验证得到的结果,res是importance排名的索引
      list(n.var = n.var, error.cv = error.cv, predicted = cv.pred, res = res)
    } 
    

    相关文章

      网友评论

          本文标题:RFCV函数

          本文链接:https://www.haomeiwen.com/subject/vsednrtx.html