R:将 LIME 应用于 quanteda 文本模型的问题

Posted

技术标签:

【中文标题】R:将 LIME 应用于 quanteda 文本模型的问题【英文标题】:R: problems applying LIME to quanteda text model 【发布时间】:2018-10-21 18:43:16 【问题描述】:

这是我的previous question 的修改版本:我正在尝试在我的quanteda 文本模型上运行 LIME,它以Trump & Clinton tweets data 为基础。我按照 Thomas Pedersen 在他的Understanding LIME 中给出的示例和@Weihuang Wong 提供的有用 SO 答案运行它:

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") 中的错误: 没有适用于“语料库”的方法应用于类“c('dfm','dgCMatrix','CsparseMatrix','dsparseMatrix','generalMatrix','dCsparseMatrix','dMatrix','sparseMatrix','compMatrix' ', '矩阵', '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】:

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 会引发错误。为了调试,我在predict_model.textmodel_nb_fitted 函数的第一行插入了print(str(newdata))。这说明newdata已经是dfm对象,所以可以直接传入predict.textmodel_nb_fitted(用dfm_select处理后)。


quanteda 的更新版本中,textmodel_nb() 返回类textmodel_nbtextmodellist 的对象。这首先需要model_type的对应方法:

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

然后我们还必须为predict_model 编写一个textmodel_nb 方法:

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() 的输出——发生了变化。

【讨论】:

好的,要添加一层复杂性!当我从一台 Mac 运行代码时,class(nb_model) 返回"textmodel_nb_fitted" "list",并且上面的代码有效。但是,在 Windows 计算机上 Macbook 2008 的输出是 "textmodel_nb" "textmodel" "list" ,为什么?而且,无论我将 predict.model 和 model_type 修改为 .textmodel 还是 .textmodel_nb,当解释器下雨时,我仍然会遇到 newdata 和训练集中的不同特征的问题。真的不知道如何在我应该在星期一给出的研讨会之前解决这个问题;)我会很感激这里的任何建议! 顺便说一句,我不确定模型类中的差异是来自不同的计算机还是只是不同版本的 R/Rstudio/packages,但是仍然存在差异 对——经过一番研究,我意识到在较新版本的quanteda 中,textmodel_nb 返回一个结构略有不同的对象。请参阅我的更新答案。我想您应该建议您的研讨会参与者安装最新版本的quanteda 它现在可以工作了,太棒了!非常感谢您在这里的指导和澄清。它拯救了我们的研讨会 :) 让我想到 SO、R 和开源社区总体上是多么了不起。感谢您参与其中

以上是关于R:将 LIME 应用于 quanteda 文本模型的问题的主要内容,如果未能解决你的问题,请参考以下文章

在 R 中将 DFM 与 quanteda 合并

R语言构建文本分类模型并使用LIME进行模型解释实战:文本数据预处理构建词袋模型构建xgboost文本分类模型基于文本训练数据以及模型构建LIME解释器解释一个测试语料的预测结果并可视化

R语言构建文本分类模型并使用LIME进行模型解释实战:文本数据预处理构建词袋模型构建xgboost文本分类模型基于文本训练数据以及模型构建LIME解释器解释多个测试语料的预测结果并可视化

将 LIME 解释应用于我的微调 BERT 以进行序列分类模型?

使用 quanteda 在 R 中的大型语料库上计算余弦相似度

Quanteda 包,朴素贝叶斯:如何预测不同特征的测试数据?