Имена объектов, хранящиеся в `object` и` newdata`, отличаются!при использовании пакета LIME для объяснения модели xgboost в R - PullRequest
2 голосов
/ 25 марта 2019

Я пытаюсь использовать LIME для объяснения бинарной модели классификации, которую я обучил с использованием XGboost. Я сталкиваюсь с ошибкой при вызове функции explain() из LIME, которая подразумевает, что у меня есть столбцы, которые не совпадают в моей модели (или объясняющем устройстве), и новые данные, для которых я пытаюсь объяснить прогнозы.

Эта виньетка для LIME демонстрирует версию с xgboost, однако это текстовая проблема, которая немного отличается от моих табличных данных. Этот вопрос , кажется, сталкивается с той же ошибкой, но также и с матрицей терминов документа, которая, кажется, затеняет решение для моего случая. Я разработал минимальный пример с mtcars, который выдал те же ошибки, что и мой собственный больший набор данных.

library(pacman)
p_load(tidyverse)
p_load(xgboost)
p_load(Matrix)
p_load(lime)

### Prepare data with partition
df <- mtcars %>% rownames_to_column()
length <- df %>% nrow()
df_train <- df %>% select(-rowname) %>% head((length-10))
df_test <- df %>% select(-rowname) %>% tail(10)

### Transform data into matrix objects for XGboost
train <- list(sparse.model.matrix(~., data = df_train %>% select(-vs)), (df_train$vs %>% as.factor()))
names(train) <- c("data", "label")
test <- list(sparse.model.matrix(~., data = df_test %>% select(-vs)), (df_test$vs %>% as.factor()))
names(test) <- c("data", "label")
dtrain <- xgb.DMatrix(data = train$data, label=train$label)
dtest <- xgb.DMatrix(data = test$data, label=test$label)


### Train model
watchlist <- list(train=dtrain, test=dtest)
mod_xgb_tree <- xgb.train(data = dtrain,  booster = "gbtree", eta = .1, nrounds = 15, watchlist = watchlist)

### Check prediction works
output <- predict(mod_xgb_tree, test$data) %>% tibble()

### attempt lime explanation
explainer <- df_train %>% select(-vs) %>% lime(model = mod_xgb_tree)  ### works, no error or warning
explanation <- df_test %>% select(-vs) %>% explain(explainer, n_features = 4) ### error, Features stored names in `object` and `newdata` are different!

names_test <- test$data@Dimnames[[2]]  ### 10 names
names_mod <- mod_xgb_tree$feature_names ### 11 names
names_explainer <- explainer$feature_type %>% enframe() %>% pull(name) ### 11 names


### see whether pre-processing helps
my_preprocess <- function(df){
  data <- df %>% select(-vs)
  label <- df$vs

  test <<- list(sparse.model.matrix( ~ ., data = data), label)
  names(test) <<- c("data", "label")

  dtest <- xgb.DMatrix(data = test$data, label=test$label)
  dtest
}

explanation <- df_test %>% explain(explainer, preprocess = my_preprocess(), n_features = 4) ### Error in feature_distribution[[i]] : subscript out of bounds

### check that the preprocessing is working ok
dtest_check <- df_test %>% my_preprocess()
output_check <- predict(mod_xgb_tree, dtest_check)

Я предполагаю, что, поскольку explainer имеет только имена исходных столбцов предиктора, где тестовые данные в своем преобразованном состоянии также имеют столбец (Intercept), это вызывает проблему. Я просто не нашел аккуратный способ предотвратить это. Любая помощь приветствуется. Я предполагаю, что должно быть аккуратное решение.

1 Ответ

0 голосов
/ 22 июня 2019

Если вы посмотрите на эту страницу (https://rdrr.io/cran/xgboost/src/R/xgb.Booster.R),, то увидите, что некоторые пользователи R могут получить следующее сообщение об ошибке: «Имена функций, хранящиеся в object и newdata, отличаются!».

Вот код этой страницы, связанный с сообщением об ошибке:

predict.xgb.Booster <- function(object, newdata, missing = NA, outputmargin = FALSE, ntreelimit = NULL,predleaf = FALSE, predcontrib = FALSE, approxcontrib = FALSE, predinteraction = FALSE,reshape = FALSE, ...)

object <- xgb.Booster.complete(object, saveraw = FALSE)
      if (!inherits(newdata, "xgb.DMatrix"))
        newdata <- xgb.DMatrix(newdata, missing = missing)
      if (!is.null(object[["feature_names"]]) &&
          !is.null(colnames(newdata)) &&
          !identical(object[["feature_names"]], colnames(newdata)))
        stop("Feature names stored in `object` and `newdata` are different!")

identical(object[["feature_names"]], colnames(newdata)) => Если имена столбцов object (т.е. ваша модель основана на вашем тренировочном наборе)не совпадают с именами столбцов newdata (т. е. ваш набор тестов), вы получите сообщение об ошибке.

Для более подробной информации:

train_matrix <- xgb.DMatrix(as.matrix(training %>% select(-target)), label = training$target, missing = NaN)
object <- xgb.train(data=train_matrix, params=..., nthread=2, nrounds=..., prediction = T)
newdata <- xgb.DMatrix(as.matrix(test %>% select(-target)), missing = NaN)

При настройке самостоятельно object и newdata с вашими данными благодаря приведенному выше коду, вы, вероятно, можете решить эту проблему, посмотрев на различия между object[["feature_names"]] и colnames(newdata). Возможно, некоторые столбцы не отображаются в том же порядке или что-то в этом роде.

...