5模型训练和调参(The caret package)

5. 模型训练和调参

内容:

  • Model Training and Parameter Tuning
  • An Example
  • Basic Parameter Tuning
  • Notes on Reproducibility
  • Customizing the Tuning Process
  • Pre-Processing Options
  • Alternate Tuning Grids
  • Plotting the Resampling Profile
  • The trainControl Function
  • Alternate Performance Metrics
  • Choosing the Final Model
  • Extracting Predictions and Class Probabilities
  • Exploring and Comparing Resampling Distributions
  • Within-Model
  • Between-Models
  • Fitting Models Without Parameter Tuning


5.1 Model Training and Parameter Tuning

caret包有很多函数试图精简构建模型和评估模型的过程。 
train 函数能用于: 
* 评估,应用抽样,模型调参的影响 
* 通过参数选择最优模型 
* 从训练集中评估模型表现 
首先,需要选择一个具体地模型。现在,有233个可以使用;详情请看train Model List 或 train Model By Tag,在这些介绍中,有一个可被优化的参数列表。用户也可以自定义模型。 
第一步就是调整模型(算法中的第一行就是选择一系列要估计的参数。例如,如果要拟合一个偏最小二乘模型,需要设定PLS估计的参数。) 





5模型训练和调参(The caret package)_第1张图片
一旦模型和要调整的参数值被定义,重抽样的类型也就被设定了。现在,在train中可以使用k折交叉验证(一次或重复的),留一交叉验证和自助法等抽样方法。重抽样过后,这个过程将会指导用户选择哪个参数。默认地,函数自动选择具有拥有最佳值的参数,尽管可以使用不同的算法。

5.2 An Example

mlbench包中有一个Sonar数据集,这里,我们载入数据集:

library(mlbench)
data(Sonar)
str(Sonar[, 1:10])

   
     
     
     
     

函数createDataPartition能创建一个分层的随机样本进入训练集和测试集:

library(caret)
set.seed(998)
inTraining <- createDataPartition(Sonar$Class, p = .75, list = FALSE)
training <- Sonar[ inTraining,]
testing  <- Sonar[-inTraining,]
   
     
     
     
     
  • 1
  • 2
  • 3
  • 4
  • 5

我们将会使用这些数据来说明这些函数功能。


5.3 Basic Parameter Tuning

默认为,简单自助抽样用于上图算法的第3行。像重复k折交叉验证和留一法也可以使用。函数trainControl用来设动抽样类型:

fitControl <- trainControl(## 10-fold CV
                           method = "repeatedcv",
                           number = 10,
                           ## repeated ten times
                           repeats = 10)
   
     
     
     
     
  • 1
  • 2
  • 3
  • 4
  • 5

更多关于trainControl的信息可以看下面章节。


train的前两个参数是预测变量和结果数据对象。第三个参数method设定模型类型(看train Model List 或 trian Model By Tag)。为了说明问题,我们会通过gbm包拟合一个boot tree模型。用重复交叉验证来拟合模型的基础语法为:

set.seed(825)
gbmFit1 <- train(Class ~ ., data = training, 
                 method = "gbm", 
                 trControl = fitControl,
                 ## This last option is actually one
                 ## for gbm() that passes through
                 verbose = FALSE)
gbmFit1

   
     
     
     
     
对于一个GBM模型,有三个主要的参数: 
* 迭代次数, 例如,树(在gbm函数中叫做n.trees) 
* 树的复杂度,称作 interaction.depth  
* 学习率:算法适应的有多快,叫做 shrinkage  
* 训练样本的最小数目( n.minobsinnode ) 
检测模型的默认值在前两列给出( shrinkage n.minobsinnode 没有给出是因为拥有这些参数的候选模型使用同样的值)。标有 accuracy 的这一列是通过交叉验证计算出的准确率。准确率的标准差从交叉验证结果中计算出。 Kappa 这一列是通过重抽样结果计算的Cohen Kappa统计量(非加权)。 train 函数用于具体的模型(见train Model List 和 train Mode By Tag)。对于这些模型, train 函数创建一个调整参数组。默认的,如果p是调整参数的个数,那么,参数组的大小为 3p 。做为另一个例子,正则判别分析(RDA)模型有两个参数( gamma lambda ),两个参数数值都在0和1之间。默认的训练参数组将会在二维空间中产生9种组合。 
在为 train 函数设定模型时有一些要点。在下一节将介绍 train  的额外其他功能。


5.4 Notes on Reproducibility

很多模型在参数估计阶段应用随机数,重抽样切片也使用随机数,有两种主要的方法可以控制随机子以确保结果可重复。 
* 有两种方法确保在调用train函数的时候有相同的重抽样本。第一种是在调用train之前使用set.seed函数。随机数生成重抽样信息。另外的,如果你愿意使用特定的数据分割,可以使用trainControl函数的index,这将会在下面讲到。 
* 当使用重抽样的模型创建后,自己自也已经创建了。在调用train函数之前设定随机子能保证使用了相同 的随机数,当使用并行处理时这并不是一个问题。为了设定模型拟合随机子,trainControl需要调用另外一个参数seeds。这个参数是使用一个整数向量列表作为随机子。trainControl的帮助页面描述了这个选项的格式。

随机数怎样使用高度依赖包的作者。很少有目标模型没有控制生成随机数的,特别是在C代码中进行计算的。

5.5 Customizing the Tuning Process

有一些方法可以自定义参数选取和构建模型过程。

5.5.1 Pre-Processing Options

就像先前所提到的,train函数在模型拟合之前可以使用多种方法进行数据预处理。preProcess函数可以用来中心化和标准化,插值,空间符号变换和通过PCA或独立成分分析进行特征提取。 
要怎么进行预处理,train函数有一个参数叫preProcess,这个参数会把方法传递到preProcess函数中,另外,preProcess也可以通过trainControl传递。 
这些处理步骤将会应用于任何的预测过程,像predict.train, extractPredictionextractProbs。预处理不会应用于直接使用object$finalModel这种对象的预测。 
对于插值,有三种主要的实施方法:

  • k最近邻处理带有缺失值的样本,并能在训练集中找到k个最近的样本。这k个训练集的值作为原始数据集的替代。当计算到训练集样本的距离的时候,用于计算的预测变量要求没有缺失值。
  • 另一种方法是使用训练集对每一个预测变量拟合一个bag树。这是一个具有正常准确率的模型,并能处理缺失值。当一个预测变量需要插值的时候,其他预测变量将会通过bag树返回值,并且通过他们预测的值作为一个新值,但模型可能有很大的计算开销。
  • 预测变量的中位数也可以用来估计缺失值。
如果在训练集中有缺失值,PCA和ICA只用其中的完整的样本。


5.5.2 Alternate Tuning Grids

调参网格可以由用户设定。参数tuneGrid可以传入一个数据框,列包含设定的参数。列名需要和拟合模型的参数名一致。对于前面提到的RDA的例子,参数名为gamma,lambda.train函数将会对每一行的参数值进行调整模型。 
对于boost树模型,我们需要固定学习率,而去调整n.trees的参数:



gbmGrid <- expand.grid(interaction.depth = c(1,5,9), n.trees = (1:30)*50, shrinkage = 0.1,n.minobsinnode =20)

nrow(gbmGrid)

set.seed(825)

gbmFit2 <- train(Class ~ ., data = training, method ="gbm", trControl = fitControl, verbose = FALSE,

## Now specify the exact models

## to evaluate:

tuneGrid = gbmGrid)


gbmFit2


如果训练集中有缺失值,PCA和ICA模型只会用完整的样本。 
另一个选项是应用一个随机的参数组合,例如“随机搜索”,这个函数将在下面介绍。 
要应用随机搜索,那就在调用trainControl的时候使用选项search = "random。这种情况下,tuneLength参数定义了要估计的参数组合的长度。

5.5.3 Plotting the Resampling Profile

plot函数用于检验模型性能和调参之间的关系。例如,函数的调用展示了第一次拟合的结果:

trellis.par.set(caretTheme())
plot(gbmFit2)
5模型训练和调参(The caret package)_第2张图片


可以使用metric选项度量性能:

trellis.par.set(caretTheme())
plot(gbmFit2,metric = "Kappa")

也可以使用ggplot方法:

ggplot(gbmFit2)

    
      
      
      
      
也有其他作图函数展现抽样估计的更多细节。详情请看xyplot.train。 
在这些图中可能需要一种不同的调参方式。要改变最终结果而不重新开始整个操作过程,update.train函数可用来重新拟合最终模
型。可以看?update.train



5.5.4 ThetrainControlFunction

trainControl函数产生参数是要控制用可能的值去创建模型:

  • method:重抽样方法:"boot","cv","LOOCV","LGOCV","repeatedcv","timeslice","none""oob"。最后一个出代估计(oob)只能应用于随机森林,袋装树,bagged earth,bagged flexible discriminant analysis或条件树森林模型。这并不包括GBM模型(gbm包作者指出,依照袋装树的OOB模型估计来选择调参并不是一个好主意)。对于留一法交叉验证,重抽样的性能度量并不能得到保证。
  • number和repeatsnumber控制K折交叉验证的数目或者自助法和留组交叉验证的抽样迭代次数。假设method = "repeatedcv",number = 10和repeates = 3,3个分开的10折交叉验证作为重抽样的方案。

  • verboseIter:输出训练日志的逻辑变量。
  • returnData:逻辑变量,把数据保存到称作trainingData的一个节点。
  • p:应用于LGOCV方法:训练比例。
  • 对于method = "timeslice",trainControl拥有参数initialWindow,horizon和fixedWindow来控制交叉验证是怎样应用于时间序列数据的。
  • classProbs:逻辑变量,决定是否计算类别概率。
  • index和indexOut:每一次从抽样元素列表。每一个列表元素是用于迭代训练的样本行。当这些值没有设定时,train函数会产生它们。
  • summaryFunction:用于计算备用性能的函数。
  • selectionFunction:选择最佳参数的函数。
  • PCAthreshICAcomp和k:这些选项传递到preProcss函数中去。
  • returnResamp:包含一下值的字符串:"all","final","none"。它们设定有多少抽样性能度量被保存。
  • allowParallel:逻辑变量,是否允许train函数使用并行处理(如果可能的话)。 
    还有其它选项在这没有讨论。


5.5.5 Alternate Performance Metrics

用户可以改变决定最佳设置的度量。默认的,回归使用RMSE和 R2 ,而分类使用准确率和Kappa统计量。回归和分类分别使用准确率和Kappa统计量选择参数值。train函数的metric参数允许用户选择哪种最优准则。例如,对于不平衡类的问题,用metric = "Kappa"来提高最中模型性能。 
如果这些参数不理想,用户可以自定义性能度量。trainControl函数中有summaryFunction参数来设定计算性能的函数。这个函数应该有一下参数: 
data:数据框或矩阵的参考表,列包含观测值obs和预测结果pred。现在,类概率没法传递到这个函数中去。数据中是调参组合的预测值。如果trainControl函数中的classProbs参数设定为TRUE,在data中就会加入一列包含类概率的值。这些列名与类水平一样。另外,如果train函数中设定了weights,那么在数据集中就会再加一列weights的值。 
lev:是一个字符串,它有训练集中的输出因子水平。对于回归来说,NULL值会传递到这额函数。 
model:应用模型的字符串,(例如传递到train函数的参数method中去的值)。

函数的输出应该是一个没有空名的数值度量向量。默认为,train函数从预测类的及角度评估分类模型。另外,类概率也能用于性能测量。为了获得重抽样中预测的类概率,trainControl函数中的参数classProbs必须设定为TRUE。这会将概率值加入到每次抽样产生的预测中去。 
在最后一节展示出,自定义函数能用于计算性能的平均得分。另一个内置函数twoClassFunction将会计算敏感度,特异性和ROC曲线下的面积。




为了使用这个准则重新建立boost tree模型,我们可以使用下面代码观察参数和ROC曲线下面积的关系:

fitControl <- trainControl(method = "repeatedcv",
                           number = 10,
                           repeats = 10,
                           ## Estimate class probabilities
                           classProbs = TRUE,
                           ## Evaluate performance using 
                           ## the following function
                           summaryFunction = twoClassSummary)
set.seed(825)gbmFit3 <- train(Class ~ ., data = training,                        method = "gbm",  trControl = fitControl,  verbose = FALSE,  tuneGrid = gbmGrid,            ## Specify which metric to optimize           metric = "ROC")gbmFit3
在这个案例中,最优参数的ROC曲线下的平均面积是0.896。

5.6 Choosing the Final Model

另一个自定义参数的过程就是修正用来选择最佳参数的算法。默认的,train函数选择具有最大性能值的模型,也可以使用其他模型的方案。Breiman等人建议简单的基于树的模型使用单个标准差规则。在这个案例中,识别了具有最佳性能值的模型,应用重抽样方法,我们能估计性能的标准误。最终的模型就是使用但标准差的最简单的模型。当基于树的模型刚开始出现过拟合,后来越来越适应模型的时候,这是有意义的。 
train函数允许用户设定选取最终的的规则。参数selectionFunction用来提供能决定最终模型的函数。包中有三个函数:best选择最大或最小值,oneSE试图捕获Breiman等人的观点,tolerance选择具有一定最佳值忍耐度的最简单的模型。详情请看best。 
只要拥有以下参数,用户也能自定义函数:


  • x是一个数据框,包括调整参数和与他们相关联的性能度量。每一行对应一个不同参数的组合。
  • metric字符向量,指定那个性能度量应被优化(可以直接传递到train函数)。
  • maximize逻辑值,表明一个性能度量的更大的值是否更好(可以直接传递到train函数)。


函数应该输出一个整数值,表明x的哪一行被选择。 
作为一个例子,如果我们选择先前基于准确率的boost树模型,我们会选择:n.tree = 650,interaction.depth = 5, shrinkage = 0.1, n.minobsinnode = 20。然而,这张图中的刻度非常紧密,准确率在0.859至0.896之间。一个更简单的模型也可能有这样的准确率。 
忍耐函数可以使用 (xxbest)/xbest×100 来找出一个更简单的函数。例如,选择一个基于2%的性能损失的参数值。


whichTwoPct <- tolerance(gbmFit3$results, metric = "ROC",
tol = 2, maximize = TRUE)
cat("best model within 2 pct of best:\n")
## best model within 2 pct of best:
gbmFit3$results[whichTwoPct, 1 : 6 ]



这表明我们能得到一个更简单的模型,和具有最佳值的ROC面积0.896相比,这个模型的ROC面积为0.881. 
这些函数的主要问题是怎样对模型的复杂性排序。在一些案例中,这很简单(例如简单树模型,偏最小二乘),但是在这样的模型中,模型排序是主观的。例如,一个有100次迭代,树的深度为2的boost树模型比50次迭代,深度为8的boost树更复杂吗?依据顺序,包会做出一些选择。在boost树模型案例中,包认为增加迭代次数比增加树的深度计算更快,所以,模型是先按照迭代排序然后再按照树深度排序。查看更多例子请看best

5.7 Extracting Predictions and Class Probabilities

先前所提到的,train函数产生的对象包括finalModel里的最优模型。通过这些对象能够作出预测。在一些例子中,像plsgbm对象,额外的参数需要设定。trian的对象应用参数优化的结果对新样本进行预测。例如,如果用predict.gbm作出预测,用户将不得不直接设定树的个数(没有默认值)。对于二分类问题,函数预测值是一种概率的形式,所以额外的步骤是要把它转化为因子向量。predict.train会自动处理这些细节。 
在R中,有很少的标准语句来进行模型的预测。例如,为了获得类概率,很多predict方法会有一个参数type,用它来设定生成类概率或类别。不同的包使用不同的type值,像prob,posterior,response,probabilityraw。在另外一些案例中,可能使用另外一些语句。 
对于predict.train函数,type只取两个值classprob。例如:


predict(gbmFit3, newdata = head(testing))

predict(gbmFit3, newdata = head(testing), type = "prob")

5.8 Exploring and Comparing Resampling Distributions

5.8.1 Within-Model

对于一个特定的模型,有很多lattice函数探索参数调整和重抽样结果的关系:

  • xyplotstripplot用于画出重抽样统计量。
  • hisstogramdensityplot用于查看参数调整的分布。

例如,下图创建了一个密度函数: 

注意到,通过多个调整参数画出重抽样结果,如果你对这个感兴趣,那么 resamples="all" 应该放入控制选项中。

5.8.2 Between-Models

caret包包含一些函数,它可以通过重抽样分布把模型间的差别字符化。这些函数是基于Hothorn和Eugster等人的工作。 
首先,用SVM模型拟合Sonar数据,数据通过preProc参数进行中心化和标准化。注意到随机数要先于模型设置,并且是和boost树模型使用的随机数是一样的。这保证抽到相同的样本,这对于我们比较两个模型有帮助。

set .seed( 825 )
svmFit <- train(Class ~ ., data = training, method = "svmRadial",
trControl = fitControl, preProc = c("center","scale"),
tuneLength = 8, metric = "ROC")
svmFit
正则判别分析模型拟合数据:
set.seed(825)rdaFit <- train(Class ~ ., data = training,
method = "rda", trControl = fitControl,
tuneLength = 4, metric = "ROC")
rdaFit


给出这些模型,我们能做出判断谁的性能比较好吗?我们首先用resamples收集重抽样结果。

resamps <- resamples(list(GBM = gbmFit3,
                          SVM = svmFit,
                          RDA = rdaFit))
resamps
summary(resamps)

注意到,在这个例子中,选项resamples = "final"应该由用户自定义。 
有很多lattice作图方法用于重抽样分布的可视化:density plots,box-whiker plots, scatterplot matrices和scatterplots of summary statistics.例如:

trellis.par.set(theme1)
bwplot(resamps, layout = c(3, 1))
trellis.par.set(caretTheme())dotplot(resamps, metric = "ROC")
trellis .par .set (theme1)
xyplot(resamps, what = "BlandAltman")

splom(resamps)

也可以应用像densityplot.resamplesparallel.resamples的可视化。 
由于模型拟合相同的数据,所以比较模型的差异显得有意义。这样,我们减少可能存在的重抽样的相关性,计算差异,然后用t检验来检验模型是否有差异。

difValues <- diff(resamps)
difValues
trellis.par.set(theme1)bwplot(difValues, layout = c(3, 1))

trellis.par.set(caretTheme())dotplot(difValues)

5.9 Fitting Models Without Parameter Tuning

在模型参数值已知的例子中,train函数可以对整个训练集拟合模型而不用重抽样或调整参数。可以使用trainControlmethod = "none".例如:

fitControl <- trainControl( method = "none", classProbs = TRUE)
set.seed(825)
gbmFit4 <- train(Class ~ ., data = training,
method = "gbm", trControl = fitControl,
verbose = FALSE,
## Only a single model can be passed to the
##function when no resamplingis used:
tuneGrid = data.frame(interaction.depth = 4,
n.trees = 100, shrinkage = .1,
n.minobsinnode = 20),
metric = "ROC")
gbmFit4

注意到plot.train,resamples,confusionMatrix.train和其他一些函数不能和这个gbmFit4对象一起使用,但是predict.train可以:
predict(gbmFit4, newdata = head(testing))

predict(gbmFit4, newdata = head(testing), type = "prob")

你可能感兴趣的:(R)