XGBoost 在 R 中应用于分类变量值不完整的数据

Application of XGBoost in R to data with incomplete values of a categorical variable

你如何应对XGBoost在R中的应用?我对此有疑问,因为当分类类型的数据列不包含其所有可能的值(模型考虑的值)时,我收到错误消息:"Featured names stored in object and newdata are different".

我知道如何通过以不同的方式准备输入数据来解决这个问题,即通过添加足够数量的虚拟变量来覆盖我打算考虑的分类变量的所有可能值。例如。如果我想使用的特征 F 取值 'a'、'b' 或 'c',我将使用特征 is_a、is_b 和 [=37] 创建 XGBoost 模型=].然后,如果在我要应用模型的输入数据中,特征 F 仅带有 'b' 或 'c' 值,我仍在使用这 3 个特征,is_c 等于0 在每次观察。

但这不是我想要的方式,因为它通常看起来很乏味,而且我在使用不同的模型时没有遇到类似的问题,例如通过 glm() 函数进行逻辑回归。

所以我的问题是:是否可以将 XGBoost 模型应用于包含具有不完整值的分类(因子)变量的观察? Incomplete 这里的意思是:并非模型考虑的所有值。

我已经根据 mtcars 数据准备了一个例子来展示这种情况。假设我们想要一个预测变速箱类型(自动或手动,第 'am' 列)的分类模型。一个可能的特征是权重(第 'wt' 列),我们希望将权重数据用作因子类型特征而不是连续类型特征。

library(xgboost)
library(dplyr)
library(dummies)

##### Example 0: wt as a continuous variable (no errors on data with incomplete values) #####
# Train:
data_train <- mtcars
model_matrix_train <- model.matrix(am ~ ., data = data_train)
xgb_data_train <- xgb.DMatrix(model_matrix_train, label = data_train$am)
param <- list(max_depth = 2, eta = 1, objective = "binary:logistic")
model_xgb <- xgb.train(param, xgb_data_train, nrounds = 100)

# Test on data with incomplete wt values:
data_test <- mtcars %>% 
  filter(wt < 4)
model_matrix_test <- model.matrix(am ~ ., data = data_test)
xgb_data_test <- xgb.DMatrix(model_matrix_test, label = data_test$am)
predict(model_xgb, newdata = xgb_data_test, type="prob")


##### Example 1: wt as a factor (error on data with incomplete values) #####
# Train:
data_train <- mtcars %>% 
  mutate(wt = factor(
    case_when(
      wt < 2 ~ "1_2",
      wt < 3 ~ "2_3",
      wt < 4 ~ "3_4",
      wt < 5 ~ "4_5",
      TRUE ~ "5_6"
    ))
  )
model_matrix_train <- model.matrix(am ~ ., data = data_train)
xgb_data_train <- xgb.DMatrix(model_matrix_train, label = data_train$am)
param <- list(max_depth = 2, eta = 1, objective = "binary:logistic")
model_xgb <- xgb.train(param, xgb_data_train, nrounds = 100)

# Test on data with incomplete wt values:
data_test <- mtcars %>% 
  filter(wt < 4) %>% 
  mutate(wt = factor(
    case_when(
      wt < 2 ~ "1_2",
      wt < 3 ~ "2_3",
      wt < 4 ~ "3_4",
      wt < 5 ~ "4_5",
      TRUE ~ "5_6"
    ))
  )
model_matrix_test <- model.matrix(am ~ ., data = data_test)
xgb_data_test <- xgb.DMatrix(model_matrix_test, label = data_test$am)
predict(model_xgb, newdata = xgb_data_test, type="prob") # ERROR

我还尝试对 wt 的所有相关案例使用虚拟变量(而不是将 wt 转换为因子变量)。结果类似于上面的例子1:

##### Example 2: wt as a dummy variable (error on data with incomplete values) #####
# Train:
data_train <- mtcars %>% 
  mutate(wt = factor(
    case_when(
      wt < 2 ~ "1_2",
      wt < 3 ~ "2_3",
      wt < 4 ~ "3_4",
      wt < 5 ~ "4_5",
      TRUE ~ "5_6"
    ))
  )
data_train <- dummy.data.frame(data_train, "wt", sep = "_")
model_matrix_train <- model.matrix(am ~ ., data = data_train)
xgb_data_train <- xgb.DMatrix(model_matrix_train, label = data_train$am)
param <- list(max_depth = 2, eta = 1, objective = "binary:logistic")
model_xgb <- xgb.train(param, xgb_data_train, nrounds = 100)

# Test on data with incomplete wt values:
data_test <- mtcars %>% 
  filter(wt < 4) %>% 
  mutate(wt = factor(
    case_when(
      wt < 2 ~ "1_2",
      wt < 3 ~ "2_3",
      wt < 4 ~ "3_4",
      wt < 5 ~ "4_5",
      TRUE ~ "5_6"
    ))
  )
data_test <- dummy.data.frame(data_test, "wt", sep = "_")
model_matrix_test <- model.matrix(am ~ ., data = data_test)
xgb_data_test <- xgb.DMatrix(model_matrix_test, label = data_test$am)
predict(model_xgb, newdata = xgb_data_test, type="prob") # ERROR

虽然输入数据中缺失特征的原因对算法来说是合理的(没有可用的分类数据),但特征缺失是因为数据不包含因子水平还是因为数据是确实不完整(缺少一个功能)。

所以我只能为您提供一种更快的方法来对新输入数据进行编码以始终具有正确的特征级别:

data_test <- mtcars %>% 
  filter(wt < 4) %>% 
  mutate(wt = factor(
    case_when(
      wt < 2 ~ "1_2",
      wt < 3 ~ "2_3",
      wt < 4 ~ "3_4",
      wt < 5 ~ "4_5",
      TRUE ~ "5_6"
    ), levels = c("1_2","2_3","3_4","4_5","5_6")) #instead of c(...) this could be variable with the stored factor levels from model creation
  )

data_test <- (data_test %>% cbind(model.matrix(~ wt-1, data = .) %>% data.frame())

这有两件重要的事情:

  1. 编码因子水平

通过在因子转换中提供级别参数,您将拥有所有相关级别。除了提供手动列表之外,您在创建原始模型时始终将适当的因子水平保存为变量。

  1. 对假人使用 cbind 和 model.matrix()

不使用 dummy.data.frame 函数,而是使用 model.matrix(),因为它将自动为缺失因子水平编码为 0。