R: проблемы применения LIME к квантовой текстовой модели

это модифицированная версия моего предыдущего вопроса: я пытаюсь запустить LIME на моей quanteda текстовой модели, которая питается от данные твитов Трампа и Клинтона. Я запускаю его, следуя примеру, приведенному Томасом Педерсеном в его понимании LIME и полезный SO-ответ, предоставленный @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) 

Но когда я запускаю объяснитель ...

corr_explanation <- lime::explain(tweets_to_explain$text, 
                              explainer, 
                              n_labels = 1,
                              n_features = 6,
                              cols = 2,
                              verbose = 0)

... Я получаю следующую ошибку:

Ошибка в UseMethod ("corpus"): нет применимого метода для 'corpus', примененного к объекту класса "c ('dfm', 'dgCMatrix', 'CsparseMatrix', 'dsparseMatrix', 'generalMatrix', 'dCsparseMatrix', ' dMatrix ',' sparseMatrix ',' compMatrix ',' Matrix ',' xMatrix ',' mMatrix ',' Mnumeric ',' replValueSp ') "

Он возвращается к применению corpus() к 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) 

Но я не понимаю, почему это должно вызывать какие-либо проблемы, поскольку новые данные представляют собой текстовый вектор?

Спасибо за любые подсказки


person Kasia Kulma    schedule 11.05.2018    source источник


Ответы (1)


corpus запускать не нужно. Попробуйте переопределить predict_model.textmodel_nb_fitted следующим образом, единственное изменение - добавить шаг dfm_select:

predict_model.textmodel_nb_fitted <- function(x, newdata, type, ...) {
  X <- dfm_select(dfm(newdata), 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)
  )  
}

Как показывает ваш traceback() вывод, corpus выдает ошибку. Для отладки я вставил print(str(newdata)) в первую строку функции predict_model.textmodel_nb_fitted. Это показывает, что newdata уже является объектом dfm, поэтому его можно передать непосредственно в predict.textmodel_nb_fitted (после обработки с помощью dfm_select).


В более поздних версиях quanteda, textmodel_nb() возвращает объект классов _15 _, _ 16_ и list. Для этого сначала потребуется соответствующий метод для model_type:

model_type.textmodel_nb <- function(x, ...) {
  return("classification")
}

Затем мы также должны написать textmodel_nb метод для predict_model:

predict_model.textmodel_nb <- function(x, newdata, type, ...) {
  X <- dfm_select(dfm(newdata), x$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)
  )  
}

Обратите внимание, что второй аргумент dfm_select отличается от аргумента predict_model.textmodel_nb_fitted (из исходной версии ответа). Это связано с тем, что структура объекта x - результат textmodel_nb() - изменилась.

person Weihuang Wong    schedule 11.05.2018
comment
Хорошо, нужно добавить еще один уровень сложности! Когда я запускаю код с одного Mac, class(nb_model) возвращает "textmodel_nb_fitted" "list", и приведенный выше код работает. Однако на компьютерах с Windows Macbook 2008 вывод будет "textmodel_nb" "textmodel" "list", почему? И независимо от того, изменяю ли я pred.model и model_type на .textmodel или .textmodel_nb, у меня по-прежнему возникают проблемы с различными функциями в newdata и обучающем наборе, когда я использую объяснитель. На самом деле не знаю, как решить эту проблему перед семинаром, который я должен провести по этому поводу в понедельник;) Буду признателен за любые предложения здесь! - person Kasia Kulma; 13.05.2018
comment
Кстати, я не уверен, что расхождения в классе модели исходят от разных компьютеров или просто от разных версий R / Rstudio / пакетов, но, тем не менее, различия есть - person Kasia Kulma; 13.05.2018
comment
Справа - после некоторого исследования я понял, что в более новых версиях quanteda, textmodel_nb возвращает объект с немного другой структурой. Смотрите мой обновленный ответ. Думаю, вам следует посоветовать участникам вашего семинара установить последнюю версию quanteda. - person Weihuang Wong; 13.05.2018
comment
Теперь это работает, фантастика! Большое спасибо за ваше руководство и разъяснения. Это спасло наш семинар :) Заставляет задуматься, насколько замечательны сообщества SO, R и открытого исходного кода в целом. Спасибо за то, что ты в этом участвовал. - person Kasia Kulma; 13.05.2018