J'essaie d'utiliser LIME pour expliquer un modèle de classification binaire que j'ai formé à l'aide de XGboost. Je rencontre une erreur lors de l'appel de la fonction Expliquer ()
depuis LIME, ce qui implique que j'ai des colonnes qui ne correspondent pas dans mon modèle (ou explicatif) et les nouvelles données que j'essaie d'expliquer prédictions pour.
Cette vignette pour LIME montre une version avec xgboost, mais c'est un problème de texte qui est un peu différent de mes données tabulaires. Cette question semble rencontrer la même erreur, mais aussi pour une matrice de termes de document, ce qui semble obscurcir la solution pour mon cas. J'ai élaboré un exemple minimal avec mtcars
qui a produit exactement les mêmes erreurs que j'obtiens dans mon propre ensemble de données plus grand.
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)
Je suppose que parce que l ' explicateur
n'a que les noms des colonnes de prédicteur d'origine, où les données de test dans leur état transformé ont également un (Intercepter)
colonne, ceci est à l'origine du problème. Je n'ai tout simplement pas trouvé de moyen efficace d'empêcher que cela se produise. Toute aide serait très appréciée. Je suppose qu'il doit y avoir une solution intéressante.
4 Réponses :
Si vous regardez cette page ( https: // rdrr. io / cran / xgboost / src / R / xgb.Booster.R ), vous verrez que certains utilisateurs de R sont susceptibles de recevoir le message d'erreur suivant: "Noms de fonctionnalités stockés dans objet
et newdata
sont différents! ".
Voici le code de cette page lié au message d'erreur:
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)
identique (object [["feature_names"]], colnames (newdata))
=> Si les noms de colonne de objet
(c'est-à-dire votre modèle basé sur votre ensemble d'entraînement) ne sont pas identiques aux noms de colonne de newdata
(c'est-à-dire votre ensemble de test ), vous obtiendrez le message d'erreur.
Pour plus de détails:
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!")
Lors de la définition par vous-même de objet
et newdata
avec vos données grâce au code ci-dessus, vous pouvez probablement résoudre ce problème en regardant les différences entre object [["feature_names"]]
et colnames (newdata)
. Probablement certaines colonnes qui n'apparaissent pas dans le même ordre ou quelque chose comme ça.
Essayez ceci dans votre nouvel ensemble de données,
colnames(test)<- make.names(colnames(test)) newdataset<- test %>% mutate_all(as.numeric) newdataset<- as.matrix(newdataset) nwtest<-xgb.DMatrix(newdataset)
J'ai des problèmes avec la première ligne. Sur quel objet dois-je appeler colnames () <-
? Si je le fais sur le dataframe df_test
, j'obtiens un tas de NA pour les noms de colonne et je ne peux pas continuer.
Pour éviter que la colonne (Interception) n'apparaisse, vous devez modifier légèrement votre code lors de la création de la matrice creuse pour vos données de test. Remplacez la ligne:
test <- list(sparse.model.matrix( ~ .-1, data = data), label)
par:
test <- list(sparse.model.matrix( ~ ., data = data), label)
J'espère que cela vous aidera
Merci, j'ai essayé cela, mais cela n'a pas semblé fonctionner.
J'ai eu le même problème mais les colonnes n'étaient pas dans l'ordre alphabétique. Pour résoudre ce problème, j'ai fait correspondre l'ordre des noms de colonne dans df_test à df_train afin que les noms de colonne soient dans le même ordre.
Créez une liste de numéros de colonne df_test dans le même ordre que df_train:
df_test_match <- df_test[,idx]
Créez un nouveau fichier df_test en utilisant cet ordre de colonne:
idx<- match(colnames(df_train), colnames(df_test))