% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/mcml_pc.R
\name{build_mcml_pc}
\alias{build_mcml_pc}
\title{Multi-Cluster Multi-Level Aggregation for Psychometric Networks}
\usage{
build_mcml_pc(
  x,
  clusters,
  aggregation = c("scaled", "composite", "mean", "median", "loadings", "average",
    "escoufier", "cancor"),
  method = c("pcor", "glasso", "cor"),
  within = c("reestimate", "subnetwork"),
  weighting = c("equal", "strength", "eigen", "closeness", "betweenness",
    "expected_influence", "specificity", "pca", "factor", "item_total"),
  cor_method = c("pearson", "spearman", "polychoric"),
  signed = TRUE,
  id_col = NULL,
  fa_method = c("ml", "paf", "minres", "cfa"),
  ...
)
}
\arguments{
\item{x}{A \code{netobject} estimated with an undirected association
method (\code{cor}, \code{pcor}, \code{glasso}; aliases accepted) -
its \code{$data} and \code{$method} are reused - or a numeric
data.frame of raw observations (then \code{method} decides the
estimator).}

\item{clusters}{Cluster membership in any of three forms: a named list of
node-label vectors (names = cluster labels); a two-column
\code{data.frame} read by position (first column = node names, second =
group labels); or a vector of cluster labels named by node. Every node
must be assigned to exactly one cluster.}

\item{aggregation}{Character. How clusters are collapsed to the macro
network. Default \code{"scaled"}.
\describe{
\item{\code{"scaled"}}{Re-estimate the network on per-cluster scores
formed as the mean of \emph{standardized} member items (the
default; was \code{"composite"}).}
\item{\code{"composite"}}{Backward-compatible alias for
\code{"scaled"}.}
\item{\code{"mean"}}{As \code{"scaled"} but on raw (unstandardized)
item means.}
\item{\code{"median"}}{As \code{"mean"} but the per-cluster score is
the row-wise median of the items (unweighted).}
\item{\code{"loadings"}}{The scaled score path with member items
weighted by their within-cluster network strength.}
\item{\code{"average"}}{Average the item-pair edges in each
between-cluster submatrix - no scores, no re-estimation.}
\item{\code{"escoufier"}}{Escoufier RV coefficient (descriptive
multivariate similarity between blocks).}
\item{\code{"cancor"}}{First canonical correlation - an upper bound
on how related two blocks can be.}
}}

\item{method}{Character. Network estimator for the re-estimation
paths and for data.frame input: \code{"pcor"} (default),
\code{"glasso"}, or \code{"cor"} - the same vocabulary as
\code{\link{build_network}}. Ignored (with the netobject's own
method used instead) when \code{x} is a netobject and
\code{method} is not given.}

\item{within}{Character. \code{"reestimate"} (default) or
\code{"subnetwork"} (see Details).}

\item{weighting}{Character. How items are weighted inside their
cluster score (the score paths \code{"scaled"} / \code{"mean"} /
\code{"loadings"}; not \code{"median"}, which is unweighted):
\describe{
\item{\code{"equal"}}{(default) 1/m per item - the scale as
scored.}
\item{\code{"strength"}}{Mean absolute connection to the other
own-cluster members in the node-level network (what
\code{aggregation = "loadings"} selects).}
\item{\code{"eigen"}}{Leading-eigenvector weights of the
within-cluster block of the node-level network - like strength
but giving extra weight to items connected to other
well-connected items.}
\item{\code{"pca"}}{First principal component of the member
items' correlation matrix - a data-statistical weighting,
blind to the estimated network.}
\item{\code{"factor"}}{Standardized loadings of a one-factor
model per cluster - the classical latent-variable weighting.
The extraction method is chosen by \code{fa_method} and the
correlation input respects \code{cor_method} (so polychoric
factor analysis of ordinal items is one call). Clusters with
fewer than 3 items (or non-converging fits) fall back to
\code{"pca"} with a warning.}
\item{\code{"closeness"}, \code{"betweenness"}}{Within-cluster
closeness / betweenness centrality of the item in the node-level
network block (absolute weights). Betweenness can be all-zero in
densely connected clusters; equal weights are used then, with a
warning.}
\item{\code{"expected_influence"}}{Mean \emph{signed} connection
to the other own-cluster members (Robinaugh et al. 2016) - like
strength, but opposite-sign connections subtract, and negative
expected influence marks reverse-keyed items.}
\item{\code{"specificity"}}{The misfit margin: own-cluster
strength minus the strongest cross-cluster strength, floored at
0. Items that belong as much to another cluster contribute
nothing to their composite - the weighting twin of the
\code{misfit} diagnostic.}
\item{\code{"item_total"}}{Corrected item-total correlation:
each item against the mean of the other (standardized) members -
the classical scale-construction weighting.}
}
\strong{Custom weightings:} \code{weighting} also accepts a
\emph{named numeric vector} (one entry per item; absolute values
are normalized within each cluster, signs flip items when
\code{signed = TRUE}) or a \emph{function}
\code{function(W_block, data_block, nodes)} returning one numeric
weight per item, evaluated per cluster.

Network-based and data-based weightings answer different questions;
comparing them is informative - divergence means the network's view
of the cluster differs from its latent-variable view. Schemes with
inherently non-negative weights (equal, closeness, betweenness,
specificity) keep the eigenvector-based item signs; sign-carrying
schemes (eigen, pca, factor, expected_influence, item_total, custom)
use their own.}

\item{cor_method}{Character. Correlation type for estimation from raw
data: \code{"pearson"} (default), \code{"spearman"}, or
\code{"polychoric"} (needs \pkg{lavaan}; see Details).}

\item{signed}{Logical. Flip reverse-keyed items in composites
(default \code{TRUE}; see Details).}

\item{id_col}{Character vector or NULL. Identifier column(s) to drop
from data.frame input before analysis (e.g., the \code{rid}/actor
columns produced by
\code{\link{convert_sequence_format}(format = "frequency")}, whose
output otherwise feeds this function directly as per-actor behavior
profiles). Same convention as the association estimators.}

\item{fa_method}{Character. Extraction method for
\code{weighting = "factor"}:
\describe{
\item{\code{"ml"}}{(default) Maximum likelihood
(\code{stats::factanal} on the \code{cor_method}-consistent
correlation matrix).}
\item{\code{"paf"}}{Iterated principal axis factoring (SMC
start, communalities iterated on the reduced correlation
matrix).}
\item{\code{"minres"}}{Minimum residual / unweighted least
squares (uniquenesses optimized to minimize squared
off-diagonal residuals).}
\item{\code{"cfa"}}{One-factor confirmatory model in
\pkg{lavaan} (standardized loadings); with
\code{cor_method = "polychoric"} the items are declared
ordered, giving the categorical (DWLS) factor model.}
}
On well-behaved unidimensional clusters the four agree closely;
divergence indicates Heywood-prone or non-unidimensional clusters.}

\item{...}{Further arguments forwarded directly to the
\code{fa_method} backend, exactly as that backend spells them
(requires \code{weighting = "factor"}): lavaan arguments for
\code{"cfa"} (\code{estimator = "WLSMV"}, \code{missing = "fiml"},
\code{se = "robust"}, ...), \code{stats::factanal()} arguments for
\code{"ml"}, and
\code{max_iter} / \code{tol} for \code{"paf"}. Arguments managed
internally (\code{model}, \code{data}, \code{covmat},
\code{n.obs}, \code{factors}) are ignored with a warning - the
model is always the one-factor model per cluster, because the
composite needs exactly one weight per item.}
}
\value{
An object of class \code{"mcml_pc"} containing:
\describe{
\item{macro}{Cluster-level netobject (k x k, undirected).}
\item{clusters}{Named list of within-cluster netobjects
(\code{NULL} for singleton clusters).}
\item{cluster_members}{Named list of member node labels.}
\item{loadings}{Tidy item-diagnostic data frame (one row per node):
\code{node}, \code{cluster}, \code{loading} (signed own-cluster),
\code{weight}, \code{sign}, \code{max_cross},
\code{cross_cluster}, \code{misfit}. \code{NULL} only when no
node-level network is available.}
\item{node_network}{The node-level netobject the aggregation was
based on (kept for diagnostics and \code{loading_stability}).}
\item{data}{The raw data (data.frame) when available, else
\code{NULL}.}
\item{meta}{List: \code{aggregation}, \code{method},
\code{within}, \code{scale}, \code{cor_method}, \code{signed},
\code{n_nodes}, \code{n_clusters}, \code{cluster_sizes},
\code{n_misfit}, \code{n_flipped}, \code{directed = FALSE},
\code{source = "pc"}, \code{experimental = TRUE}.}
}
}
\description{
\strong{Experimental.} Aggregates a node-level psychometric network
(correlation, partial correlation, or EBICglasso) into a cluster-level
macro network plus per-cluster within networks - the MCML view that
\code{\link{build_mcml}} provides for transition networks, adapted to
the statistics of undirected association networks. The API and the
exact aggregation formulas may change between releases.

Unlike transition counts, partial correlations do not aggregate by
arithmetic: the submatrix of a pcor matrix is \emph{not} the pcor
network of the subsystem (the conditioning set changes), and averaging
pcor entries across blocks is descriptive only. The five
\code{aggregation} methods therefore have explicitly different
statuses:

\describe{
\item{\code{"average"} (descriptive)}{Macro edge A--B = mean of the
signed node-level weights between members of A and members of B;
macro diagonal = mean within-block off-diagonal weight. Needs only
the weight matrix (works on data-less netobjects). Caveat: signed
averaging can cancel opposite-sign edges; interpret as net average
association, not connectivity strength.}
\item{\code{"composite"} (re-estimated)}{Per-observation cluster
scores = (optionally standardized) mean of member variables; the
chosen \code{method} is then re-fit on the k composite columns,
so the macro network is a genuine correlation / pcor / EBICglasso
network among clusters. Requires raw data.}
\item{\code{"loadings"} (re-estimated, connectivity-weighted)}{As
\code{"composite"}, but member variables are weighted by their
within-cluster connection strength in the node-level network (the
absolute summed weight to the other members of their own cluster,
normalized to sum to 1 per cluster). Nodes that anchor their
cluster contribute more to its composite. This is Nestimate's own
weighting - related in spirit to network loadings
(Christensen & Golino 2021) but not a reimplementation of any
EGA-family estimator. Requires raw data.}
\item{\code{"rv"} (descriptive, multivariate)}{Macro edge A--B =
Escoufier's RV coefficient between the member blocks - a matrix
correlation in \verb{[0, 1]} computed from the block covariance
structure. No composites are formed and no estimator is re-fit,
so nothing is lost to averaging; signs are not represented.
Requires raw data.}
\item{\code{"canonical"} (descriptive, multivariate)}{Macro edge
A--B = the first canonical correlation between the member blocks:
the strongest linear relationship any weighting of A's items can
have with any weighting of B's items - an upper bound on what
composite methods can recover. Requires raw data.}
}
}
\details{
\strong{Item diagnostics.} Whenever raw data or a node-level network
is available, every item's connection strength to \emph{every} cluster
is computed. The \code{$loadings} table reports, per item: its signed
own-cluster loading, its composite weight, its strongest cross-cluster
loading, and a \code{misfit} flag set when the cross-cluster loading
exceeds the own-cluster loading - evidence the item is assigned to the
wrong cluster. Misfit items trigger a warning; every aggregation
silently inherits a bad membership, so fix the assignment rather than
ignoring the flag.

\strong{Reverse-keyed items.} With \code{signed = TRUE} (default),
items whose summed within-cluster association is negative are flipped
(their standardized values enter composites with weight sign -1), so a
reverse-keyed item reinforces its cluster composite instead of
cancelling it. Flips are reported in the \code{sign} column and via a
warning.

\strong{Missing data.} Composites are per-row weighted means over the
\emph{observed} members (weights renormalized per row); rows with no
observed member yield \code{NA} and are dropped by the estimator with
a message. Node-level estimation applies the estimators' own
complete-case handling.

\strong{Ordinal items.} \code{cor_method = "polychoric"} (requires the
\pkg{lavaan} package) estimates the node-level and within-cluster
networks from polychoric correlations - appropriate for Likert items.
Composites are continuous sums, so the macro re-estimation uses
Pearson correlations of the composites regardless.

\strong{Within-cluster networks} follow \code{within}:
\code{"reestimate"} (default) re-fits the estimator on the member
columns alone - the honest conditional structure of the subsystem;
\code{"subnetwork"} slices the node-level weight matrix and is
descriptive (for pcor/glasso it retains conditioning on
out-of-cluster nodes). Modes without raw data force
\code{"subnetwork"}. Singleton clusters get no within network
(\code{NULL}).

\strong{Uncertainty.} The composite/loadings macro network is a full
netobject carrying its composite data, so
\code{\link{bootstrap_network}(fit$macro)} (edge-weight CIs) and
\code{\link{vertex_bootstrap}(fit$macro)} (network-level CIs) work
directly; \code{\link{vertex_compare}(fit1$macro, fit2$macro)}
compares two groups. \code{\link{loading_stability}} quantifies how
stable the composite weights themselves are under case resampling.

All constituent networks are undirected
(\code{meta$directed = FALSE}), so renderers that auto-detect
directedness (e.g. \code{cograph::plot_mcml()}) draw the result
without arrowheads.
}
\examples{
set.seed(1)
n <- 200
sigma <- matrix(0.15, 6, 6)
sigma[1:3, 1:3] <- 0.5
sigma[4:6, 4:6] <- 0.5
diag(sigma) <- 1
z <- matrix(rnorm(n * 6), n, 6) \%*\% chol(sigma)
df <- as.data.frame(z)
names(df) <- c("a1", "a2", "a3", "b1", "b2", "b3")
clusters <- list(A = c("a1", "a2", "a3"), B = c("b1", "b2", "b3"))

fit <- build_mcml_pc(df, clusters, aggregation = "composite",
                     method = "cor")
fit$macro$weights
fit$loadings

}
\references{
Escoufier, Y. (1973). Le traitement des variables vectorielles.
\emph{Biometrics}, 29(4), 751-760.

Hotelling, H. (1936). Relations between two sets of variates.
\emph{Biometrika}, 28(3/4), 321-377.

Robinaugh, D. J., Millner, A. J., & McNally, R. J. (2016). Identifying
highly influential nodes in the complicated grief network.
\emph{Journal of Abnormal Psychology}, 125(6), 747-757.

Christensen, A. P., & Golino, H. (2021). On the equivalency of factor
and network loadings. \emph{Behavior Research Methods}, 53, 1563-1580.

Epskamp, S., & Fried, E. I. (2018). A tutorial on regularized partial
correlation networks. \emph{Psychological Methods}, 23(4), 617-634.
}
\seealso{
\code{\link{build_mcml}} for transition networks,
\code{\link{loading_stability}} for composite-weight stability,
\code{\link{bootstrap_network}} and \code{\link{vertex_bootstrap}}
for uncertainty on the macro network.
}
