跳至主要内容

使用 SuperLearner 在 R 中进行集成学习

提升您的机器学习效果,使用 R 的 SuperLearner 包探索集成方法:了解随机森林、袋装法等更多内容!
· 15分钟 阅读

使用 AI 探索

您是否曾想构建一个机器学习集成模型,却不知道从何入手?本教程将通过 SuperLearner 带您上手。这个 R 包通过提供标准化封装器,调用诸如 glmnet、knn、randomForest 等流行 R 机器学习库,用高级函数轻松创建机器学习集成模型!

在本教程中,您将学习以下主题:

  • 什么是集成?在进入本教程的实战示例之前,先简要了解一下集成的定义!
  • 为什么选择 SuperLearner,它到底做什么?
  • 使用 SuperLearner 在 R 中进行集成学习:本节将教您如何安装所需包、准备数据并创建您的第一个集成模型!您还将看到如何训练模型并用其进行预测。在此过程中,您将涉及核支持向量机、贝叶斯广义线性模型以及袋装法。最后,您将了解如何调参以进一步提升模型表现!

完成后,您将训练出第一个集成模型、对新数据进行预测,并对集成中的部分组件进行了调优。

什么是集成?

这些都很棒,但集成究竟是什么?

集成是将多个机器学习模型的概率预测或数值预测进行组合:可以取平均、对各模型加权后求和,或在分类问题中采用多数表决。这会形成“多票决策”的情形,更可能将预测推向正确的类别,或在回归中更接近真实数值。集成往往在各基模型存在分歧时效果最佳。实践中,组合多个模型通常表现良好,往往优于单一算法的实现。

您可以通过分别拟合多个模型、分别预测并再将其结果合并的方式手动创建集成。

为什么选择 SuperLearner?

既然您已经了解什么是集成,您可能会问 SuperLearner 库究竟做什么。简单来说,SuperLearner 是一种算法,它使用交叉验证来评估多个机器学习模型(或同一模型在不同设置下)的性能。随后,它基于测试数据上的性能,为这些模型创建一个最优加权平均,也就是所谓的“集成”。

但为什么要使用 SuperLearner?

尽管您将在教程中进一步体会这个R 包的强大之处,您已经可以先参考以下优势:

  • SuperLearner 允许您只需添加算法即可拟合集成模型
  • 如前所述,SuperLearner 使用交叉验证,本质上用来估计所有模型的风险。这使其非常适合模型比较!
  • SuperLearner 通过自动估计集成权重,让集成更高效。这通常是一项繁琐且需要大量试验的任务。
  • SuperLearner 会自动移除对集成预测能力无贡献的模型,让您可以放心尝试大量算法!

下面来看一下使用 SuperLearner 的流程。

使用 SuperLearner 在 R 中进行集成学习

安装 SuperLearner 包

可以使用 install.packages() 从 CRAN 安装 SuperLearner,然后用 library() 加载到工作空间:

 # Install the package
install.packages("SuperLearner")

# Load the package
library("SuperLearner")

准备数据

为演示 SuperLearner,您将使用 MASS 包中的 Pima 印第安妇女数据集。MASS 包包含训练集(用于训练模型)和测试集(用于评估模型在未见数据上的性能)。该数据集提供了有关 Pima 印第安妇女的一些描述性特征,如怀孕次数、年龄以及是否患有糖尿病。数据集的目标是预测糖尿病。

type 列用于指示是否患有糖尿病。它是一个二元 Yes/No 列,这意味着它服从二项分布。

注意,不做过多理论展开,二项分布是伯努利试验(成功/失败概率试验)的集合。二项分布很容易识别,因为只有两种可能的响应,在这里即 Yes 或 No。为什么要提这个?因为 SuperLearner 需要您定义模型所属问题的分布族。稍后在拟合模型时,您将更详细地看到这一点。

     # Get the `MASS` library
    library(MASS)

    # Train and test sets
    train <- Pima.tr
    test <- Pima.te

    # Print out the first lines of `train`
    head(train)
    ##   npreg glu bp skin  bmi   ped age type
    ## 1     5  86 68   28 30.2 0.364  24   No
    ## 2     7 195 70   33 25.1 0.163  55  Yes
    ## 3     5  77 82   41 35.8 0.156  35   No
    ## 4     0 165 76   43 47.9 0.259  26   No
    ## 5     0 107 60   25 26.4 0.133  23   No
    ## 6     5  97 76   27 35.6 0.378  52  Yes
    # Get a summary of `train`
    summary(train)
    ##      npreg            glu              bp              skin      
    ##  Min.   : 0.00   Min.   : 56.0   Min.   : 38.00   Min.   : 7.00  
    ##  1st Qu.: 1.00   1st Qu.:100.0   1st Qu.: 64.00   1st Qu.:20.75  
    ##  Median : 2.00   Median :120.5   Median : 70.00   Median :29.00  
    ##  Mean   : 3.57   Mean   :124.0   Mean   : 71.26   Mean   :29.21  
    ##  3rd Qu.: 6.00   3rd Qu.:144.0   3rd Qu.: 78.00   3rd Qu.:36.00  
    ##  Max.   :14.00   Max.   :199.0   Max.   :110.00   Max.   :99.00  
    ##       bmi             ped              age         type    
    ##  Min.   :18.20   Min.   :0.0850   Min.   :21.00   No :132  
    ##  1st Qu.:27.57   1st Qu.:0.2535   1st Qu.:23.00   Yes: 68  
    ##  Median :32.80   Median :0.3725   Median :28.00            
    ##  Mean   :32.31   Mean   :0.4608   Mean   :32.11            
    ##  3rd Qu.:36.50   3rd Qu.:0.6160   3rd Qu.:39.25            
    ##  Max.   :47.90   Max.   :2.2880   Max.   :63.00

提示:如果想获取关于该数据集变量的更多信息,可像这样使用 help() 函数:

 help(Pima.tr)

运行上述命令后,您会得出 type 列表示糖尿病。

在分类问题中,SuperLearner 还要求对响应变量进行编码。由于您在解决二项分类问题,您将把 type 变量的因子编码为 0-1:

     y <- as.numeric(train[,8])-1
    ytest <- as.numeric(test[,8])-1

由于 type 列是因子,R 会将其编码为 1 和 2,但这并非您想要的:理想情况下,类型应编码为 0 和 1,分别对应 "No" 和 "Yes"。在上述代码中,您对整列减去 1 来得到 0-1 编码。R 也会按照因子顺序进行编码。

该包还要求将预测变量(X)和响应(Y)放在各自的数据结构中。您已在上文拆出了 Y,现在需要拆出 X。同时也拆分测试集:

     x <- data.frame(train[,1:7])
    xtest <- data.frame(test[,1:7])

注意,有些算法不仅需要数据框,还需要以数据框保存的模型矩阵。nnet 算法就是一个例子。在回归问题中,几乎总是会使用模型矩阵来为 SuperLearner 存储数据。模型矩阵的作用是将因子变量拆分为各自的列,并将其从文本值重编码为 0-1 值。它不会影响数值列。模型矩阵会增加算法需要处理的列数,因此可能增加计算时间。对于像本例这样的小数据集,影响很小,但更大的数据集可能会受到较大影响。结论是:在拟合模型前,先决定您要尝试哪些算法。在这个简单示例中,您将直接使用已有的数据框结构。

使用 SuperLearner 训练您的第一个集成模型

要开始创建第一个模型,您可以用以下命令预览包中可用的模型:

     listWrappers()
    ## All prediction algorithm wrappers in SuperLearner:

    ##  [1] "SL.bartMachine"      "SL.bayesglm"         "SL.biglasso"        
    ##  [4] "SL.caret"            "SL.caret.rpart"      "SL.cforest"         
    ##  [7] "SL.dbarts"           "SL.earth"            "SL.extraTrees"      
    ## [10] "SL.gam"              "SL.gbm"              "SL.glm"             
    ## [13] "SL.glm.interaction"  "SL.glmnet"           "SL.ipredbagg"       
    ## [16] "SL.kernelKnn"        "SL.knn"              "SL.ksvm"            
    ## [19] "SL.lda"              "SL.leekasso"         "SL.lm"              
    ## [22] "SL.loess"            "SL.logreg"           "SL.mean"            
    ## [25] "SL.nnet"             "SL.nnls"             "SL.polymars"        
    ## [28] "SL.qda"              "SL.randomForest"     "SL.ranger"          
    ## [31] "SL.ridge"            "SL.rpart"            "SL.rpartPrune"      
    ## [34] "SL.speedglm"         "SL.speedlm"          "SL.step"            
    ## [37] "SL.step.forward"     "SL.step.interaction" "SL.stepAIC"         
    ## [40] "SL.svm"              "SL.template"         "SL.xgboost"

    ## 
    ## All screening algorithm wrappers in SuperLearner:

    ## [1] "All"
    ## [1] "screen.corP"           "screen.corRank"        "screen.glmnet"        
    ## [4] "screen.randomForest"   "screen.SIS"            "screen.template"      
    ## [7] "screen.ttest"          "write.screen.template"

您会注意到有预测算法封装器和筛选算法封装器。其中包含了一些可用于分类、回归或两者皆可的流行库。筛选算法由 SuperLearner 用于自动变量选择。

当您要使用上述列表中的某个算法时,需要在环境中安装对应的包。这是因为 SuperLearner 实际会调用这些包并在使用该方法时拟合模型。这也意味着,例如如果您从不使用 SL.caret 方法,就不需要安装 caret 包。

拟合模型很简单,但我们将用单模型示例一步步走过。

您将拟合 Ranger 算法,它是著名随机森林的更快实现。

回顾:随机森林是一种强大的方法,本质上是对决策树的集成。决策树通过观察数据并在模型中的各变量之间计算概率划分,从而为您的预测提供路径。决策树容易对数据过拟合,也就是对新数据泛化较差。随机森林通过基于多次数据样本生长多棵决策树,并对这些预测取平均来解决该问题。它还会在每个样本中仅选择特征子集,这也是它区别于树的袋装法之处。这样构建出的模型不会对数据过拟合。是不是很酷?

在本例中,您可能需要先用 install.packages() 安装 ranger 包,才能开始拟合模型。

完成后,您可以在 SuperLearner() 函数中使用 SL.ranger。

由于随机森林(以及 Ranger)在算法中包含随机采样,多次拟合将不会得到相同结果。因此在本练习中,您将设置随机种子,以便复现实验并在同一随机基线下比较多个模型。R 使用 set.seed() 设置随机种子。种子可以是任意数字,这里使用 150。

    set.seed(150)
    single.model <- SuperLearner(y,
                                 x,
                                 family=binomial(),
                                 SL.library=list("SL.ranger"))

SuperLearner 需要 Y(目标/响应变量)、X(预测变量)、family(可为高斯或二项),以及以列表形式给出的库。在此即 SL.ranger。

还记得之前关于二项分布的讨论吗?现在您就明白了:若使用高斯族,您的 0-1 范围预测将不合适。

接着,简单打印模型将给出系数(算法在模型中的权重)和风险(算法产生的误差)。在幕后,包会拟合集成中使用的每个算法以产生风险指标。

     single.model
    ## 
    ## Call:  
    ## SuperLearner(Y = y, X = x, family = binomial(), SL.library = list("SL.ranger")) 
    ## 
    ## 
    ## 
    ##                    Risk Coef
    ## SL.ranger_All 0.1759541    1

此处风险小于 0.20。当然,这需要通过外部交叉验证和测试集进一步检验,但这是个不错的开始。SuperLearner 的妙处在于它尝试通过交叉验证自动构建集成。当然,如果只有一个模型,它就会获得集成的全部权重。

单模型不错,但不借助 SuperLearner 也能做到。那如何拟合集成模型呢?

在 R 中训练集成:核支持向量机、贝叶斯 GLM 与袋装法

使用 SuperLearner 进行集成就是选择要用的算法这么简单。本例中,我们添加来自 kernlab 包的核支持向量机(KSVM)、来自 arm 包的贝叶斯广义线性模型(GLM),以及来自 ipred 包的袋装法。

但 KSVM 和贝叶斯 GLM 是什么?

  • KSVM 使用所谓的“核技巧”来计算点与点之间的距离。相比在特征空间中绘图并计算坐标,核方法计算点之间的内积,从而更快。随后,支持向量机用于在分类中学习点之间的非线性边界。支持向量机尝试在常常非线性的机器学习问题中为两类创建一条“间隔”。然后根据新点在空间中的位置,将其分类到间隔两侧之一。

  • 贝叶斯 GLM 模型在这里可以看作是逻辑回归的一种实现,至少在您处理 0-1 分类时如此。贝叶斯 GLM 与 KSVM 的不同在于它使用扩展的回归算法在每一步更新系数。袋装法与上述随机森林相似,但不对子特征进行抽样。这意味着您将从随机样本中生长多棵决策树,并将它们的预测取平均来得到最终预测。

现在,让我们拟合第一个集成!

提示:别忘了先安装这些包!此外,您可能还会被提示安装其他依赖包。

     # Set the seed
    set.seed(150)

    # Fit the ensemble model
    model <- SuperLearner(y,
                          x,
                          family=binomial(),
                          SL.library=list("SL.ranger",
                                          "SL.ksvm",
                                          "SL.ipredbagg",
                                          "SL.bayesglm"))

    # Return the model
    model
    ## 
    ## Call:  
    ## SuperLearner(Y = y, X = x, family = binomial(), SL.library = list("SL.ranger",  
    ##     "SL.ksvm", "SL.ipredbagg", "SL.bayesglm")) 
    ## 
    ## 
    ##                       Risk     Coef
    ## SL.ranger_All    0.1756230 0.000000
    ## SL.ksvm_All      0.1838340 0.000000
    ## SL.ipredbagg_All 0.1664828 0.524182
    ## SL.bayesglm_All  0.1677593 0.475818

加入这些算法后模型得到了改进,格局也随之改变。Ranger 和 KVSM 的系数为 0,意味着它们不再被加权到集成中。贝叶斯 GLM 和袋装法构成了模型权重的其余部分。您会注意到 SuperLearner 在为您计算风险并决定能降低误差的最优模型组合。

要理解每个模型对整体模型的具体贡献及其变异性,您可以使用 SuperLearner 的内部交叉验证函数 CV.SuperLearner()。可用 V 参数设置折数,此处设为 5:

     # Set the seed
    set.seed(150)

    # Get V-fold cross-validated risk estimate
    cv.model <- CV.SuperLearner(y,
                                x,
                                V=5,
                                SL.library=list("SL.ranger",
                                                "SL.ksvm",
                                                "SL.ipredbagg",
                                                "SL.bayesglm"))

    # Print out the summary statistics
    summary(cv.model)
    ## 
    ## Call:  
    ## CV.SuperLearner(Y = y, X = x, V = 5, SL.library = list("SL.ranger",  
    ##     "SL.ksvm", "SL.ipredbagg", "SL.bayesglm")) 
    ## 
    ## Risk is based on: Mean Squared Error
    ## 
    ## All risk estimates are based on V =  5 
    ## 
    ##         Algorithm     Ave       se     Min     Max
    ##     Super Learner 0.17277 0.014801 0.16250 0.19557
    ##       Discrete SL 0.17964 0.014761 0.16363 0.19244
    ##     SL.ranger_All 0.17866 0.015004 0.14811 0.20518
    ##       SL.ksvm_All 0.19382 0.020301 0.15685 0.26215
    ##  SL.ipredbagg_All 0.17791 0.015858 0.15831 0.19244
    ##   SL.bayesglm_All 0.16628 0.014318 0.15322 0.18022

交叉验证的摘要显示了模型的平均风险、模型的变异性以及风险的范围。

绘图还能直观展示所用模型及其变异性:

     plot(cv.model)

在 R 中的集成学习

很容易看出,贝叶斯 GLM 的平均表现最好,而 KSVM 表现最差,且相较其他模型具有更大的变异性。SuperLearner 的妙处在于:若某个模型拟合不佳或贡献不大,它的权重会被设为 0!除非您计划今后重新训练模型,否则无需移除并重训。只要记住,合理的模型训练应包括对整个模型进行交叉验证。在真实场景中,这就是在预测新数据前评估模型风险的方式。

使用 SuperLearner 进行预测

使用专用命令 predict.SuperLearner(),您可以轻松对新数据集进行预测。这意味着您不能使用普通的 predict() 函数!

     predictions <- predict.SuperLearner(model, newdata=xtest)

predict.SuperLearner() 接受一个模型参数(SuperLearner 拟合对象)以及待预测的新数据。预测结果首先返回整体集成的预测:

     head(predictions$pred)
    ##            [,1]
    ## [1,] 0.79322181
    ## [2,] 0.11895658
    ## [3,] 0.04612200
    ## [4,] 0.05928159
    ## [5,] 0.68824522
    ## [6,] 0.54373451

它还会返回各基学习器的单独预测:

     head(predictions$library.predict)
    ##      SL.ranger_All SL.ksvm_All SL.ipredbagg_All SL.bayesglm_All
    ## [1,]         0.796   0.8089502       0.82086658      0.76276712
    ## [2,]         0.129   0.1580203       0.18586049      0.04525230
    ## [3,]         0.016   0.1579566       0.06255427      0.02801949
    ## [4,]         0.102   0.1885473       0.07238268      0.04484885
    ## [5,]         0.638   0.7108875       0.58791672      0.79877149
    ## [6,]         0.550   0.6898737       0.37488066      0.72975132

这可让您查看每个模型如何对每个观测进行分类,有助于调试模型或一次性拟合多个模型以决定后续使用哪一个。

您可能注意到返回的是概率形式的预测量。这意味着您需要一个阈值来判定分类为 1 还是 0。只有在二项分类情形下需要这样做,回归不需要。

通常应在训练时通过交叉验证来确定阈值,但为简化起见,这里使用 0.50。由于这是一个简单的二项问题,您将使用 dplyr 的 ifelse() 将概率重编码:

     # Load the package
    library(dplyr)

    # Recode probabilities
    conv.preds <- ifelse(predictions$pred>=0.5,1,0)

现在,您可以用 caret 构建混淆矩阵来查看结果:

     # Load in `caret`
    library(caret)

    # Create the confusion matrix
    cm <- confusionMatrix(conv.preds, ytest)

    # Return the confusion matrix
    cm
 
    ## Confusion Matrix and Statistics
    ## 
    ##           Reference
    ## Prediction   0   1
    ##          0 199  45
    ##          1  24  64
    ##                                           
    ##                Accuracy : 0.7922          
    ##                  95% CI : (0.7445, 0.8345)
    ##     No Information Rate : 0.6717          
    ##     P-Value [Acc > NIR] : 8.166e-07       
    ##                                           
    ##                   Kappa : 0.5044          
    ##  Mcnemar's Test P-Value : 0.01605         
    ##                                           
    ##             Sensitivity : 0.8924          
    ##             Specificity : 0.5872          
    ##          Pos Pred Value : 0.8156          
    ##          Neg Pred Value : 0.7273          
    ##              Prevalence : 0.6717          
    ##          Detection Rate : 0.5994          
    ##    Detection Prevalence : 0.7349          
    ##       Balanced Accuracy : 0.7398          
    ##                                           
    ##        'Positive' Class : 0               
    ##

在该数据集上,您的准确率约为 0.7921687,这个表现不错。虽然许多算法可以得到更高分数,但对于一个快速集成来说已经很好了。通过在训练中使用交叉验证并尝试不同模型,您很容易进一步提升分数。

超参数调优

虽然当前表现并不差,但您可以通过调优集成中某些模型的超参数来进一步提升性能。Ranger 在您的模型中权重不高,可能是因为需要更多的树并调优 mtry 参数。您也许还能通过将 nbagg 参数从默认的 25 提升到 250 来改进袋装法。

有两种方法可以做到:要么定义一个函数来调用学习器并修改参数,要么使用 create.Learner() 函数。接下来您将了解这些选项。

定义函数

第一种方法借助 function()。您可以定义一个函数来调用学习器并修改参数。函数调用使用省略号 ... 传递附加参数。三个点允许对公式进行修改,而无需在函数中显式指定修改内容。这意味着如果要更改 10 个参数,无需在函数中创建 10 个对象与之对应。这是一种通用的函数写法。

     SL.ranger.tune <- function(...){
      SL.ranger(..., num.trees=1000, mtry=2)
    }

    SL.ipredbagg.tune <- function(...){
      SL.ipredbagg(..., nbagg=250)
    }

SL.ranger.tune 是您修改后的 ranger 方法名,SL.ipredbagg.tune 是您修改后的 ipredbagg 方法名。现在已经创建了新的学习器函数,您可以将它们传递给交叉验证公式,看看性能是否提升。

注意,您会在算法列表中保留原始的 SL.ranger 和 SL.ipredbagg,以比较调优版本是否带来提升。

     # Set the seed
    set.seed(150)

    # Tune the model
    cv.model.tune <- CV.SuperLearner(y,
                                     x,
                                     V=5,
                                     SL.library=list("SL.ranger",
                                                     "SL.ksvm",
                                                     "SL.ipredbagg","SL.bayesglm", 
                                                     "SL.ranger.tune",
                                                     "SL.ipredbagg.tune"))

    # Get summary statistics
    summary(cv.model.tune)
    ## 
    ## Call:  
    ## CV.SuperLearner(Y = y, X = x, V = 5, SL.library = list("SL.ranger",  
    ##     "SL.ksvm", "SL.ipredbagg", "SL.bayesglm", "SL.ranger.tune", "SL.ipredbagg.tune")) 
    ## 
    ## 
    ## Risk is based on: Mean Squared Error
    ## 
    ## All risk estimates are based on V =  5 
    ## 
    ##              Algorithm     Ave       se     Min     Max
    ##          Super Learner 0.17272 0.014969 0.15849 0.19844
    ##            Discrete SL 0.17250 0.014989 0.15645 0.18430
    ##          SL.ranger_All 0.17897 0.015084 0.15388 0.19920
    ##            SL.ksvm_All 0.19573 0.020278 0.16095 0.26304
    ##       SL.ipredbagg_All 0.17667 0.015629 0.16473 0.18898
    ##        SL.bayesglm_All 0.16628 0.014318 0.15322 0.18022
    ##     SL.ranger.tune_All 0.17637 0.014882 0.15218 0.19793
    ##  SL.ipredbagg.tune_All 0.17813 0.015869 0.16455 0.19260
    # Plot the tuned model
    plot(cv.model.tune)

R 集成

从图中可以看到,随着在 SL.ipredbagg.tune 中增大 nbagg 参数,ipredbagg 似乎有所提升。Ranger 在调参后似乎变差,但我们先保留它,看看 SuperLearner 是否认为它仍有用。

再次强调,妙处在于如果某算法无关紧要,SuperLearner 会直接将其权重设为 0。请记住,最好的集成并非由单个表现最好的算法组成,而是由彼此互补、共同完成分类任务的算法组成。

让我们用调好的参数拟合新模型,看看权重如何:

     # Set the seed
    set.seed(150)

    # Create the tuned model
    model.tune <- SuperLearner(y,
                              x,
                              SL.library=list("SL.ranger",
                                              "SL.ksvm",
                                              "SL.ipredbagg",
                                              "SL.bayesglm",
                                              "SL.ranger.tune",
                                              "SL.ipredbagg.tune"))

    # Return the tuned model
    model.tune
    ## 
    ## Call:  
    ## SuperLearner(Y = y, X = x, SL.library = list("SL.ranger", "SL.ksvm",  
    ##     "SL.ipredbagg", "SL.bayesglm", "SL.ranger.tune", "SL.ipredbagg.tune")) 
    ## 
    ## 
    ## 
    ##                            Risk      Coef
    ## SL.ranger_All         0.1748247 0.0000000
    ## SL.ksvm_All           0.1974033 0.0000000
    ## SL.ipredbagg_All      0.1745503 0.0000000
    ## SL.bayesglm_All       0.1634855 0.7162423
    ## SL.ranger.tune_All    0.1725514 0.0000000
    ## SL.ipredbagg.tune_All 0.1711161 0.2837577

现在,SL.bayesglm 和 SL.ipredbagg.tune 成为仅有的两个带权算法。用测试集进行预测得到如下结果:

     # Gather predictions for the tuned model
    predictions.tune <- predict.SuperLearner(model.tune, newdata=xtest)

    # Recode predictions
    conv.preds.tune <- ifelse(predictions.tune$pred>=0.5,1,0)

    # Return the confusion matrix
    confusionMatrix(conv.preds.tune,ytest)
    ## Confusion Matrix and Statistics
    ## 
    ##           Reference
    ## Prediction   0   1
    ##          0 200  43
    ##          1  23  66
    ##                                           
    ##                Accuracy : 0.8012          
    ##                  95% CI : (0.7542, 0.8428)
    ##     No Information Rate : 0.6717          
    ##     P-Value [Acc > NIR] : 1.116e-07       
    ##                                           
    ##                   Kappa : 0.5271          
    ##  Mcnemar's Test P-Value : 0.01935         
    ##                                           
    ##             Sensitivity : 0.8969          
    ##             Specificity : 0.6055          
    ##          Pos Pred Value : 0.8230          
    ##          Neg Pred Value : 0.7416          
    ##              Prevalence : 0.6717          
    ##          Detection Rate : 0.6024          
    ##    Detection Prevalence : 0.7319          
    ##       Balanced Accuracy : 0.7512          
    ##                                           
    ##        'Positive' Class : 0               
    ##

这在测试集上带来了小幅提升,并展示了使用 SuperLearner 进行模型调优的思路。

create.Learner()

第二种调参方法是使用 create.Learner() 函数。它允许您定制现有的 SuperLearner:

     learner <- create.Learner("SL.ranger", params=list(num.trees=1000, mtry=2))
    learner2 <- create.Learner("SL.ipredbagg", params=list(nbagg=250))

create.Learner() 的第一个参数是学习器名称字符串。然后传递一个参数列表以修改。这会创建一个对象:

     learner
    ## $grid
    ## NULL
    ## 
    ## $names
    ## [1] "SL.ranger_1"
    ## 
    ## $base_learner
    ## [1] "SL.ranger"
    ## 
    ## $params
    ## $params$num.trees
    ## [1] 1000
    ## 
    ## $params$mtry
    ## [1] 2

现在,将该学习器传给 SuperLearner 时,使用该对象中的 names 成员:

     # Set the seed
    set.seed(150)

    # Create a second tuned model
    cv.model.tune2 <- CV.SuperLearner(y,
                                      x,
                                      V=5,
                                      SL.library=list("SL.ranger",
                                                      "SL.ksvm",
                                                      "SL.ipredbagg",
                                                      "SL.bayesglm", 
                                                      learner$names,
                                                      learner2$names))

    # Get summary statistics
    summary(cv.model.tune2)
    ## 
    ## Call:  
    ## CV.SuperLearner(Y = y, X = x, V = 5, SL.library = list("SL.ranger",  
    ##     "SL.ksvm", "SL.ipredbagg", "SL.bayesglm", learner$names, learner2$names)) 
    ## 
    ## 
    ## Risk is based on: Mean Squared Error
    ## 
    ## All risk estimates are based on V =  5 
    ## 
    ##           Algorithm     Ave       se     Min     Max
    ##       Super Learner 0.17272 0.014969 0.15849 0.19844
    ##         Discrete SL 0.17250 0.014989 0.15645 0.18430
    ##       SL.ranger_All 0.17897 0.015084 0.15388 0.19920
    ##         SL.ksvm_All 0.19573 0.020278 0.16095 0.26304
    ##    SL.ipredbagg_All 0.17667 0.015629 0.16473 0.18898
    ##     SL.bayesglm_All 0.16628 0.014318 0.15322 0.18022
    ##     SL.ranger_1_All 0.17637 0.014882 0.15218 0.19793
    ##  SL.ipredbagg_1_All 0.17813 0.015869 0.16455 0.19260
    # Plot `cv.model.tune2`
    plot(cv.model.tune2)

R 的集成机器学习

最终结果与第一种方法相同。使用哪种方式取决于您的偏好。

更多 R 中的集成模型与机器学习

哇,您已经覆盖了很多内容!现在,您应当已经熟悉 SuperLearner,并成功用它训练了第一个集成。这个包让快速添加模型变得非常容易。需要注意的是,方法和数据形式上有一些细微之处。不过,如果拿不准,将模型矩阵以数据框保存几乎总能奏效。

回顾一下,您安装并加载了 SuperLearner,整理了数据集,拟合了单个模型,训练了第一个集成,用集成进行了预测,并调优了一些超参数!

下一步可以尝试该包的一些高级主题,如并行化、特征选择与筛选、使用模型矩阵、编写您自己的 SuperLearner,以及集成交叉验证。

查看 DataCamp 的R 机器学习入门教程。

主题