| Title: | Latent Dirichlet Allocation Using 'tidyverse' Conventions |
|---|---|
| Description: | Implements an algorithm for Latent Dirichlet Allocation (LDA), Blei et al. (2003) <https://www.jmlr.org/papers/volume3/blei03a/blei03a.pdf>, using style conventions from the 'tidyverse', Wickham et al. (2019)<doi:10.21105/joss.01686>, and 'tidymodels', Kuhn et al.<https://tidymodels.github.io/model-implementation-principles/>. Fitting is done via 'warpLDA', a Metropolis-Hastings sampler, Chen et al. (2016) <doi:10.48550/arXiv.1510.08628>. Also implements several novel features for LDA such as guided models and transfer learning. |
| Authors: | Tommy Jones [aut, cre] (ORCID: <https://orcid.org/0000-0001-6457-2452>), Brendan Knapp [ctb] (ORCID: <https://orcid.org/0000-0003-3284-4972>), Barum Park [ctb] |
| Maintainer: | Tommy Jones <[email protected]> |
| License: | MIT + file LICENSE |
| Version: | 0.1.1.999 |
| Built: | 2026-10-11 15:50:00 UTC |
| Source: | https://github.com/tommyjones/tidylda |
tidylda objectsaugment appends observation level model outputs.
## S3 method for class 'tidylda' augment( x, data, type = c("class", "prob"), document_col = "document", term_col = "term", ... )## S3 method for class 'tidylda' augment( x, data, type = c("class", "prob"), document_col = "document", term_col = "term", ... )
x |
an object of class |
data |
a tidy tibble containing one row per original document-token pair, such as is returned by tdm_tidiers with column names c("document", "term") at a minimum. |
type |
one of either "class" or "prob" |
document_col |
character specifying the name of the column that
corresponds to document IDs. Defaults to |
term_col |
character specifying the name of the column that
corresponds to term/token IDs. Defaults to |
... |
other arguments passed to methods,currently not used |
The key statistic for augment is P(topic | document, token) =
P(topic | token) * P(token | document). P(topic | token) are the entries
of the 'lambda' matrix in the tidylda object passed
with x. P(token | document) is taken to be the frequency of each
token normalized within each document.
augment returns a tidy tibble containing one row per document-token
pair, with one or more columns appended, depending on the value of type.
If type = 'prob', then one column per topic is appended. Its value
is P(topic | document, token).
If type = 'class', then the most-probable topic for each document-token
pair is returned. If multiple topics are equally probable, then the topic
with the smallest index is returned by default.
Calculates the probabilistic coherence of a topic or topics. This approximates semantic coherence or human understandability of a topic.
calc_prob_coherence(beta, data, m = 5)calc_prob_coherence(beta, data, m = 5)
beta |
A numeric matrix or a numeric vector. The vector, or rows of the matrix represent the numeric relationship between topic(s) and terms. For example, this relationship may be p(word|topic) or p(topic|word). |
data |
A document term matrix or term co-occurrence matrix. The preferred
class is a |
m |
An integer for the number of words to be used in the calculation. Defaults to 5 |
For each pair of words {a, b} in the top M words in a topic, probabilistic coherence calculates P(b|a) - P(b), where {a} is more probable than {b} in the topic. For example, suppose the top 4 words in a topic are {a, b, c, d}. Then, we calculate 1. P(a|b) - P(b), P(a|c) - P(c), P(a|d) - P(d) 2. P(b|c) - P(c), P(b|d) - P(d) 3. P(c|d) - P(d) All 6 differences are averaged together.
Returns an object of class numeric corresponding to the
probabilistic coherence of the input topic(s).
# Load a pre-formatted dtm and topic model data(nih_sample_dtm) # fit a model set.seed(12345) model <- tidylda( data = nih_sample_dtm[1:20, ], k = 5, iterations = 100, burnin = 50 ) calc_prob_coherence(beta = model$beta, data = nih_sample_dtm, m = 5)# Load a pre-formatted dtm and topic model data(nih_sample_dtm) # fit a model set.seed(12345) model <- tidylda( data = nih_sample_dtm[1:20, ], k = 5, iterations = 100, burnin = 50 ) calc_prob_coherence(beta = model$beta, data = nih_sample_dtm, m = 5)
tidylda objectsglance constructs a single-row summary "glance" of a tidylda
topic model.
## S3 method for class 'tidylda' glance(x, ...)## S3 method for class 'tidylda' glance(x, ...)
x |
an object of class |
... |
other arguments passed to methods,currently not used |
glance returns a one-row tibble with the
following columns:
num_topics: the number of topics in the model
num_documents: the number of documents used for fitting
num_tokens: the number of tokens covered by the model
iterations: number of total sampling iterations run
burnin: number of burn-in iterations run
dtm <- nih_sample_dtm lda <- tidylda(data = dtm, k = 10, iterations = 100, burnin = 75) glance(lda)dtm <- nih_sample_dtm lda <- tidylda(data = dtm, k = 10, iterations = 100, burnin = 75) glance(lda)
This dataset holds information on research grants awarded by the National Institutes of Health (NIH) in 2014. The data set was downloaded in approximately January of 2015. It includes both 'projects' and 'abstracts' files.
data("nih_sample")data("nih_sample")
For nih_sample, a tibble of 100 randomly-sampled
grants' abstracts and metadata. For nih_sample_dtm, a
dgCMatrix-class representing the document term matrix
of abstracts from 100 randomly-sampled grants.
National Institutes of Health ExPORTER https://reporter.nih.gov/exporter
Sample from the marginal posteriors of a tidylda topic
model. This is useful for quantifying uncertainty around the parameters of
beta or theta.
posterior(x, ...) ## S3 method for class 'tidylda' posterior(x, matrix, which, times, ...)posterior(x, ...) ## S3 method for class 'tidylda' posterior(x, matrix, which, times, ...)
x |
An object of class |
... |
Other arguments, currently not used. |
matrix |
A character of either 'theta' or 'beta', indicating from which matrix to draw posterior samples. |
which |
Row index of |
times |
Integer, number of samples to draw. |
posterior returns a tibble with one row per parameter per sample.
Returns a data frame where each row is a single sample from the posterior.
Each column is the distribution over a single parameter. The variable var
is a facet for subsetting by document (for theta) or topic (for beta).
Heinrich, G. (2005) Parameter estimation for text analysis. Technical report. Archived copy (arbylon.net no longer resolves; this is the Internet Archive's copy.)
# load some data data(nih_sample_dtm) # fit a model set.seed(12345) m <- tidylda( data = nih_sample_dtm[1:20, ], k = 5, iterations = 200, burnin = 175 ) # sample from the marginal posterior corresponding to topic 1 t1 <- posterior( x = m, matrix = "beta", which = 1, times = 100 ) # sample from the marginal posterior corresponding to documents 5 and 6 d5 <- posterior( x = m, matrix = "theta", which = c(5, 6), times = 100 )# load some data data(nih_sample_dtm) # fit a model set.seed(12345) m <- tidylda( data = nih_sample_dtm[1:20, ], k = 5, iterations = 200, burnin = 175 ) # sample from the marginal posterior corresponding to topic 1 t1 <- posterior( x = m, matrix = "beta", which = 1, times = 100 ) # sample from the marginal posterior corresponding to documents 5 and 6 d5 <- posterior( x = m, matrix = "theta", which = c(5, 6), times = 100 )
Obtains predictions of topics for new documents from a fitted LDA model
## S3 method for class 'tidylda' predict( object, new_data, type = c("prob", "class", "distribution"), method = c("mh", "dot", "gibbs"), iterations = NULL, burnin = -1, no_common_tokens = c("default", "zero", "uniform"), times = 100, threads = 1, verbose = TRUE, mh_steps = 1, ... )## S3 method for class 'tidylda' predict( object, new_data, type = c("prob", "class", "distribution"), method = c("mh", "dot", "gibbs"), iterations = NULL, burnin = -1, no_common_tokens = c("default", "zero", "uniform"), times = 100, threads = 1, verbose = TRUE, mh_steps = 1, ... )
object |
a fitted object of class |
new_data |
a DTM or TCM of class |
type |
one of "prob", "class", or "distribution". Defaults to "prob". |
method |
one of either "mh" or "dot". If "mh", the model's
Metropolis-Hastings sampler is used
and |
iterations |
If |
burnin |
If |
no_common_tokens |
behavior when encountering documents that have no tokens
in common with the model. Options are " |
times |
Integer, number of samples to draw if |
threads |
Number of parallel threads, defaults to 1. Used when
|
verbose |
Logical. Do you want to print a progress bar out to the console?
Only active if |
mh_steps |
Integer. Metropolis-Hastings proposals per token per pass
when |
... |
Additional arguments, currently unused |
If predict.tidylda encounters documents that have no tokens in common
with the model in object it will engage in one of three behaviors based
on the setting of no_common_tokens.
default (the default) sets all topics to 0 for offending documents. This
enables continued computations downstream in a way that NA would not.
However, if no_common_tokens == "default", then predict.tidylda
will emit a warning for every such document it encounters.
zero has the same behavior as default but it emits a message
instead of a warning.
uniform sets all topics to 1/k for every topic for offending documents.
it does not emit a warning or message.
type gives different outputs depending on whether the user selects
"prob", "class", or "distribution". If "prob", the default, returns a
a "theta" matrix with one row per document and one column per topic. If
"class", returns a vector with the topic index of the most likely topic in
each document. If "distribution", returns a tibble with one row per
parameter per sample. Number of samples is set by the times argument.
# load some data data(nih_sample_dtm) # fit a model set.seed(12345) m <- tidylda( data = nih_sample_dtm[1:20, ], k = 5, iterations = 200, burnin = 175 ) str(m) # predict on held-out documents using Metropolis-Hastings "fold in" p1 <- predict(m, nih_sample_dtm[21:100, ], method = "mh", iterations = 200, burnin = 175 ) # predict on held-out documents using the dot product p2 <- predict(m, nih_sample_dtm[21:100, ], method = "dot") # compare the methods barplot(rbind(p1[1, ], p2[1, ]), beside = TRUE, col = c("red", "blue")) # predict classes on held out documents p3 <- predict(m, nih_sample_dtm[21:100, ], method = "mh", type = "class", iterations = 100, burnin = 75 ) # predict distribution on held out documents p4 <- predict(m, nih_sample_dtm[21:100, ], method = "mh", type = "distribution", iterations = 100, burnin = 75, times = 10 )# load some data data(nih_sample_dtm) # fit a model set.seed(12345) m <- tidylda( data = nih_sample_dtm[1:20, ], k = 5, iterations = 200, burnin = 175 ) str(m) # predict on held-out documents using Metropolis-Hastings "fold in" p1 <- predict(m, nih_sample_dtm[21:100, ], method = "mh", iterations = 200, burnin = 175 ) # predict on held-out documents using the dot product p2 <- predict(m, nih_sample_dtm[21:100, ], method = "dot") # compare the methods barplot(rbind(p1[1, ], p2[1, ]), beside = TRUE, col = c("red", "blue")) # predict classes on held out documents p3 <- predict(m, nih_sample_dtm[21:100, ], method = "mh", type = "class", iterations = 100, burnin = 75 ) # predict distribution on held out documents p4 <- predict(m, nih_sample_dtm[21:100, ], method = "mh", type = "distribution", iterations = 100, burnin = 75, times = 10 )
Print a summary for objects of class tidylda
## S3 method for class 'tidylda' print(x, digits = max(3L, getOption("digits") - 3L), n = 5, ...)## S3 method for class 'tidylda' print(x, digits = max(3L, getOption("digits") - 3L), n = 5, ...)
x |
an object of class |
digits |
minimal number of significant digits |
n |
Number of rows to show in each displayed |
... |
further arguments passed to or from other methods |
Silently returns x
dtm <- nih_sample_dtm lda <- tidylda(data = dtm, k = 10, iterations = 100) print(lda) lda print(lda, digits = 2)dtm <- nih_sample_dtm lda <- tidylda(data = dtm, k = 10, iterations = 100) print(lda) lda print(lda, digits = 2)
Update an LDA model using warpLDA's Metropolis-Hastings sampler.
## S3 method for class 'tidylda' refit( object, new_data, iterations = NULL, burnin = -1, prior_weight = 1, additional_k = 0, additional_eta_sum = 250, optimize_alpha = FALSE, calc_likelihood = FALSE, calc_r2 = FALSE, return_data = FALSE, threads = 1, verbose = TRUE, likelihood_every = 10, mh_steps = 1, ... )## S3 method for class 'tidylda' refit( object, new_data, iterations = NULL, burnin = -1, prior_weight = 1, additional_k = 0, additional_eta_sum = 250, optimize_alpha = FALSE, calc_likelihood = FALSE, calc_r2 = FALSE, return_data = FALSE, threads = 1, verbose = TRUE, likelihood_every = 10, mh_steps = 1, ... )
object |
a fitted object of class |
new_data |
A document term matrix or term co-occurrence matrix of class dgCMatrix. |
iterations |
Integer number of sampling iterations to run. |
burnin |
Integer number of burnin iterations. If |
prior_weight |
Numeric, 0 or greater or |
additional_k |
Integer number of topics to add, defaults to 0. |
additional_eta_sum |
Numeric magnitude of prior for additional topics.
Ignored if |
optimize_alpha |
Deprecated as of version 0.1.0 and ignored. See
|
calc_likelihood |
Logical. Do you want to calculate the log likelihood every iteration?
Useful for assessing convergence. Defaults to |
calc_r2 |
Logical. Do you want to calculate R-squared after the model is trained?
Defaults to |
return_data |
Logical. Do you want |
threads |
Number of parallel threads, defaults to 1. Results are
identical at any thread count; see |
verbose |
Logical. Do you want to print a progress bar out to the console?
Defaults to |
likelihood_every |
Integer. Evaluate the log likelihood every n-th
iteration. Defaults to 10. See |
mh_steps |
Integer. Metropolis-Hastings proposals per token per pass.
Defaults to 1. See |
... |
Additional arguments, currently unused |
refit allows you to (a) update the probabilities (i.e. weights) of
a previously-fit model with new data or additional iterations and (b) optionally
use beta of a previously-fit LDA topic model as the eta prior
for the new model. This is tuned by setting beta_as_prior = FALSE or
beta_as_prior = TRUE respectively.
prior_weight tunes how strong the base model is represented in the prior.
If prior_weight = 1, then the tokens from the base model's training data
have the same relative weight as tokens in new_data. In other words,
it is like just adding training data. If prior_weight is less than 1,
then tokens in new_data are given more weight. If prior_weight
is greater than 1, then the tokens from the base model's training data are
given more weight.
If prior_weight is NA, then the new eta is equal to
eta from the old model, with new tokens folded in.
(For handling of new tokens, see below.) Effectively, this just controls
how the sampler initializes (described below), but does not give prior
weight to the base model.
Instead of initializing token-topic assignments in the manner for new
models (see tidylda), the update initializes in 2
steps:
First, topic-document probabilities (i.e. theta) are obtained by a
call to predict.tidylda using method = "dot"
for the documents in new_data. Next, both beta and theta are
passed to an internal function, initialize_topic_counts,
which assigns topics to tokens in a manner approximately proportional to
the posteriors and executes a single sampling iteration.
refit handles the addition of new vocabulary by adding a flat prior
over new tokens. Specifically, each entry in the new prior is equal to the
10th percentile of eta from the old model. The resulting model will
have the total vocabulary of the old model plus any new vocabulary tokens.
In other words, after running refit.tidylda ncol(beta) >= ncol(new_data)
where beta is from the new model and new_data is the additional data.
You can add additional topics by setting the additional_k parameter
to an integer greater than zero. New entries to alpha have a flat
prior equal to the median value of alpha in the old model. (Note that
if alpha itself is a flat prior, i.e. scalar, then the new topics have
the same value for their prior.) New entries to eta have a shape
from the average of all previous topics in eta and scaled by
additional_eta_sum.
Returns an S3 object of class c("tidylda").
# load a document term matrix data(nih_sample_dtm) d1 <- nih_sample_dtm[1:50, ] d2 <- nih_sample_dtm[51:100, ] # fit a model m <- tidylda(d1, k = 10, iterations = 200, burnin = 175 ) # update an existing model by adding documents using old model as prior m2 <- refit( object = m, new_data = rbind(d1, d2), iterations = 200, burnin = 175, prior_weight = 1 ) # use an old model to initialize new model and not use old model as prior m3 <- refit( object = m, new_data = d2, # new documents only iterations = 200, burnin = 175, prior_weight = NA ) # add topics while updating a model by adding documents m4 <- refit( object = m, new_data = rbind(d1, d2), additional_k = 3, iterations = 200, burnin = 175 )# load a document term matrix data(nih_sample_dtm) d1 <- nih_sample_dtm[1:50, ] d2 <- nih_sample_dtm[51:100, ] # fit a model m <- tidylda(d1, k = 10, iterations = 200, burnin = 175 ) # update an existing model by adding documents using old model as prior m2 <- refit( object = m, new_data = rbind(d1, d2), iterations = 200, burnin = 175, prior_weight = 1 ) # use an old model to initialize new model and not use old model as prior m3 <- refit( object = m, new_data = d2, # new documents only iterations = 200, burnin = 175, prior_weight = NA ) # add topics while updating a model by adding documents m4 <- refit( object = m, new_data = rbind(d1, d2), additional_k = 3, iterations = 200, burnin = 175 )
tidylda topic modelTidy the result of a tidylda topic model
## S3 method for class 'tidylda' tidy(x, matrix, log = FALSE, ...) ## S3 method for class 'matrix' tidy(x, matrix, log = FALSE, ...)## S3 method for class 'tidylda' tidy(x, matrix, log = FALSE, ...) ## S3 method for class 'matrix' tidy(x, matrix, log = FALSE, ...)
x |
an object of class |
matrix |
the matrix to tidy; one of |
log |
do you want to have the result on a log scale? Defaults to |
... |
other arguments passed to methods,currently not used |
Returns a tibble.
If matrix = "beta" then the result is a table of one row per topic
and token with the following columns: topic, token, beta
If matrix = "theta" then the result is a table of one row per document
and topic with the following columns: document, topic, theta
If matrix = "lambda" then the result is a table of one row per topic
and token with the following columns: topic, token, lambda
tidy(matrix): Tidy an individual matrix.
Useful for predictions and called from tidy.tidylda
If log = TRUE then "log_" will be appended to the name of the third
column of the resulting table. e.g "beta" becomes "log_beta".
dtm <- nih_sample_dtm lda <- tidylda(data = dtm, k = 10, iterations = 100, burnin = 75) tidy_beta <- tidy(lda, matrix = "beta") tidy_theta <- tidy(lda, matrix = "theta") tidy_lambda <- tidy(lda, matrix = "lambda")dtm <- nih_sample_dtm lda <- tidylda(data = dtm, k = 10, iterations = 100, burnin = 75) tidy_beta <- tidy(lda, matrix = "beta") tidy_theta <- tidy(lda, matrix = "theta") tidy_lambda <- tidy(lda, matrix = "lambda")
Fit a Latent Dirichlet Allocation topic model using warpLDA, a Metropolis-Hastings sampler.
tidylda( data, k, iterations = NULL, burnin = -1, alpha = 0.1, eta = 0.05, optimize_alpha = FALSE, calc_likelihood = TRUE, calc_r2 = FALSE, threads = 1, return_data = FALSE, verbose = TRUE, likelihood_every = 10, mh_steps = 1, ... )tidylda( data, k, iterations = NULL, burnin = -1, alpha = 0.1, eta = 0.05, optimize_alpha = FALSE, calc_likelihood = TRUE, calc_r2 = FALSE, threads = 1, return_data = FALSE, verbose = TRUE, likelihood_every = 10, mh_steps = 1, ... )
data |
A document term matrix or term co-occurrence matrix. The preferred
class is a |
k |
Integer number of topics. |
iterations |
Integer number of sampling iterations to run. |
burnin |
Integer number of burnin iterations. If |
alpha |
Numeric scalar or vector of length |
eta |
Numeric scalar, numeric vector of length |
optimize_alpha |
Deprecated as of version 0.1.0 and ignored. Accepted
so that existing calls keep working; passing |
calc_likelihood |
Logical. Do you want to calculate the log likelihood every iteration?
Useful for assessing convergence. Defaults to |
calc_r2 |
Logical. Do you want to calculate R-squared after the model is trained?
Defaults to |
threads |
Number of parallel threads, defaults to 1. See Details, below. |
return_data |
Logical. Do you want |
verbose |
Logical. Do you want to print a progress bar out to the console?
Defaults to |
likelihood_every |
Integer. Evaluate the log likelihood every n-th
iteration. Defaults to 10. Ignored if |
mh_steps |
Integer. Metropolis-Hastings proposals per token per pass. Defaults to 1. See 'details' below. |
... |
Additional arguments, currently unused |
Fitting uses **warpLDA** (Chen et al., https://arxiv.org/abs/1510.08628), a Metropolis-Hastings sampler that alternates document-ordered and word-ordered passes over the corpus so that each pass touches only a small, cache-resident working set. It replaces the collapsed Gibbs sampler used through version 0.0.7, and is written in Rcpp and parallelized with RcppThread. Some implementation notes follow:
Topic-token and topic-document assignments are not initialized based on a
uniform-random sampling, as is common. Instead, topic-token probabilities
(i.e. beta) are initialized by sampling from a Dirichlet distribution
with eta as its parameter. The same is done for topic-document
probabilities (i.e. theta) using alpha. Then an internal
function is called (initialize_topic_counts) to run
a single sampling iteration to initialize assignments of tokens to topics
and topics to documents.
When you use burn-in iterations (i.e. burnin = TRUE), the resulting
beta and theta matrices are calculated by averaging over every
iteration after the specified number of burn-in iterations. If you do not
use burn-in iterations, then the matrices are calculated from the last run
only. Ideally, you'd burn in every iteration before convergence, then average
over the chain after its converged (and thus every observation is independent).
optimize_alpha is deprecated as of version 0.1.0 and is ignored. It
rescaled alpha by topic size each iteration, standing in for
fixed-point estimation that was never written. alpha is now fixed
for the whole run. The argument will be removed in a future release.
Two log likelihood columns, and they answer different questions.
When calc_likelihood = TRUE, the log_likelihood slot has a
column of each.
log_likelihood is : the probability
of the observed tokens under the current estimates of theta and
beta. It is a plug-in quantity, so it improves monotonically as
topics are added and cannot be used to choose k.
log_joint is , the collapsed
joint, with theta and beta analytically integrated out. This
is the quantity most of the LDA literature reports. Integrating out the
parameters leaves a discrete distribution, so unlike a density it is always
negative, and it carries an implicit penalty for model complexity. It is
also the sampler's own target, which makes it the more informative of the
two for judging convergence.
Both condition on the current assignment of tokens to topics, so both are
within-model diagnostics. Neither is a valid basis for comparing
models to each other; that requires with the
topic assignments marginalized out, which is intractable and needs the
held-out estimators of Wallach et al. (2009).
Both are evaluated every tenth iteration by default rather than every
iteration. This is not thinning: the chain advances every iteration and
every post-burn-in iteration still contributes to the posterior means. Only
these diagnostics, which feed nothing the sampler uses, are computed less
often. Pass likelihood_every = 1 to recover a value per iteration.
Both accept eta as a scalar, a vector, or a matrix, here and in
refit.tidylda and
predict.tidylda.
mh_steps sets how many Metropolis-Hastings proposals each token
gets per pass. The default of 1 reproduces the reference implementation.
Raising it is cheaper than raising iterations by the same factor,
because the per-pass overhead — rebuilding the count matrices and the
proposal tables — is paid once per iteration however many proposals each
token receives. Measured on this package's medium benchmark corpus at
k = 100, mh_steps = 4 costs about twice a single-step
iteration rather than four times.
That is a statement about cost, not about fit. The proposal distribution is
built once per document or word type, so additional steps draw repeatedly
from the same proposal, where additional iterations rebuild it from updated
counts and alternate the two passes. Whether a short run with several steps
matches a long run with one has not been measured; treat mh_steps
as an experimental control rather than a drop-in substitute for iterations.
threads sets the number of worker threads. Results are identical at
any thread count, so it trades wall clock for cores and nothing else; a
model fitted under set.seed() is reproducible whether it was fitted
on one thread or twenty. It defaults to 1, so that tidylda never
takes cores it was not asked for – which matters when fitting many models
inside your own parallel loop.
Returns an S3 object of class tidylda. See new_tidylda.
# load some data data(nih_sample_dtm) # fit a model set.seed(12345) m <- tidylda( data = nih_sample_dtm[1:20, ], k = 5, iterations = 200, burnin = 175 ) str(m) # predict on held-out documents using Metropolis-Hastings "fold in" p1 <- predict(m, nih_sample_dtm[21:100, ], method = "mh", iterations = 200, burnin = 175 ) # predict on held-out documents using the dot product method p2 <- predict(m, nih_sample_dtm[21:100, ], method = "dot") # compare the methods barplot(rbind(p1[1, ], p2[1, ]), beside = TRUE, col = c("red", "blue"))# load some data data(nih_sample_dtm) # fit a model set.seed(12345) m <- tidylda( data = nih_sample_dtm[1:20, ], k = 5, iterations = 200, burnin = 175 ) str(m) # predict on held-out documents using Metropolis-Hastings "fold in" p1 <- predict(m, nih_sample_dtm[21:100, ], method = "mh", iterations = 200, burnin = 175 ) # predict on held-out documents using the dot product method p2 <- predict(m, nih_sample_dtm[21:100, ], method = "dot") # compare the methods barplot(rbind(p1[1, ], p2[1, ]), beside = TRUE, col = c("red", "blue"))