R: проблемы применения LIME к квантовой текстовой модели - PullRequest
0 голосов
/ 11 мая 2018

это измененная версия моего предыдущего вопроса : я пытаюсь запустить LIME для моей quanteda текстовой модели, которая передает данные Трампа и Клинтона . Я запускаю его, следуя примеру, приведенному Томасом Педерсеном в его Понимании ЛАЙМ и полезном 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 ("корпус"): неприменимый метод для «корпуса», примененный к объекту класса «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) 

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

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

1 Ответ

0 голосов
/ 11 мая 2018

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() возвращает объект классов textmodel_nb, textmodel и 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() - изменилась.

...