梯度提升模型的变量重要性(以 50 天为间隔滚动)

Posted

技术标签:

【中文标题】梯度提升模型的变量重要性(以 50 天为间隔滚动)【英文标题】:Variable Importance (rolling in 50days interval) for Gradient Boosting Model 【发布时间】:2021-06-15 20:57:04 【问题描述】:

我有以下数据表dt.traindays的数量和函数varImportance,来得到一个线性模型的变量重要性:

library(data.table)
library(caret)
library(xgboost)
library(zoo)

days <- 50
set.seed(123)
dt.train <- data.table(date = seq(as.Date('2020-01-01'), by = '1 day', length.out = 366),
                       'DE' = rnorm(366, 30, 1), 'windDE' = rnorm(366, 10, 1),
                       'consumptionDE' = rnorm(366, 35, 1), 'nuclearDE' = rnorm(366, 8, 1), 
                       'solarDE' = rnorm(366, 1, 1), check.names = FALSE)

## Variable Importance Function: ##
## LINEAR MODEL: ##
varImportance <- function(data)
    ## Model fitting: ##
    xgbModel <- stats::lm(DE ~ .-1, data = data.table(data))
    varimp <- caret::varImp(xgbModel)
    importance <- t(varimp)


## Iterative Variable Importance for Linear Model: ##
dt.importance <- as.data.frame(zoo::rollapply(dt.train[, !"date"], 
                                              FUN = varImportance,
                                              width = days,
                                              by.column = FALSE,
                                              align = 'left')
)

## Adding date-column again: ##
dt.importance <- cbind(dt.train[1:nrow(dt.importance), .(date)], dt.importance)

这里一切正常,但我需要为梯度提升机器学习模型做同样的事情。我已经尝试过以相同的方式进行操作,其中模型拟合的准备工作在 varImportance 函数中:

  ## Variable Importance function: ##
  ## GRADIENT BOOSTING: ##
  varImportance <- function(data)
    
    ## Create response vector and predictor matrix: ##
    v.trainY <- data$DE
    m.trainData <- as.matrix(data[, c("date", "DE") := list(NULL, NULL)])

    ## Hyper parameter tuning and grid search: ##
    xgb_trcontrol <- caret::trainControl(method = "cv",
                                         number = 3,
                                         allowParallel = TRUE,
                                         verboseIter = TRUE,
                                         returnData = FALSE
    ) 
    
    xgbgrid <- base::expand.grid(nrounds = c(150), # 15000
                                 max_depth = c(2),
                                 eta = c(0.01),
                                 gamma = c(1),
                                 colsample_bytree = c(1),
                                 min_child_weight = c(2),
                                 subsample = c(0.6)
    )

    ## Model fitting: ##
    xgbModel <- caret::train(m.trainData, 
                             v.trainY,
                             trControl = xgb_trcontrol,
                             tuneGrid = xgbgrid,
                             method = "xgbTree"
    )
    
    varimp <- caret::varImp(xgbModel, scale = FALSE)
    importance <- t(varimp$importance)
    
  
## Iterative Variable Importance for Gradient Boosting: ##
dt.importance <- as.data.frame(zoo::rollapply(dt.train, 
                                              FUN = varImportance,
                                              width = days,
                                              by.column = FALSE,
                                              align = 'left')
)

## Adding date-column again: ##
dt.importance <- cbind(dt.train[1:nrow(dt.importance), .(date)], dt.importance)

不幸的是,这不能每 50 天迭代一次(抛出错误:$ operator is invalid for atomic vectors)。 varImportance 函数中的 varImp() 在运行一次时适用于梯度提升模型。

编辑 1:

您的回答使用 Gradient Boosting 引发以下错误:

编辑 2:

当我评论 trControl = xgb_trcontrol 时,我收到以下错误:

【问题讨论】:

如果我理解正确的话,第一个计算应该是varImportance(dt.train[1:days])。但是,这会返回错误。我错过了什么吗? 第一个计算应该来自1: days,第二个来自2: days,第三个来自3: days,以此类推。这已经适用于线性模型,您可以尝试一下,然后应该清楚它的含义。我想对梯度提升做同样的事情,并且我已经尝试过了(如您在上面看到的),但是使用我的版本会引发错误。也许有人知道另一个版本以便它可以工作或如何解决这个问题? 感谢您的反馈。 “不”迭代地工作“可能会令人困惑,因为第一次迭代根本不起作用。第一步是在尝试迭代之前让 xgbMpdel 与 varImp 一起工作。 如果我为整个数据集拟合 xgbModel,然后我用varimp &lt;- caret::varImp(xgbModel, scale = FALSE) 计算拟合模型的变量重要性,这很好。所以,varImp 工作正常,当它不与函数 varImportance 迭代使用时。 在我的系统上,varImportance(dt.train) 返回Non-tree model detected! This function can only be used with tree models. 【参考方案1】:

在使用一些 data.table 函数时,您需要将输入转换回 data.table。 rollapply 将输入作为矩阵发送。您应该注意,您的第一列是日期,当 rollapply 将数据子集转换为矩阵时,所有内容都将转换为字符类。

由于您不在函数中使用日期,因此最好在 rollapply 函数中发送数据之前删除此列。但是,如果要发送完整数据,则需要将所有内容从字符转换回数字。在下面的代码中,我只是在输入中删除日期列。

这是工作代码 -

library(data.table)
library(caret)
library(xgboost)
library(zoo)

days <- 50
set.seed(123)
dt.train <- data.table(date = seq(as.Date('2020-01-01'), by = '1 day', length.out = 366),
                       'DE' = rnorm(366, 30, 1), 'windDE' = rnorm(366, 10, 1),
                       'consumptionDE' = rnorm(366, 35, 1), 'nuclearDE' = rnorm(366, 8, 1), 
                       'solarDE' = rnorm(366, 1, 1), check.names = FALSE)

## GRADIENT BOOSTING: ##
varImportance <- function(data)
  
  data = data.table(data.frame(data))
  ## Create response vector and predictor matrix: ##
  v.trainY <- data$DE
  m.trainData <- as.matrix(data[, c("DE") := list(NULL)])
  
  ## Hyper parameter tuning and grid search: ##
  xgb_trcontrol <- caret::trainControl(method = "cv",
                                       number = 3,
                                       allowParallel = TRUE,
                                       verboseIter = TRUE,
                                       returnData = FALSE
  ) 
  
  xgbgrid <- base::expand.grid(nrounds = c(150), # 15000
                               max_depth = c(2),
                               eta = c(0.3),
                               gamma = c(1),
                               colsample_bytree = c(1),
                               min_child_weight = c(2),
                               subsample = c(0.6)
  )
  
  ## Model fitting: ##
  xgbModel <- caret::train(m.trainData, 
                           v.trainY,
                           trControl = xgb_trcontrol,
                            tuneGrid = xgbgrid,
                           method = "xgbTree" )
  
  varimp <- caret::varImp(xgbModel, scale = FALSE)
  importance <- t(varimp$importance)
  

## Iterative Variable Importance for Gradient Boosting: ##
dt.importance1 <- as.data.frame(zoo::rollapply(dt.train[,-1], 
                                              FUN = varImportance,
                                              width = days,
                                              by.column = FALSE,
                                              align = 'left')
)

## Adding date-column again: ##
dt.importance <- cbind(dt.train[1:nrow(dt.importance1), .(date)], dt.importance1)

【讨论】:

感谢您的回答。我稍后会尝试一下。这是否也适用于多元自适应回归样条(= MARS),我在以下问题中提到过:link 并且具有与梯度提升相同的模型拟合约定。 使用答案中的代码会引发错误(请参阅上面的问题)。为什么它对你有效,但对我无效?错误信息是什么意思? 您收到“$ operator is invalid for atomic vectors”错误,因为 rollapply 无法正常工作。 第二个错误提示你不能对交叉验证的结果使用predict。在您的代码中注释 trControl = xgb_trcontrol 并重试。请参阅有关此主题的另一篇文章 - ***.com/questions/52007875/… 当我评论 trControl = xgb_trcontrol 时,会产生以下警告/错误(请参阅我在问题中的第二次编辑)。

以上是关于梯度提升模型的变量重要性(以 50 天为间隔滚动)的主要内容,如果未能解决你的问题,请参考以下文章

如何在从模型中选择特征时执行随机网格搜索?

2万字阐述-Python 用 XGBoost 进行梯度提升的数据准备(收藏)

部分依赖图和梯度提升(GBM 包)

如何阻止梯度提升机过拟合?

XGBoost feature importance特征重要性-实战印第安人糖尿病数据集(附代码)

Python机器学习之梯度提升树