Implements the Threshold-Based Naive Bayes (Tb-NB) classifier
and its iterative refinement (iTb-NB) for binary sentiment / text
classification problems. The classifier computes a continuous
log-likelihood ratio score per document and uses a data-driven decision
threshold estimated via K-fold cross-validation on a user-selected
criterion (accuracy, F1 score, Matthews correlation coefficient,
balanced error, etc.). An optional
iterative refinement procedure locally re-estimates the threshold in
regions of class overlap using either Gaussian kernel density estimation
or a Central Limit Theorem bootstrap approximation. The package exposes
an idiomatic R formula + data.frame interface together with a
'quanteda'-based text preprocessing pipeline, supports user-supplied
document-feature matrices, and includes an optional word-embedding
extension that augments the Bag-of-Words with K nearest semantic
neighbours of each token. The package additionally implements the
p-value extension proposed by Romano (2025) for both document- and
feature-level interpretability via tbnb_pvalues(). Methods are
described in Romano, Contu, Mola, Conversano (2024)
tbnb implements the Threshold-Based Naive Bayes (Tb-NB) classifier and
its iterative refinement (iTb-NB) for binary sentiment / text
classification problems, following an idiomatic R API
(formula + data.frame, S3 methods, predict(), summary(), coef(),
plot()).
Classical Naive Bayes outputs poorly-calibrated posterior probabilities when conditional independence is violated. Tb-NB sidesteps the issue by:
Models are described in:
install.packages("tbnb")
library(tbnb)
data(toy_reviews)
# Formula + data interface (no manual text preprocessing required)
fit <- itbnb(
sentiment ~ text,
data = toy_reviews,
preprocess = tbnb_preprocess(language = "english"),
criterion = "balanced_error",
K = 5,
iterative = TRUE,
iter_mode = "kde"
)
summary(fit)
predict(fit, newdata = toy_reviews[1:5, ], type = "class")
predict(fit, newdata = toy_reviews[1:5, ], type = "score")
plot(fit, newdata = toy_reviews, y = toy_reviews$sentiment)
If you already have a document-feature matrix (e.g. a quanteda::dfm
or a Matrix sparse matrix), pass it directly via x / y:
fit <- itbnb(x = my_dfm, y = sentiment, criterion = "f1")
The package implements the p-value extension proposed in Romano (2025, doi:10.1007/978-3-031-96736-8_41): for any fitted model you can compute document-level p-values (how extreme is each document's score under the per-class score distribution) and feature-level p-values (which words are statistically significant predictors, not just "top-K by log-odds").
# Per-document p-values + uncertainty flag
pv_doc <- tbnb_pvalues(fit, type = "document",
newdata = toy_reviews,
method = "clt") # or "kde"
head(pv_doc)
# Per-feature p-values
pv_feat <- tbnb_pvalues(fit, type = "feature", method = "clt")
head(pv_feat[order(pv_feat$p_value), ], 10)
# summary() integrates the significant-feature ranking
summary(fit, pvalues = TRUE, pvalue_method = "clt")
Beyond the original papers, tbnb supports an optional semantic
augmentation of the Bag-of-Words using a word-embedding model
(approach C in the design notes): for each token in a document, the top-k
nearest neighbours in the embedding space are added to the BoW. This can
help with sparsity and synonym handling while leaving Tb-NB's word-level
interpretability intact.
emb <- tbnb_embedding(my_glove_matrix, k = 3, min_similarity = 0.6)
fit <- itbnb(sentiment ~ text, data = reviews, embedding = emb)
This extension is not part of the original Tb-NB / iTb-NB papers and must be explicitly enabled.
GPL (>= 3)