Наивный Байес в Quanteda vs Caret: совершенно разные результаты - PullRequest
0 голосов
/ 29 января 2019

Я пытаюсь использовать пакеты 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%.

Ответы [ 2 ]

0 голосов
/ 14 апреля 2019

Приведенный выше ответ верен, я просто хотел добавить, что вы можете использовать дистрибутив Бернулли с пакетами «naivebayes» и «e1071», превратив ваши переменные в факторы.Их выходные данные должны соответствовать textmodel_nb 'quanteda' с распределением Бернулли.

Кроме того, вы можете проверить: https://cran.r -project.org / web / packages / fastNaiveBayes / index.html .Это реализует распределение Бернулли, Мультивиномов и Гаусса, работает с разреженными матрицами и является невероятно быстрым (самый быстрый в настоящее время на CRAN).

0 голосов
/ 30 января 2019

Ответ таков: caret (который использует naive_bayes из пакета naivebayes ) предполагает гауссово распределение, тогда как quanteda::textmodel_nb() основано на более подходящем тексту многочленовом распределении(с возможностью распределения Бернулли также).

Документация для textmodel_nb() повторяет пример из книги IIR (Мэннинг, Рагхаван и Шютце 2008) и еще один пример из Юрафски и Мартина (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

Однако оба caret и e1071 работают на плотных матрицах, что является одной из причин, по которым они настолько ошеломительно медленны по сравнению с подходом quanteda , который работает с разреженным 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
...