% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/mmm.R
\name{build_mmm}
\alias{build_mmm}
\title{Fit a Mixed Markov Model}
\usage{
build_mmm(
  data,
  k = 2L,
  n_starts = 50L,
  max_iter = 200L,
  tol = 1e-06,
  smooth = 0.01,
  seed = NULL,
  covariates = NULL,
  covariate_effect = c("em", "posthoc"),
  estimator = c("auto", "firth", "multinom", "chisq")
)
}
\arguments{
\item{data}{A data.frame (wide format), \code{netobject}, or
\code{tna} model. For tna objects, extracts the stored data.}

\item{k}{Integer. Whole finite number of mixture components, >= 2.
Default: 2.}

\item{n_starts}{Integer. Positive whole finite number of random restarts.
Default: 50.}

\item{max_iter}{Integer. Positive whole finite maximum EM iterations per
start. Default: 200.}

\item{tol}{Numeric. Finite positive convergence tolerance. Default: 1e-6.}

\item{smooth}{Numeric. Finite non-negative Laplace smoothing constant.
Default: 0.01.}

\item{seed}{Integer or NULL. Random seed.}

\item{covariates}{Optional. Covariates integrated into the EM algorithm
to model covariate-dependent mixing proportions. Accepts a string,
character vector, formula, or data.frame (same forms as
\code{\link{build_clusters}}). For \code{netobject} or
\code{cograph_network} input, names are resolved against
\code{$metadata} first, so a typical call is
\code{build_mmm(net, k = 3, covariates = "session_label")}.
Unlike the post-hoc analysis in \code{build_clusters()}, these
covariates directly influence cluster membership during EM
estimation (see \code{covariate_effect}).}

\item{covariate_effect}{How \code{covariates} enter the model.
\code{"em"} (default) folds them into the EM as covariate-dependent
mixing proportions, so they shape the cluster fit itself (and rows
with missing covariates are dropped before fitting). \code{"posthoc"}
fits a plain mixture on every sequence and uses the covariates only
for the after-fit multinomial logit, so covariate values --- and
their missingness --- never change which clusters are found. Ignored
when \code{covariates} is \code{NULL}.}

\item{estimator}{Multinomial fitter for the post-hoc covariate
analysis (does not affect EM): \code{"auto"} (default) inspects the
cluster x covariate cross-tab and falls back to \code{"firth"} only
when any cell has fewer than 5 observations (separation risk),
otherwise the much faster \code{"multinom"}; \code{"firth"} forces
Firth's penalised likelihood via \code{brglm2::brmultinom} (finite
under separation); \code{"multinom"} forces \code{nnet::multinom}
(warns about separation risk); \code{"chisq"} runs descriptive
tests (no logit). See \code{\link{build_clusters}} for full details.}
}
\value{
An object of class \code{net_mmm} with components:
\describe{
\item{data}{The full N-row sequence frame used for estimation.}
\item{models}{List of \code{netobject}s, one per component. Each
component carries the rows assigned to that component in its
\code{$data} slot, while its transition matrix is the EM-estimated
component transition matrix.}
\item{k}{Number of components.}
\item{mixing}{Numeric vector of mixing proportions.}
\item{posterior}{N x k matrix of posterior probabilities.}
\item{assignments}{Integer vector of hard assignments (1..k).}
\item{quality}{List: \code{avepp} (per-class), \code{avepp_overall},
\code{entropy}, \code{relative_entropy},
\code{classification_error}.}
\item{log_likelihood, BIC, AIC, ICL}{Model fit statistics.}
\item{states}{Character vector of state names.}
}
}
\description{
Discovers latent subgroups with different transition dynamics using
Expectation-Maximization. Each mixture component has its own transition
matrix. Sequences are probabilistically assigned to components.
}
\section{Initial states}{

The first sequence column has special status: it is read directly as
the per-sequence initial state (\code{init_state[i] <-
match(raw_data[i, state_cols[1L]], states)}). The function does
\strong{not} scan forward to the first non-missing position, and it
does not apply any \code{na_syms}-style symbol conversion (unlike
\code{\link{build_clusters}}). The state vocabulary is built from the
unique non-\code{NA} values across all columns, so if your data uses
a sentinel character such as \code{"*"} or \code{"\%"} for missing
cells, that sentinel becomes a real state and the first column reads
it as a valid initial state. If you want padded leading missings to
be treated as missing, recode them to \code{NA} before calling
\code{build_mmm()} (then \code{match()} returns \code{NA}, which the
EM treats as an uninformative initial distribution), or left-trim the
leading missings so each sequence's first column carries an observed
state.
}

\examples{
seqs <- data.frame(V1 = sample(c("A","B","C"), 30, TRUE),
                   V2 = sample(c("A","B","C"), 30, TRUE))
mmm <- build_mmm(seqs, k = 2, n_starts = 1, max_iter = 10, seed = 1)
mmm
\donttest{
seqs <- data.frame(
  V1 = sample(LETTERS[1:3], 30, TRUE), V2 = sample(LETTERS[1:3], 30, TRUE),
  V3 = sample(LETTERS[1:3], 30, TRUE), V4 = sample(LETTERS[1:3], 30, TRUE)
)
mmm <- build_mmm(seqs, k = 2, seed = 42)
print(mmm)
summary(mmm)
}

}
\seealso{
\code{\link{compare_mmm}}, \code{\link{build_network}}
}
