it's a modified version of my previous question: I'm trying to run LIME on my quanteda
text model that feeds off Trump & Clinton tweets data. I run it following an example given by Thomas Pedersen in his Understanding LIME and useuful SO answer provided by @Weihuang Wong:
library(dplyr)
library(stringr)
library(quanteda)
library(lime)
#data prep
tweet_csv <- read_csv("tweets.csv")
# creating corpus and dfm for train and test sets
get_matrix <- function(df){
corpus <- quanteda::corpus(df)
dfm <- quanteda::dfm(corpus, remove_url = TRUE, remove_punct = TRUE, remove = stopwords("english"))
}
set.seed(32984)
trainIndex <- sample.int(n = nrow(tweet_csv), size = floor(.8*nrow(tweet_csv)), replace = F)
train_dfm <- get_matrix(tweet_csv$text[trainIndex])
train_raw <- tweet_csv[, c("text", "tweet_num")][as.vector(trainIndex), ]
train_labels <- tweet_csv$author[as.vector(trainIndex)] == "realDonaldTrump"
test_dfm <- get_matrix(tweet_csv$text[-trainIndex])
test_raw <- tweet_csv[, c("text", "tweet_num")][-as.vector(trainIndex), ]
test_labels <- tweet_csv$author[-as.vector(trainIndex)] == "realDonaldTrump"
#### make sure that train & test sets have exactly same features
test_dfm <- dfm_select(test_dfm, train_dfm)
### Naive Bayes model using quanteda::textmodel_nb ####
nb_model <- quanteda::textmodel_nb(train_dfm, train_labels)
nb_preds <- predict(nb_model, test_dfm) #> 0.5
# select only correct predictions
predictions_tbl <- data.frame(predict_label = nb_preds$nb.predicted,
actual_label = test_labels,
tweet_name = rownames(nb_preds$posterior.prob)
) %>%
mutate(tweet_num =
as.integer(
str_trim(
str_replace_all(tweet_name, "text", ""))
))
correct_pred <- predictions_tbl %>%
filter(actual_label == predict_label)
# pick a sample of tweets for explainer
tweets_to_explain <- test_raw %>%
filter(tweet_num %in% correct_pred$tweet_num) %>%
head(4)
### set up correct model class and predict functions
class(nb_model)
model_type.textmodel_nb_fitted <- function(x, ...) {
return("classification")
}
# have to modify the textmodel_nb_fitted so that
predict_model.textmodel_nb_fitted <- function(x, newdata, type, ...) {
X <- corpus(newdata)
X <- dfm_select(dfm(X), x$data$x)
res <- predict(x, newdata = X, ...)
switch(
type,
raw = data.frame(Response = res$nb.predicted, stringsAsFactors = FALSE),
prob = as.data.frame(res$posterior.prob, check.names = FALSE)
)
}
### run the explainer - no problems here
explainer <- lime(tweets_to_explain$text, # lime returns error on different features in explainer and explanations, even if I use the same dataset in both. Raised an issue on Github and asked a question on SO
model = nb_model,
preprocess = get_matrix)
But when I run the explainer...
corr_explanation <- lime::explain(tweets_to_explain$text,
explainer,
n_labels = 1,
n_features = 6,
cols = 2,
verbose = 0)
... I get the following error:
Error in UseMethod("corpus") : no applicable method for 'corpus' applied to an object of class "c('dfm', 'dgCMatrix', 'CsparseMatrix', 'dsparseMatrix', 'generalMatrix', 'dCsparseMatrix', 'dMatrix', 'sparseMatrix', 'compMatrix', 'Matrix', 'xMatrix', 'mMatrix', 'Mnumeric', 'replValueSp')"
It goes back to applying corpus()
to newdata
:
5.corpus(newdata)
4.predict_model.textmodel_nb_fitted(x = explainer$model, newdata = permutations_tokenized,
type = o_type)
3.predict_model(x = explainer$model, newdata = permutations_tokenized,
type = o_type)
2.explain.character(tweets_to_explain$text, explainer, n_labels = 1,
n_features = 6, cols = 2, verbose = 0)
1.lime::explain(tweets_to_explain$text, explainer, n_labels = 1,
n_features = 6, cols = 2, verbose = 0)
But I don't understand why should this cause any issues as new data is a text vector?
Thanks for any hints