【机器学习】Stacking与K折交叉验证

其他机器学习系列文章见于专题:机器学习进阶之路——学习笔记整理,欢迎大家关注。

1. Stacking定义

  Stacking并不是简单地对个体学习器的结果做简单逻辑处理,而是先从初始数据集训练出初级学习器,将初级学习器的输出当成特征,初始样本的标记仍被当作标记,由此生成一个新数据集用于训练学习器。

Stacking结构图

2. Stacking原理

  假设我们有两个初级学习器 M o d e l 1 Model1 Model1 M o d e l 2 Model2 Model2

  (1)对初级学习器 M o d e l 1 Model1 Model1,利用训练集 D D D进行训练,然后用训练好的 M o d e l 1 Model1 Model1预测训练集 D D D和测试集 T T T的标签列,结果分别为 P 1 P1 P1 T 1 T1 T1

  (2)对初级学习器 M o d e l 2 Model2 Model2,重复步骤(1),得到预测标签结果 P 2 P2 P2 T 2 T2 T2

  (3)将两个初级学习器的结果合并,得到次级学习器 M o d e l 3 Model3 Model3的训练集 P 3 = ( P 1 , P 2 ) P3=(P1, P2) P3=(P1,P2)和测试集 T 3 = ( T 1 , T 2 ) T3=(T1, T2) T3=(T1,T2)。也就是说,有多少个初级学习器,次级学习器的训练集和测试集就有多少列(特征)。

  (4)用 P 3 P3 P3训练次级学习器 M o d e l 3 Model3 Model3,并预测 T 3 T3 T3,得到最终的预测结果。

3. Stacking算法描述

  输入:训练集 D D D,初级学习算法 L 1 , L 2 , . . . , L T {\mathfrak{L}}_1,{\mathfrak{L}}_2,...,{\mathfrak{L}}_T L1,L2,...,LT,次级学习算法 L \mathfrak{L} L

  过程:

    (1)对 i = 1 , 2 , … , m {i = 1,2, \ldots ,m} i=1,2,,m,使用初级学习算法 L t \mathfrak{L}_t Lt产生初级学习器 h t = L t ( D ) h _ { t } = \mathfrak { L } _ { t } ( D ) ht=Lt(D);

    (2)生成次级训练集:

       D ′ = ∅ D ^ { \prime } = \emptyset D=

       f o r i = 1 , 2 , … , m d o {{for\quad }i = 1,2, \ldots ,m\quad do} fori=1,2,,mdo

         f o r t = 1 , 2 , … , T d o {{for\quad }t = 1,2, \ldots ,T\quad do} fort=1,2,,Tdo

           z i t = h t ( x i ) {{z_{it}} = {h_t}\left( {{x_i}} \right)} zit=ht(xi)

         e n d f o r {{ end\quad for}} endfor

         D ′ = D ′ ∪ ( ( z i 1 , z i 2 , … , z i T ) , y i ) {{D^\prime } = {D^\prime } \cup \left( {\left( {{z_{i1}},{z_{i2}}, \ldots ,{z_{iT}}} \right),{y_i}} \right)} D=D((zi1,zi2,,ziT),yi)

       e n d f o r {{ end\quad for}} endfor

    (3)在 D ′ {D'} D上用次级学习算法 L \mathfrak{L} L产生次级学习器 h ′ = L ( D ′ ) {h'} = {\mathfrak{L}}\left( {D'} \right) h=L(D)

  输出: H ( x ) = h ′ ( h 1 ( x ) , h 2 ( x ) , … , h T ( x ) ) H\left( x \right) = h'\left( {{h_1}\left( x \right),{h_2}\left( x \right), \ldots ,{h_T}\left( x \right)} \right) H(x)=h(h1(x),h2(x),,hT(x))

4. K折交叉验证

  但是,上述这种做法直接利用训练集训练得到的模型去预测训练集的标签,过拟合风险比较大。因此,一般通过k折交叉验证来缓解这种做法的过拟合问题。

Stacking的5折交叉验证流程图

  以5折交叉验证为例,做法如下:

  (1)原始训练集 D D D被随机划分5个大小相似的子集 D 1 , D 2 , … , D 5 {D_1},{D_2}, \ldots ,{D_5} D1,D2,,D5,令 D j D_j Dj D ‾ j = D \ D j {\overline D _j} = D\backslash {D_j} Dj=D\Dj分别表示第 j j j折的测试集和训练集。

  (2) D 1 D_1 D1训练 M o d e l 1 Model1 Model1,然后在 D 1 D_1 D1上进行预测得到 P 11 P_{11} P11;用 D 2 D_2 D2训练 M o d e l 1 Model1 Model1,然后在 D 2 D_2 D2上进行预测得到 P 12 {P_{12}} P12,重复5次将预测得到的 P 1 = ( P 11 ⋮ P 15 ) P 1 = \left( \begin{array} { c } { P _ { 11 } } \\ { \vdots } \\ { P _ { 15 } } \end{array} \right) P1=P11P15 P 1 P1 P1的训练集样本数等于原始训练集 D D D中的样本数。

  (3)在每次5折交叉验证中,都利用训练好的 M o d e l 1 Model1 Model1对整个测试集 T T T进行预测,然后将5次预测结果求平均得到 T 1 T1 T1

  (4)对初级学习器 M o d e l 2 Model2 Model2,重复步骤(2)(3),得到标签预测结果 P 2 P2 P2 T 2 T2 T2

  (5)拼接得到次级学习器 M o d e l 3 Model3 Model3的训练集 P 3 = ( P 1 , P 2 ) P3=(P1,P2) P3=(P1,P2)和测试集 T 3 = ( T 1 , T 2 ) T3=(T1,T2) T3=(T1,T2)

  (6)用 P 3 P3 P3训练次级学习器 M o d e l 3 Model3 Model3,并预测 T 3 T3 T3,得到最终的预测结果。

参考文献:

  1. 《机器学习》第八章集成学习——周志华
  2. Kaggle机器学习之模型融合(stacked)心得
  3. 【机器学习】模型融合方法概述
  • 3
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
以下是一个基于RandomForest、SVM和XGBoost的stacking代码,使用R2、RMSE和MAE作为评价指标,对训练集进行5折交叉验证: ``` library(caret) library(randomForest) library(e1071) library(xgboost) # 读取数据 data <- read.csv("data.csv") # 拆分数据集为训练集和测试集 set.seed(123) trainIndex <- createDataPartition(data$target, p = .8, list = FALSE) train <- data[trainIndex, ] test <- data[-trainIndex, ] # 定义基模型 rf_model <- randomForest(target ~ ., data = train) svm_model <- svm(target ~ ., data = train) xgb_model <- xgboost(data = as.matrix(train[,1:9]), label = train$target, nrounds = 100, verbose = FALSE) # 交叉验证 folds <- createFolds(train$target, k = 5, list = TRUE) numFolds <- length(folds) # 定义stacking训练集和测试集 stack_train <- data.frame(matrix(NA, nrow = nrow(train), ncol = 3)) colnames(stack_train) <- c("RF", "SVM", "XGB") stack_test <- data.frame(matrix(NA, nrow = nrow(test), ncol = 3)) colnames(stack_test) <- c("RF", "SVM", "XGB") # 训练基模型 for (i in 1:numFolds) { trainIndex <- unlist(folds[i]) cv_train <- train[trainIndex, ] cv_test <- train[-trainIndex, ] # 训练RF rf_pred <- predict(rf_model, cv_test) stack_train[-trainIndex, "RF"] <- rf_pred stack_test[, "RF"] <- stack_test[, "RF"] + predict(rf_model, newdata = test) / numFolds # 训练SVM svm_pred <- predict(svm_model, cv_test) stack_train[-trainIndex, "SVM"] <- svm_pred stack_test[, "SVM"] <- stack_test[, "SVM"] + predict(svm_model, newdata = test) / numFolds # 训练XGB xgb_pred <- predict(xgb_model, as.matrix(cv_test[,1:9])) stack_train[-trainIndex, "XGB"] <- xgb_pred stack_test[, "XGB"] <- stack_test[, "XGB"] + predict(xgb_model, as.matrix(test[,1:9])) / numFolds } # 计算stacking训练集上的R2、RMSE和MAE stack_train$target <- train$target stack_model <- lm(target ~ ., data = stack_train) stack_train_pred <- predict(stack_model, stack_train) stack_train_r2 <- R2(stack_train$target, stack_train_pred) stack_train_rmse <- RMSE(stack_train$target, stack_train_pred) stack_train_mae <- MAE(stack_train$target, stack_train_pred) # 计算stacking测试集上的R2、RMSE和MAE stack_test_pred <- predict(stack_model, stack_test) stack_test_r2 <- R2(test$target, stack_test_pred) stack_test_rmse <- RMSE(test$target, stack_test_pred) stack_test_mae <- MAE(test$target, stack_test_pred) # 打印结果 cat(paste0("Stacking Training R2: ", round(stack_train_r2, 4), "\n")) cat(paste0("Stacking Training RMSE: ", round(stack_train_rmse, 4), "\n")) cat(paste0("Stacking Training MAE: ", round(stack_train_mae, 4), "\n")) cat(paste0("Stacking Testing R2: ", round(stack_test_r2, 4), "\n")) cat(paste0("Stacking Testing RMSE: ", round(stack_test_rmse, 4), "\n")) cat(paste0("Stacking Testing MAE: ", round(stack_test_mae, 4), "\n")) ``` 注意:以上代码仅供参考,具体实现应根据数据集和模型的不同进行相应修改。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值