Quanteda 与插入符号中的朴素贝叶斯:截然不同的结果
Naive Bayes in Quanteda vs caret: wildly different results
我正在尝试将包 quanteda
和 caret
一起使用,以根据经过训练的样本 class 化文本。作为测试 运行,我想比较 quanteda
的内置朴素贝叶斯 classifier 和 caret
中的朴素贝叶斯 classifier。但是,我似乎无法让 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 class 几乎从未被预测过!所以我很确定我在这里遗漏了一些重要的东西,因为我认为实现应该非常相似,但不确定是什么。
我已经查看了 quanteda
函数的源代码(希望它可能构建在 caret
或底层包上)并看到正在进行一些加权和平滑.如果我在训练前对我的 dfm 应用相同的方法(稍后设置 laplace = 0
),准确性会好一点。然而也只有53%。
答案是 caret(使用 naivebayes 包中的 naive_bayes
)假设高斯分布,而 quanteda::textmodel_nb()
基于更适合文本的多项式分布(也可选择伯努利分布)。
textmodel_nb()
的文档复制了 IIR 书中的示例(Manning、Raghavan 和 Schütze 2008)以及 Jurafsky 和 Martin (2018) 的进一步示例也被引用。参见:
Manning、Christopher D.、Prabhakar Raghavan 和 Hinrich Schütze。 2008. 信息检索简介。剑桥大学出版社(第 13 章)。 https://nlp.stanford.edu/IR-book/pdf/irbookonlinereading.pdf
Jurafsky、Daniel 和 James H. Martin。 2018. 语音和语言处理。自然语言处理、计算语言学和语音识别简介。第三版草案,2018 年 9 月 23 日(第 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
上面的答案是正确的,我只是想补充一点,您可以通过将变量转换为因子来将伯努利分布与 'naivebayes' 和 'e1071' 包一起使用。这些的输出应该匹配 'quanteda' textmodel_nb 与伯努利分布。
此外,您可以查看:https://cran.r-project.org/web/packages/fastNaiveBayes/index.html。这实现了伯努利、多项式和高斯分布,适用于稀疏矩阵并且速度非常快(目前在 CRAN 上最快)。
我正在尝试将包 quanteda
和 caret
一起使用,以根据经过训练的样本 class 化文本。作为测试 运行,我想比较 quanteda
的内置朴素贝叶斯 classifier 和 caret
中的朴素贝叶斯 classifier。但是,我似乎无法让 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 class 几乎从未被预测过!所以我很确定我在这里遗漏了一些重要的东西,因为我认为实现应该非常相似,但不确定是什么。
我已经查看了 quanteda
函数的源代码(希望它可能构建在 caret
或底层包上)并看到正在进行一些加权和平滑.如果我在训练前对我的 dfm 应用相同的方法(稍后设置 laplace = 0
),准确性会好一点。然而也只有53%。
答案是 caret(使用 naivebayes 包中的 naive_bayes
)假设高斯分布,而 quanteda::textmodel_nb()
基于更适合文本的多项式分布(也可选择伯努利分布)。
textmodel_nb()
的文档复制了 IIR 书中的示例(Manning、Raghavan 和 Schütze 2008)以及 Jurafsky 和 Martin (2018) 的进一步示例也被引用。参见:
Manning、Christopher D.、Prabhakar Raghavan 和 Hinrich Schütze。 2008. 信息检索简介。剑桥大学出版社(第 13 章)。 https://nlp.stanford.edu/IR-book/pdf/irbookonlinereading.pdf
Jurafsky、Daniel 和 James H. Martin。 2018. 语音和语言处理。自然语言处理、计算语言学和语音识别简介。第三版草案,2018 年 9 月 23 日(第 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
上面的答案是正确的,我只是想补充一点,您可以通过将变量转换为因子来将伯努利分布与 'naivebayes' 和 'e1071' 包一起使用。这些的输出应该匹配 'quanteda' textmodel_nb 与伯努利分布。
此外,您可以查看:https://cran.r-project.org/web/packages/fastNaiveBayes/index.html。这实现了伯努利、多项式和高斯分布,适用于稀疏矩阵并且速度非常快(目前在 CRAN 上最快)。