Наивный Байес в Quanteda vs caret: совершенно разные результаты
Я пытаюсь использовать пакеты quanteda
а также caret
вместе, чтобы классифицировать текст на основе обученного образца. В качестве теста я хотел сравнить встроенный наивный байесовский классификатор quanteda
с теми, в caret
, Тем не менее, я не могу получить caret
работать правильно.
Вот код для воспроизведения. Сначала на quanteda
боковая сторона:
library(quanteda)
library(quanteda.corpora)
library(caret)
corp <- data_corpus_movies
set.seed(300)
id_train <- sample(docnames(corp), size = 1500, replace = FALSE)
# get training set
training_dfm <- corpus_subset(corp, docnames(corp) %in% id_train) %>%
dfm(stem = TRUE)
# get test set (documents not in id_train, make features equal)
test_dfm <- corpus_subset(corp, !docnames(corp) %in% id_train) %>%
dfm(stem = TRUE) %>%
dfm_select(pattern = training_dfm,
selection = "keep")
# train model on sentiment
nb_quanteda <- textmodel_nb(training_dfm, docvars(training_dfm, "Sentiment"))
# predict and evaluate
actual_class <- docvars(test_dfm, "Sentiment")
predicted_class <- predict(nb_quanteda, newdata = test_dfm)
class_table_quanteda <- table(actual_class, predicted_class)
class_table_quanteda
#> predicted_class
#> actual_class neg pos
#> neg 202 47
#> pos 49 202
Неплохо. Точность составляет 80,8% без настройки. Теперь то же самое (насколько я знаю) в caret
training_m <- convert(training_dfm, to = "matrix")
test_m <- convert(test_dfm, to = "matrix")
nb_caret <- train(x = training_m,
y = as.factor(docvars(training_dfm, "Sentiment")),
method = "naive_bayes",
trControl = trainControl(method = "none"),
tuneGrid = data.frame(laplace = 1,
usekernel = FALSE,
adjust = FALSE),
verbose = TRUE)
predicted_class_caret <- predict(nb_caret, newdata = test_m)
class_table_caret <- table(actual_class, predicted_class_caret)
class_table_caret
#> predicted_class_caret
#> actual_class neg pos
#> neg 246 3
#> pos 249 2
Точность здесь не только плачевна (49,6% - примерно вероятность), но и почти не предсказывают класс pos! Так что я почти уверен, что упускаю что-то важное здесь, поскольку я предполагаю, что реализации должны быть довольно похожими, но не уверен, что именно.
Я уже посмотрел на исходный код для quanteda
функция (надеясь, что она может быть построена на caret
или базовый пакет в любом случае) и увидел, что происходит некоторое взвешивание и сглаживание. Если я применяю то же самое к моему dfm перед тренировкой (настройка laplace = 0
позже) точность немного лучше. Еще и только 53%.
1 ответ
Ответ в том, что каретка (которая использует naive_bayes
из пакета naivebayes) предполагает гауссово распределение, тогда как quanteda::textmodel_nb()
основывается на более подходящем для текста многочленовом распределении (с возможностью распределения Бернулли также).
Документация для textmodel_nb()
повторяет пример из книги IIR (Мэннинг, Рагхаван и Шютце 2008), а также приведен еще один пример из Jurafsky and Martin (2018). Увидеть:
Мэннинг, Кристофер Д., Прабхакар Рагхаван и Генрих Шютце. 2008. Введение в поиск информации. Издательство Кембриджского университета (глава 13). https://nlp.stanford.edu/IR-book/pdf/irbookonlinereading.pdf
Юрафски, Даниэль и Джеймс Х. Мартин. 2018. Обработка речи и языка. Введение в обработку естественного языка, компьютерную лингвистику и распознавание речи. Проект 3-го издания от 23 сентября 2018 года (глава 4). https://web.stanford.edu/~jurafsky/slp3/4.pdf
Другой пакет, e1071, дает те же результаты, которые вы нашли, поскольку он также основан на распределении Гаусса.
library("e1071")
nb_e1071 <- naiveBayes(x = training_m,
y = as.factor(docvars(training_dfm, "Sentiment")))
nb_e1071_pred <- predict(nb_e1071, newdata = test_m)
table(actual_class, nb_e1071_pred)
## nb_e1071_pred
## actual_class neg pos
## neg 246 3
## pos 249 2
Однако и карета, и e1071 работают на плотных матрицах, что является одной из причин, по которой они настолько ошеломительно медленны по сравнению с квантовым подходом, который работает с разреженной dfm. Таким образом, с точки зрения соответствия, эффективности и (в соответствии с вашими результатами) эффективности классификатора, должно быть достаточно ясно, какой из них предпочтительнее!
library("rbenchmark")
benchmark(
quanteda = {
nb_quanteda <- textmodel_nb(training_dfm, docvars(training_dfm, "Sentiment"))
predicted_class <- predict(nb_quanteda, newdata = test_dfm)
},
caret = {
nb_caret <- train(x = training_m,
y = as.factor(docvars(training_dfm, "Sentiment")),
method = "naive_bayes",
trControl = trainControl(method = "none"),
tuneGrid = data.frame(laplace = 1,
usekernel = FALSE,
adjust = FALSE),
verbose = FALSE)
predicted_class_caret <- predict(nb_caret, newdata = test_m)
},
e1071 = {
nb_e1071 <- naiveBayes(x = training_m,
y = as.factor(docvars(training_dfm, "Sentiment")))
nb_e1071_pred <- predict(nb_e1071, newdata = test_m)
},
replications = 1
)
## test replications elapsed relative user.self sys.self user.child sys.child
## 2 caret 1 29.042 123.583 25.896 3.095 0 0
## 3 e1071 1 217.177 924.157 215.587 1.169 0 0
## 1 quanteda 1 0.235 1.000 0.213 0.023 0 0
Приведенный выше ответ верен, я просто хотел добавить, что вы можете использовать дистрибутив Бернулли с пакетами "naivebayes" и "e1071", превратив ваши переменные в факторы. Их выходные данные должны соответствовать textmodel_nb 'quanteda' с распределением Бернулли.
Кроме того, вы можете проверить: https://cran.r-project.org/web/packages/fastNaiveBayes/index.html. Это реализует распределение Бернулли, Мультивиномов и Гаусса, работает с разреженными матрицами и является невероятно быстрым (самый быстрый в настоящее время на CRAN).