R:将 LIME 应用于 quanteda 文本模型的问题
R: problems applying LIME to quanteda text model
这是我的 : 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 :
的修改版本
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)
...我收到以下错误:
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')"
它回到应用 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)
但我不明白为什么这会导致任何问题,因为新数据是文本向量?
感谢任何提示
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()
returns 的更新版本中 类 textmodel_nb
、textmodel
和 list
.这首先需要 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()
的输出——已经改变。
这是我的 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
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)
...我收到以下错误:
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')"
它回到应用 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)
但我不明白为什么这会导致任何问题,因为新数据是文本向量?
感谢任何提示
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()
returns 的更新版本中 类 textmodel_nb
、textmodel
和 list
.这首先需要 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()
的输出——已经改变。