| Title: | Longitudinal Additive and Multiplicative Effects Models for Networks |
|---|---|
| Description: | Additive and multiplicative effects models for both cross-sectional and longitudinal network analysis. The package provides two main functions: ame() for cross-sectional networks and lame() for longitudinal networks. It supports square and rectangular network structures. Key features include: (1) Cross-sectional network analysis via ame() with support for binary, continuous, ordinal, and count data; (2) Longitudinal network analysis via lame() with additive sender/receiver and multiplicative latent-factor effects that can evolve over time through AR(1) processes (Sewell and Chen (2015) <doi:10.1080/01621459.2014.988214>; Durante and Dunson (2014) <doi:10.1093/biomet/asu040>); (3) Handling of changing actor compositions across time periods in longitudinal models; (4) Performance improvements through C++ implementations via 'Rcpp' and 'RcppArmadillo'. |
| Authors: | Cassy Dorff [aut], Shahryar Minhas [aut, cre], Tosin Salau [aut] |
| Maintainer: | Shahryar Minhas <[email protected]> |
| License: | MIT + file LICENSE |
| Version: | 1.3.5 |
| Built: | 2026-10-08 11:13:09 UTC |
| Source: | https://github.com/netify-dev/lame |
Creates a visualization of the additive sender (row) and receiver (column) random effects from an AME or LAME model. Automatically detects whether effects are static or dynamic and provides appropriate visualization options.
ab_plot( fit, effect = c("sender", "receiver", "both"), sorted = TRUE, labels = NULL, title = NULL, time_point = NULL, plot_type = c("snapshot", "trajectory", "faceted", "ribbon"), show_actors = NULL )ab_plot( fit, effect = c("sender", "receiver", "both"), sorted = TRUE, labels = NULL, title = NULL, time_point = NULL, plot_type = c("snapshot", "trajectory", "faceted", "ribbon"), show_actors = NULL )
fit |
An object of class "ame" or "lame" from fitting an AME model |
effect |
Character string specifying which effect to plot:
"sender" (default), "receiver", or "both". "both" draws the sender
and receiver effects as two panels, each sorted on its own; for
dynamic fits it is available in the snapshot views
( |
sorted |
Logical; if TRUE (default), actors are sorted by effect
magnitude. Applies to |
labels |
Logical; if TRUE, actor labels are shown on x-axis (default TRUE
for n <= 50 actors). Applies to |
title |
Optional title for the plot ( |
time_point |
For dynamic effects, which time point to plot (default: last). Can be a numeric index, "all" for a faceted plot, or "average" for time-averaged |
plot_type |
For dynamic effects: "snapshot" (single time), "trajectory" (evolution over time), "faceted" (grid of time points), or "ribbon" (effect path with a 95\ band per period). For static effects, this parameter is ignored. |
show_actors |
Character vector of specific actors to highlight (for dynamic trajectory / ribbon plots) |
The additive effects in AME models represent:
Actor-specific tendencies to form outgoing ties. Positive values indicate actors who send more ties than expected; negative values indicate actors who send fewer ties.
Actor-specific tendencies to receive incoming ties. Positive values indicate actors who receive more ties than expected; negative values indicate actors who receive fewer ties.
For static effects, the plot displays these effects as a dot plot with vertical lines extending from zero to each effect estimate.
For dynamic effects (when fit contains a_dynamic/b_dynamic), additional options are available to visualize how effects evolve over time.
A ggplot2 object that can be further customized
Cassy Dorff, Shahryar Minhas, Tosin Salau
# Fit an AME model data(YX_nrm) fit <- ame(YX_nrm$Y, Xdyad = YX_nrm$X, nscan = 100, burn = 10, odens = 1, verbose = FALSE) # Visualize sender effects ab_plot(fit, effect = "sender") # Visualize receiver effects without sorting ab_plot(fit, effect = "receiver", sorted = FALSE)# Fit an AME model data(YX_nrm) fit <- ame(YX_nrm$Y, Xdyad = YX_nrm$X, nscan = 100, burn = 10, odens = 1, verbose = FALSE) # Visualize sender effects ab_plot(fit, effect = "sender") # Visualize receiver effects without sorting ab_plot(fit, effect = "receiver", sorted = FALSE)
Sender (a) and receiver (b) additive-effect point estimates as a sorted
lollipop chart. Mirrors ab_plot but without posterior
intervals: this is a point estimator. If the fit was produced via
ame_als(..., bootstrap = N), bootstrap 95\
error bars.
ab_plot.ame_als( fit, effect = c("sender", "receiver", "both"), top_n = Inf, ... )ab_plot.ame_als( fit, effect = c("sender", "receiver", "both"), top_n = Inf, ... )
fit |
an |
effect |
|
top_n |
integer; show only the top / bottom |
... |
reserved. |
A ggplot object.
A valued sociomatrix (Y) and matrix of nodal attributes (X) for students in community 3 of the AddHealth study.
Y: A sociomatrix in which the value of the edge corresponds to an ad-hoc measure of intensity of the relation. Note that students were only allowed to nominate up to 5 male friends and 5 female friends.
X: Matrix of students attributes, including sex, race (1=white, 2=black, 3=hispanic, 4=asian, 5=mixed/other) and grade.
Originally available at http://moreno.ss.uci.edu/data.html#adhealth
(site no longer accessible).
data(addhealthc3)data(addhealthc3)
list
A valued sociomatrix (Y) and matrix of nodal attributes (X) for students in community 9 of the AddHealth study.
Y: A sociomatrix in which the value of the edge corresponds to an ad-hoc measure of intensity of the relation. Note that students were only allowed to nominate up to 5 male friends and 5 female friends.
X: Matrix of students attributes, including sex, race (1=white, 2=black, 3=hispanic, 4=asian, 5=mixed/other) and grade.
Originally available at http://moreno.ss.uci.edu/data.html#adhealth
(site no longer accessible).
data(addhealthc9)data(addhealthc9)
list
Computes a fast point estimate of a time-varying coefficient vector
for a longitudinal network model by solving the
first-difference-penalised least-squares problem. No MCMC, no
multiplicative effects, no random effects – purely a regression
point estimate with a smoothing penalty on the coefficient path.
Useful for rapid exploration and for generating starting values for
a full lame(dynamic_beta = ...) fit.
als_dynamic_beta(Y, Xdyad, lambda = 0, intercept = TRUE)als_dynamic_beta(Y, Xdyad, lambda = 0, intercept = TRUE)
Y |
A list of |
Xdyad |
A list of |
lambda |
Non-negative smoothing parameter. Default |
intercept |
Logical; include an intercept (default
|
At this is independent per-period OLS
fits. As the solution converges to a
single pooled (constant over time).
A list with beta (a matrix of
estimates), lambda, residual_ss (sum of squared
residuals across periods), intercept, and
call. Class "als_dynamic_beta".
als_dynamic_beta is a regression-only smoother; the
returned object carries time-varying alone, no
additive () or multiplicative () AME
components. It is therefore not a special case of
lame_als (which always estimates the full AME
decomposition) and not a special case of
lame(dynamic_beta = TRUE) (which is Bayesian with
an AR(1) / RW1 / RW2 / Matern 3/2 state-space prior). Use it when
you want a fast, point-only, deterministic smoother for the
coefficient path; use lame(dynamic_beta = ...) when
you need full posterior uncertainty and additive / multiplicative
effects.
lame for the full Bayesian dynamic-
fit (AR(1) / RW1 / RW2 / Matern 3/2);
lame_als for the longitudinal AME point estimator
(static , full ).
set.seed(1) n <- 10; Tn <- 4 X <- replicate(Tn, array(rnorm(n*n*2), c(n, n, 2)), simplify = FALSE) beta_true <- rbind(seq(-1, 1, length.out = Tn), seq(0.5, -0.5, length.out = Tn)) Y <- vector("list", Tn) for (t in seq_len(Tn)) { Yt <- X[[t]][, , 1] * beta_true[1, t] + X[[t]][, , 2] * beta_true[2, t] + matrix(rnorm(n*n, 0, 0.2), n, n) diag(Yt) <- NA Y[[t]] <- Yt } fit_als <- als_dynamic_beta(Y, X, lambda = 0) # per-period LS fit_smooth <- als_dynamic_beta(Y, X, lambda = 10) # smoother pathset.seed(1) n <- 10; Tn <- 4 X <- replicate(Tn, array(rnorm(n*n*2), c(n, n, 2)), simplify = FALSE) beta_true <- rbind(seq(-1, 1, length.out = Tn), seq(0.5, -0.5, length.out = Tn)) Y <- vector("list", Tn) for (t in seq_len(Tn)) { Yt <- X[[t]][, , 1] * beta_true[1, t] + X[[t]][, , 2] * beta_true[2, t] + matrix(rnorm(n*n, 0, 0.2), n, n) diag(Yt) <- NA Y[[t]] <- Yt } fit_als <- als_dynamic_beta(Y, X, lambda = 0) # per-period LS fit_smooth <- als_dynamic_beta(Y, X, lambda = 10) # smoother path
Builds a start_vals list for ame or lame
from an ALS point estimate. This is useful when the ALS fit has already found
a good latent-space solution and the MCMC chain should start near that
solution rather than from diffuse random values.
als_start_vals(fit, jitter = 0, seed = NULL)als_start_vals(fit, jitter = 0, seed = NULL)
fit |
a fitted |
jitter |
non-negative standard deviation for independent Gaussian perturbations added to numeric starting values. Use a small positive value for multiple MCMC chains. |
seed |
optional integer seed used for the jitter. |
A list that can be passed to start_vals. For a dynamic ALS
fit it also carries rho_uv, sigma_uv, rho_ab, and
sigma_ab, so the MCMC run starts its AR(1) hyperparameters from
the ALS solution. Read these as starting values rather than estimates:
the persistences are the values the ALS smoothness penalty used (the
prior means unless prior set them), and the innovation scales are
implied by the fitted paths, which the penalty shrinks, so they run
below the posterior scale.
An MCMC routine providing a fit to an additive and multiplicative effects
(AME) regression model to cross-sectional relational data of various types.
This function supports both unipartite (square) and bipartite (rectangular)
networks. For longitudinal networks, use the lame function. The
additive and multiplicative effects framework is due to Hoff (2005, 2021).
ame( Y, Xdyad = NULL, Xrow = NULL, Xcol = NULL, rvar = TRUE, cvar = TRUE, dcor = !symmetric, nvar = TRUE, R = 0, R_row = NULL, R_col = NULL, mode = c("unipartite", "bipartite"), family = "normal", intercept = !(family == "ordinal"), symmetric = FALSE, odmax = rep(max(apply(Y > 0, 1, sum, na.rm = TRUE)), nrow(Y)), prior = list(), g = NA, seed = 6886, nscan = 10000, burn = 500, odens = 25, verbose = TRUE, gof = TRUE, custom_gof = NULL, plot = FALSE, start_vals = NULL, periodic_save = FALSE, out_file = NULL, save_interval = 0.25, posterior_opts = NULL, n_chains = 1, cores = 1, use_sparse_matrices = FALSE, method = c("mcmc", "als"), bootstrap = 0L, bootstrap_type = c("parametric", "block"), bootstrap_block_length = 1L, bootstrap_seed = NULL, multistart = c("none", "cheap", "full"), save_log_lik = FALSE, ordinal_cutpoints = c("data_induced", "explicit"), print, ..., model.name = NULL )ame( Y, Xdyad = NULL, Xrow = NULL, Xcol = NULL, rvar = TRUE, cvar = TRUE, dcor = !symmetric, nvar = TRUE, R = 0, R_row = NULL, R_col = NULL, mode = c("unipartite", "bipartite"), family = "normal", intercept = !(family == "ordinal"), symmetric = FALSE, odmax = rep(max(apply(Y > 0, 1, sum, na.rm = TRUE)), nrow(Y)), prior = list(), g = NA, seed = 6886, nscan = 10000, burn = 500, odens = 25, verbose = TRUE, gof = TRUE, custom_gof = NULL, plot = FALSE, start_vals = NULL, periodic_save = FALSE, out_file = NULL, save_interval = 0.25, posterior_opts = NULL, n_chains = 1, cores = 1, use_sparse_matrices = FALSE, method = c("mcmc", "als"), bootstrap = 0L, bootstrap_type = c("parametric", "block"), bootstrap_block_length = 1L, bootstrap_seed = NULL, multistart = c("none", "cheap", "full"), save_log_lik = FALSE, ordinal_cutpoints = c("data_induced", "explicit"), print, ..., model.name = NULL )
Y |
For unipartite: an n x n square relational matrix. For bipartite:
an nA x nB rectangular relational matrix where nA is the number of row
nodes and nB is the number of column nodes. A cross-sectional
netify object is also accepted and converted with
|
Xdyad |
For unipartite: an n x n x pd array of dyadic covariates (e.g. distance, shared group). For
bipartite: an nA x nB x pd array. A 2-D matrix (single dyadic covariate) must be wrapped as
|
Xrow |
For unipartite: an n x pr matrix of sender (row) covariates (e.g. sender's age, group).
For bipartite: an nA x pr matrix of row-node covariates. A |
Xcol |
For unipartite: an n x pc matrix of receiver (column) covariates. For bipartite:
an nB x pc matrix of column-node covariates. A |
rvar |
logical: fit row random effects (asymmetric case)? |
cvar |
logical: fit column random effects (asymmetric case)? |
dcor |
logical: fit a dyadic correlation (asymmetric case)? Note: not used for bipartite networks. |
nvar |
logical: fit nodal random effects (symmetric case)? |
R |
integer: dimension of the multiplicative effects (can be zero). For bipartite networks, this is used as the default for both R_row and R_col if they are not specified. |
R_row |
integer: for bipartite networks, dimension of row node multiplicative effects (defaults to R) |
R_col |
integer: for bipartite networks, dimension of column node multiplicative effects (defaults to R) |
mode |
character: either "unipartite" (default) for square networks or "bipartite" for rectangular networks.
Not all combinations of |
family |
character: one of "normal","binary","ordinal","cbin","frn","poisson". See the Supported family x mode combinations table below for which combinations are valid; see Details for the model assumptions behind each family. |
intercept |
logical: fit model with an intercept? |
symmetric |
logical: Is the sociomatrix symmetric by design? |
odmax |
a scalar integer or vector of length n giving the maximum number of nominations that each node may make - used for "frn" and "cbin" families |
prior |
a list containing hyperparameters for the prior distributions. Available options and their defaults:
Common usage: prior = list(Sab0 = diag(c(2, 2)), eta0 = 10) for moderate
shrinkage, or prior = list(Sab0 = diag(c(0.5, 0.5))) for tighter control.
For a unipartite cross-sectional |
g |
optional scalar for the Zellner g-prior on regression
coefficients ( |
seed |
random seed for the MCMC sampler (default 6886). The sampler
is seeded internally with this value, so results are reproducible by
default and an external |
nscan |
number of iterations of the Markov chain (beyond burn-in) |
burn |
burn in for the Markov chain. Typical use is |
odens |
output density (thinning interval) for the Markov chain.
|
verbose |
logical: print progress while running? Default TRUE. |
gof |
logical: calculate goodness of fit statistics? Setting to TRUE adds approximately 2-5% to runtime. For faster sampling without GOF overhead, set gof=FALSE and use gof() after model fitting. |
custom_gof |
optional function or list of named functions for computing custom goodness-of-fit statistics. Each function must accept a single matrix Y as input and return a numeric vector. If a single function is provided, it should return a named vector. If a list of functions is provided, each function should return a single value and will be named according to the list names. Custom statistics will be computed in addition to default statistics. Example: custom_gof = function(Y) c(density = mean(Y > 0, na.rm = TRUE)) |
plot |
accepted for signature parity with |
start_vals |
List from previous model run containing parameter starting values for new MCMC |
periodic_save |
logical: indicating whether to periodically save MCMC results |
out_file |
character vector indicating name and path in which file should be stored if periodic_save is selected. For example, on an Apple OS out_file="~/Desktop/ameFit.rda". |
save_interval |
quantile interval indicating when to save during the post-burn-in period. |
posterior_opts |
optional list of posterior draw-storage options,
usually built with |
n_chains |
integer: number of MCMC chains to run (default: 1) |
cores |
integer: number of cores for parallel chains (default: 1) |
use_sparse_matrices |
logical: use sparse matrix storage for large networks? (default: FALSE). Recommended only for truly sparse networks (< 10% non-zero entries). |
method |
character: |
bootstrap |
integer (only used when |
bootstrap_type |
character (only used when |
bootstrap_block_length |
integer: block length for the block bootstrap. |
bootstrap_seed |
optional integer seed for the bootstrap. |
multistart |
character (only used when |
save_log_lik |
logical: when |
ordinal_cutpoints |
character: cutpoint convention for
|
print |
Deprecated. Use |
... |
reserved for future use. Passing |
model.name |
optional string for model selection output |
This command provides posterior inference for parameters in AME models of cross-sectional relational data, assuming one of eight possible data types/models. The function supports both unipartite networks (square adjacency matrices) and bipartite networks (rectangular adjacency matrices with distinct row and column node sets) for single time point analysis.
Model. For a dyad the AME linear predictor is
where are regression coefficients on dyadic / nodal
covariates, is a row (sender) random effect, is
a column (receiver) random effect, and is the
multiplicative latent-factor term (rank R). The observation
model is with
specified by family (Gaussian for "normal", probit
for "binary" / "cbin", etc.). For unipartite
(symmetric = FALSE) the residual error has dyad-level
correlation between and ; for
bipartite, dyad correlation is fixed at 0.
Priors (in brief). has a Zellner-style g-prior
(g); are jointly Normal with covariance
(Inverse-Wishart prior Sab0 / eta0);
are independent Normal with covariance
(Inverse-Wishart prior with scale kappa0 * Suv0
and kappa0 degrees of freedom);
the dyad-correlation has an arc-sine prior on
(density proportional to ), updated with
Metropolis steps. See prior_summary(fit) for the priors
actually used.
Choosing R. The multiplicative rank R controls the
dimensionality of latent homophily / heterogeneity not explained
by covariates and additive effects. R = 0 fits an
additive-only social-relations model; R = 1 or 2 is
typical for small / medium networks; R > floor(n/3) is rarely
identifiable and will issue a warning. Latent factors capture
unobserved structure (clusters, hub patterns, transitive triangles
the covariates miss) and are accessed at fit$U, fit$V.
Identifiability. The latent factor term
is invariant to rotation and reflection of ; the package
canonicalises with an SVD so successive draws are interpretable.
For visual stability across posterior summaries see
procrustes_align and latent_positions.
Theoretical Foundation:
The AME model decomposes network structure into several components:
where:
: Fixed effects of dyadic/nodal covariates
: Additive sender (row) effect for node i
: Additive receiver (column) effect for node j
: Multiplicative interaction between latent factors
: Dyadic error term (may be correlated)
This specification generalizes the social relations model (Warner et al. 1979) and latent space models (Hoff et al. 2002) within a unified framework.
Prior Distributions:
The model uses conjugate and semi-conjugate priors where possible:
Regression coefficients: (g-prior)
Additive effects: jointly
Covariance: (inverse-Wishart)
Multiplicative effects: Hierarchical shrinkage via
Dyadic correlation: arc-sine prior on , density
, with Metropolis updates
The inverse-Wishart prior on allows learning correlation between
sender and receiver effects, capturing reciprocity patterns.
Note on the additive-effects variance scale: for a unipartite fit Sab0
defaults to a data-scaled matrix rather than a fixed diag(2). For the
"normal" and "poisson" families the default is
Sab0 = diag(2) * vscale, where vscale is an empirical-Bayes
moment estimate of the sender/receiver variance: the mean of the variances of
the centred row means and column means of Y (of log1p(Y) for
"poisson"). The "binary", "ordinal", "cbin" and
"frn" families apply the same idea to a probit-moment residual, but
only when start_vals is not supplied and the design has at least one
column; otherwise they fall back to Sab0 = diag(2) with
eta0 = 4. A bipartite fit always uses Sab0 = diag(2).
Call prior_summary() on a fitted object to see the prior actually used.
The data scaling matters because the inverse-Wishart prior contributes
pseudo-data on the scale of eta0 * Sab0 no matter what units Y
is in, so a fixed Sab0 = diag(2) pulls the additive-effects variances
va/vb upward whenever the true sender/receiver variance is well
below 1, most visibly at small . In Social Relations Model simulations
the data-scaled default recovers small true variances with modest bias where
a fixed diag(2) prior can nearly double them; the data-scaled prior is
mildly more conservative in the opposite regime, when the true variance is
large relative to the residual scale.
This default differs from the amen package, whose
ame(family = "nrm") leaves Sab0 = diag(2) and eta0 = 4.
To reproduce amen's additive-effects posterior, pass
prior = list(Sab0 = diag(2), eta0 = 4). The choice affects only
va, vb and (weakly) cab; ve and rho are
unchanged.
Multiplicative Effects (Latent Factors):
When R > 0, the model includes R-dimensional latent factors:
Asymmetric case: with interaction
Symmetric case: with eigendecomposition
Captures homophily, transitivity, and community structure
R chosen via model selection or set to 2-3 for visualization
Estimation Algorithm:
The model uses a Gibbs sampler with the following updates:
Sample latent Z given parameters (data augmentation for non-normal families)
Update regression coefficients via g-prior conjugate update
Update additive effects (a,b) jointly with
Update covariance from inverse-Wishart
Update multiplicative effects U,V via Gibbs or Metropolis-Hastings
Update dyadic correlation via Metropolis-Hastings
Update variance (for continuous families)
Standard Model Types:
The following data types/models are available:
"normal": A normal AME model (identity link: ).
"binary": A binary probit AME model (probit link: ).
"ordinal": An ordinal probit AME model (cumulative probit link). An intercept is not identifiable in this model.
"cbin": An AME model for censored binary data (probit link with censoring). The value of 'odmax' specifies the maximum number of links each row may have.
"frn": An AME model for fixed rank nomination networks. A higher value of the rank indicates a stronger relationship. The value of 'odmax' specifies the maximum number of links each row may have.
"poisson": An overdispersed Poisson AME model for count data:
with ,
a lognormal-mixed Poisson. The conditional mean given the latent is
; the marginal mean is , not
. On sparse count matrices (only a few dozen nonzero
cells) the multiplicative factors are weakly identified: UVPM can
differ across seeds while the fit is otherwise stable. For such data
compare seeds, check sum(fit$YPM) against the observed total, and
prefer R = 0 unless the factors reproduce. The sampler includes a
joint level move on the latent log-rates and the intercept (acceptance
rate in fit$mh_counters$pois_shift_accept) so the predicted total
settles quickly even when most cells are zero; the dyadic variance
ve still mixes slowly on such data, so use long chains.
Posterior Samples (full MCMC chains):
BETA |
Regression coefficients ( |
VC |
Variance components ( |
GOF |
Goodness-of-fit statistics (( |
Posterior Means (averaged over chain):
APM |
Additive row/sender effects (n-vector) |
BPM |
Additive column/receiver effects (m-vector); NULL for symmetric networks |
U |
Multiplicative row/sender factors (n xR matrix) |
V |
Multiplicative column/receiver factors (m xR matrix); NULL for symmetric networks |
L |
Eigenvalue matrix (R xR diagonal); symmetric networks only |
YPM |
Posterior mean of Y on response scale (for predictions and imputing missing values) |
Metadata:
family |
Model family (normal, binary, etc.) |
mode |
Network mode (unipartite or bipartite) |
symmetric |
Logical indicating if network is symmetric |
R |
Dimension of multiplicative effects |
Optional Posterior Samples (if requested via posterior_options):
U_samples |
Samples of U (n xR xiterations array) |
V_samples |
Samples of V (m xR xiterations array) |
a_samples |
Samples of row effects (n xiterations matrix) |
b_samples |
Samples of column effects (m xiterations matrix) |
Note on the latent-scale matrices:
The posterior-mean multiplicative product is stored on the fit
(UVPM, or ULUPM for symmetric fits); EZ (the expected
latent network) is not stored, to save memory. Accessors:
reconstruct_EZ(fit) - Returns linear predictor (link scale, not response scale)
reconstruct_UVPM(fit) - Returns the stored posterior-mean
multiplicative product (UVPM / ULUPM) when present,
otherwise U\
Generating posterior distributions:
Use simulate_posterior(fit, component="UV") to generate posterior samples
for components where only means are stored, or use posterior_options()
during model fitting to save full posterior samples.
model.name |
Name of the model (if provided) |
Every family is supported under
both modes. The bipartite Z-samplers live in R/rZ_bipartite.R
and dispatch per family; see also the inline comment in R/lame.R
(the rectangular samplers live in R/rZ_bipartite.R).
| family | unipartite | bipartite |
| normal | yes | yes |
| binary | yes | yes |
| ordinal | yes | yes |
| cbin | yes | yes |
| frn | yes | yes |
| poisson | yes | yes |
Symmetric (symmetric = TRUE) fits require a symmetric Y.
family = "ordinal" with symmetric = TRUE is supported via the
dedicated sampler in R/rZ_ord_sym_fc.R, which uses the
symmetric-doubled precision and mirrors upper-triangle draws to the lower
triangle so holds at every sweep. The rank-nomination
families ("cbin", "frn") model each actor's own ranked
nominations and are directed by construction, so symmetric = TRUE
is rejected for them.
Symmetric input with one triangle missing. When
symmetric = TRUE and one triangle of Y is fully NA
(the user stored only the lower or upper triangle), the symmetry validator
any(is.finite(Y - t(Y))) evaluates FALSE and the call
proceeds: the sampler then treats the populated triangle as the
symmetric data and mirrors it. This is usually intended, but if the
upper / lower triangles were meant to differ, the model is silently
fitting half the data. Audit anyNA(Y[upper.tri(Y)]) !=
anyNA(Y[lower.tri(Y)]) before calling if you are unsure.
ame() accepts a matrix directly. For long-format edgelists,
bipartite data, and covariates, use netify to build the network object
and pass that object as Y. ame() will call
netify::to_lame() internally. If you already have an igraph or
network object and only need a plain adjacency matrix,
as_lame_y is still available as a small convenience helper.
For an undirected/symmetric network, pass symmetric = TRUE; for a
rectangular two-mode network (students x courses, donors x candidates), pass
mode = "bipartite" or build the netify object with
mode = "bipartite". Xrow and Xcol accept either a
numeric matrix or a data.frame (coerced internally); Xdyad must be a
3-D array n x n x p of numeric covariates with no
Inf/NaN.
AME and ERGM are complementary tools for binary network analysis, not direct substitutes. ERGM is a class of exponential-family models built around explicit network statistics (counts of edges, mutual ties, triangles, geometrically-weighted shared partners, ...). You write the statistics you think matter, ERGM gives you their coefficients. ERGM excels when you have a substantive theory about which configurations drive tie formation.
AME models latent homophily / heterogeneity directly via
sender, receiver, and multiplicative latent-factor effects. You don't
enumerate triadic terms; the multiplicative-effects rank R
captures higher-order structure (clustering, transitivity, hub
patterns) implicitly. AME excels when (a) you have dyadic / nodal
covariates whose effects you want to interpret cleanly without ERGM
degeneracy, (b) higher-order structure is "nuisance" that you want
to absorb but not parameterise, or (c) you need a posterior
distribution over predictions for forecasting or imputation.
Practical guidance: if your research question is "do nodes that
share attribute X tend to form triangles together?", reach for
ERGM's gwesp. If your research question is "controlling for
unobserved sender / receiver heterogeneity and latent clustering,
what is the effect of dyadic covariate X?", reach for AME. The
R = 0 additive-only case is the social relations model
(Warner, Kenny, Stoto 1979); R >= 1 adds latent space.
For users coming from statnet::ergm, the rough analogues are:
| ERGM term | AME analogue |
edges |
intercept (probit link, not logit) |
nodecov("x") |
Xrow = x or Xcol = x |
nodematch("g") |
dyadic covariate via nodematch(g) into Xdyad |
nodefactor("g") |
dyadic covariate via nodefactor(g) into Xdyad (drop one level) |
absdiff("z") |
dyadic covariate via absdiff(z) into Xdyad |
mutual |
dcor = TRUE -> the rho parameter (probit-scale, not log-odds; not numerically comparable to ERGM's mutual) |
gwesp / transitivity |
R >= 1 multiplicative latent factors (not the same statistic) |
| sender activity heterogeneity | rvar = TRUE, gives a_i, va |
| receiver popularity heterog. | cvar = TRUE, gives b_j, vb
|
For family = "binary" the link is probit, so the intercept is on the
probit scale; do not compare it to an ERGM edges estimate by simple
arithmetic.
Both amen and lame export ame(); loading both
packages fires a startup warning telling you to call
lame::ame(...) or amen::ame(...) explicitly.
For default cross-sectional calls, lame::ame() follows the
amen::ame() interface: the fit$BETA slot is a
2-D [n_stored, p] matrix in both packages, so scripts that
call colMeans(fit$BETA) or apply(fit$BETA, 2, mean)
continue to work unchanged. lame additionally accepts
family = "binary" (which amen 1.4.5 no longer
accepts; amen requires "bin"). The print
argument is deprecated in favour of verbose; calls that pass
print = ... still work but warn.
The cross-sectional path has no dynamic_beta option (an
AR(1) prior on a single-period coefficient is unidentified), so the
BETA 3-D shape that lame() can produce never arises
from ame(). See lame for the longitudinal path
and the silent-aggregation hazard with 2-D apply(fit$BETA, 2, mean)
scripts under dynamic_beta = TRUE.
The regression-coefficient prior is a Zellner g-prior
(beta ~ N(0, g * sigma^2 * (XtX)^-1) where XtX is
the design cross-product). g is a top-level
argument of ame(), not an entry in prior = list(...)
(a common slip).
There is no per-coefficient prior knob. If you need student_t, horseshoe, or to centre a slope away from zero, AME does not currently expose it; the g-prior structure is the only knob.
Unknown names in prior = list(...) are warned about (a typo
like Sab = ... instead of Sab0 would otherwise be
silently dropped).
Cassy Dorff, Shahryar Minhas, Tosin Salau
lame for longitudinal models,
gof for post-hoc goodness-of-fit computation,
gof_plot for visualizing GOF results,
latent_positions for extracting latent positions as a tidy data frame,
procrustes_align for Procrustes alignment of latent positions,
summary.ame for model summaries,
coef.ame for coefficient extraction
data(YX_bin) fit <- ame(YX_bin$Y, Xdyad = YX_bin$X, burn = 10, nscan = 100, odens = 1, family = "binary", verbose = FALSE) summary(fit) # Note: you should run the Markov chain much longer in practicedata(YX_bin) fit <- ame(YX_bin$Y, Xdyad = YX_bin$X, burn = 10, nscan = 100, odens = 1, family = "binary", verbose = FALSE) summary(fit) # Note: you should run the Markov chain much longer in practice
Fits an additive and multiplicative effects (AME) model to a single cross-sectional network by iterative block coordinate descent, producing a fast point estimate with no MCMC and no credible intervals.
The estimation algorithm adapts the iterative block coordinate
descent estimator of the Social Influence Regression (SIR) model of
Hoff & Minhas (the algorithm implemented in sir::sir_alsfit() and
nicknamed "ALS" in that package) to the AME model. It is a port and
adaptation, not original lame methodology.
ame_als( Y, Xdyad = NULL, Xrow = NULL, Xcol = NULL, R = 0, family = "normal", mode = c("unipartite", "bipartite"), symmetric = FALSE, max_iter = 200, tol = 1e-06, lowrank_method = c("mm", "als", "hybrid"), non_normal_method = c("irls", "transform"), link = c("probit", "logit"), linear_solver = c("eigen", "qr", "auto"), multistart = c("none", "cheap", "full"), bootstrap = 0L, bootstrap_type = c("parametric", "block"), bootstrap_block_length = 1L, bootstrap_seed = NULL, verbose = TRUE, seed = 6886 )ame_als( Y, Xdyad = NULL, Xrow = NULL, Xcol = NULL, R = 0, family = "normal", mode = c("unipartite", "bipartite"), symmetric = FALSE, max_iter = 200, tol = 1e-06, lowrank_method = c("mm", "als", "hybrid"), non_normal_method = c("irls", "transform"), link = c("probit", "logit"), linear_solver = c("eigen", "qr", "auto"), multistart = c("none", "cheap", "full"), bootstrap = 0L, bootstrap_type = c("parametric", "block"), bootstrap_block_length = 1L, bootstrap_seed = NULL, verbose = TRUE, seed = 6886 )
Y |
a square (unipartite) or rectangular (bipartite) relational matrix.
A cross-sectional netify object is also accepted and converted with
|
Xdyad |
an |
Xrow |
an |
Xcol |
an |
R |
integer dimension of the multiplicative effects (default |
family |
one of |
mode |
|
symmetric |
logical; fit a symmetric (undirected) model. Unipartite only. |
max_iter |
maximum number of block coordinate descent iterations (default 200). |
tol |
convergence tolerance on the relative change in residual sum of
squares (default |
lowrank_method |
inner solver for the multiplicative (low-rank) block:
|
non_normal_method |
for the non-normal ALS families, |
link |
link for |
linear_solver |
solver for the regression block: |
multistart |
for |
bootstrap |
integer: if > 0, additionally run |
bootstrap_type |
character: |
bootstrap_block_length |
integer: block length for the block
bootstrap; only used when |
bootstrap_seed |
optional integer seed for the bootstrap (the point
fit uses |
verbose |
logical; print progress (default |
seed |
random seed (default |
The AME decomposition
is conditionally linear: it is a linear regression in
for fixed multiplicative factors , and the optimal rank-R
for fixed is the truncated SVD of the
residual matrix. The estimator therefore cycles, until the residual sum of
squares stabilises, through three blocks — each a monotone
(objective-non-increasing) update: a joint least-squares solve for the
intercept and regression coefficients (with a
ginv pseudoinverse fallback for rank-deficient designs);
Gauss-Seidel sweeps to convergence for the additive effects ;
and a weighted low-rank update for the multiplicative factors
via SVD (eigen-decomposition when symmetric = TRUE). The weighting
makes the multiplicative step correct for unbalanced longitudinal panels
(dyads observed at unequal numbers of time points); severely unbalanced
panels may need more iterations to converge, so raise max_iter if the
fit reports non-convergence.
For family = "normal" this is a least-squares (Gaussian maximum-
likelihood) fit — the exact global solution when R = 0, and a
local optimum of the non-convex low-rank objective when R > 0.
For "binary" and "poisson", the estimator uses an IRLS
working-response path by default, so coefficients are on the requested
link scale (binary probit/logit, Poisson log). The fixed-transform path is
still available as a faster exploratory score, but its coefficients are not
calibrated effect sizes. For R > 0 the multiplicative factor block
of the IRLS families solves a penalized (MAP) sub-problem: each factor row
carries the ridge implied by the AME prior , with the per-column prior scale estimated by an EM step (the
analog of the MCMC draw). This is what makes the estimate
well-defined: the unpenalized rank-R binary MLE does not exist
under quasi-separation, and fitting it directly inflates every
coefficient (a runaway that grows with R, with the latent variance
diverging). With the penalty the latent variance does not run away and
the slope inflation is bounded and stable in R; a residual
finite-sample (incidental-parameters) upward bias remains, on the order of
+10-15\
posterior mean). This residual is a property of the estimator class, not a
code defect: because a nonlinear-likelihood point estimator profiles the
latent factors at their joint optimum rather than integrating
them, it cannot be consistent for the regression coefficient
(Neyman-Scott). The bias is dominated by rank over-specification –
it is largest when R is set higher than the data support (the
factors then absorb noise) and is only ~5\
ame() / lame() path integrates the factors out and is
verified calibrated by simulation-based calibration, so binary
R > 0 ALS is best used as a fast exploratory / rank-selection score,
with ame(..., method = "mcmc") for final coefficient inference
(bootstrap = N gives ALS-scale intervals but reproduces, rather than
removes, this bias). Rank and ordinal families
("ordinal", "cbin",
"frn") are not supported by ALS and raise an informative error; use
ame or lame for those likelihoods.
Row/column (node) covariates. A node covariate broadcasts to a
per-actor constant, which is collinear with the additive sender/receiver
effect, so its coefficient is not identified by the objective alone. It is
identified here by an explicit constraint: the additive effects are taken
orthogonal to the node covariates, and beta_row/beta_col are
the corresponding between-actor regression coefficients (the additive
effects then carry only the residual heterogeneity). This is the standard
estimand under the assumption that the additive effects are uncorrelated
with the node covariates; if that assumption is doubtful the coefficient
absorbs the covariate-correlated part of the additive heterogeneity.
Time-varying node covariates are summarised by their per-actor mean; if a
node covariate varies within actor over time the discarded within-actor
variation triggers a warning.
Identifiability of the additive and multiplicative terms. For
R > 0 the additive term and the multiplicative term
are not separately identified by the objective alone: a
broadcast (row- or column-constant) component can sit in either, since a
pure sender effect is itself rank one. The estimator imposes the
standard AME gauge — the multiplicative term is double-centered (zero row
and column means), so all broadcast structure is carried by —
which makes the reported unique given the fitted values and
independent of the optimisation path. For a unipartite network the
double-centering means are taken over the full matrix, which includes the
structurally unobserved self-tie diagonal that the model fills in by its
low-rank completion; the additive/multiplicative split therefore carries an
dependence on that completion. On a disconnected observed-dyad
graph the additive effects additionally have a per-component level shift,
which is pinned to a precision-weighted minimum-norm gauge so that
a, b and the variance components remain reproducible. A dyadic
covariate that is itself (near) low-rank can still be partially aliased with
the multiplicative term, so keep R modest relative to the covariate
structure. This residual aliasing is intrinsic to the AME model — the MCMC
estimator resolves it only through its priors.
Choosing R. There is no automatic order-selection criterion (the
working-response objective has no likelihood, so AIC/BIC do not apply). Fit a
few values — e.g. lapply(0:4, function(r) ame_als(Y, R = r,
...)) — and inspect deviance (the residual sum of squares): it
falls steeply while real multiplicative signal is being captured and then
flattens, so the “elbow” of that curve is a reasonable choice. With
R > 0 the objective is non-convex; use multistart to guard
against local optima.
Uncertainty is obtained separately, by the bootstrap; see
ame_als_bootstrap. (The SIR paper's own primary standard
errors are Hessian-based, classical and sandwich/robust. For AME a
Hessian-based variance is awkward on two counts: without an explicit gauge
fix the rotational invariance of the multiplicative factors leaves the joint
Hessian rank-deficient, and even with a gauge fixed the Gaussian
working-response approximation used for the non-normal families leaves a
Hessian-based variance miscalibrated. The bootstrap side-steps both, so it is
preferred here.)
An object of class "ame_als": a list with the point
estimates. When R > 0 the fitted multiplicative surface is
exposed as UVPM (U L U'} for symmetric fits, which also
carry it as \code{ULUPM}; \code{U V' otherwise), matching the slot
names on MCMC fits.
estimates mu, beta, a, b, U, V
(L for symmetric models), the linear predictor EZ,
response-scale fitted values, working-scale residuals,
convergence information, and the variance-component vector VC with
five descriptive entries:
va, vb
empirical variances of the sender and receiver additive effects.
cabcovariance of the sender and receiver effects
(NA for symmetric or bipartite models).
rhodyadic residual reciprocity — the correlation between
the residuals of and — not the sender/receiver
correlation cor(a, b).
veresidual variance, on the model's own scale and
degrees-of-freedom-corrected () so it matches the MCMC posterior-mean s2. For a
binary IRLS fit the probit/logit model fixes the latent error
variance at 1 by identification, so ve is reported as
1; the working-scale GLM dispersion (about 1 under correct
specification) is kept separately as ve_working.
These are descriptive summaries of the point estimates, not random-effect
variance components. See ame_als_bootstrap for
uncertainty and vcov.ame_als for a fast analytic
covariance of the regression coefficients.
ame / lame
The ALS estimator is a fast, frequentist point estimator. It covers most
static AME workflows, and the top-level lame(..., method = "als")
dispatcher covers several dynamic workflows, but posterior-specific features
still require the MCMC estimator:
Families. ALS supports normal, binary, and
poisson. For ordinal, cbin,
and frn, fall back to ame /
lame.
Dynamic effects. lame_als itself fits a
static model pooled across time slices. The top-level dispatcher
lame(..., method = "als") routes supported dynamic requests to a
dynamic point estimator for normal, binary, and poisson panels,
including named panels where actors enter or exit: dynamic_ab,
selected intercept/dyadic/node
dynamic_beta, and AR(1) or Student-t dynamic_uv for
directed, symmetric, and bipartite panels. The snap-only
dynamic_uv = TRUE, dynamic_uv_kind = "snap" case routes to
lame_snap_als for supported normal unipartite and
bipartite panels.
Node-covariate coefficients use the same orthogonal additive-effect
decomposition as lame_als; dynamic node coefficients use
period-specific node values when selected by dynamic_beta, while
static node coefficients use per-actor means. bipartite dynamic_g
is available on the dynamic als path for normal, binary, and poisson
panels. changing actor composition requires row and column names on every
slice so actors can be aligned; smoothing penalties are broken across
actor-entry gaps. rank/censored dynamic families remain on the mcmc path. static
ame_als() / lame_als() fits still use a
single latent rank R; the dynamic bipartite ALS dispatcher
honours separate R_row and R_col values.
Priors. ALS has no priors. prior = list(...) and
g = ... are MCMC-only; the dispatcher ame(..., method = "als")
warns and ignores them.
Posterior quantities. No $BETA / $VC posterior
draws on the point fit. Use bootstrap = N for a sampling
distribution analogue; the draws are bootstrap, not Bayesian.
Multi-chain. Not applicable; n_chains is dropped.
Convergence diagnostics. No Rhat / ESS / trace_plot.
Features that work the same on ALS fits: coef,
vcov (sandwich on regression block), confint (auto-routes
bootstrap intervals when present, sandwich Wald otherwise), predict,
fitted, residuals, summary, print,
nobs, simulate.ame_als,
gof_plot.ame_als, ab_plot.ame_als,
uv_plot, latent_positions.
Cassy Dorff, Shahryar Minhas, Tosin Salau
Minhas, S. and Hoff, P. D. (2025). Decomposing Network Dynamics: Social
Influence Regression. Political Analysis. The iterative block
coordinate descent estimator adapted here originates with that work
(implemented in sir::sir_alsfit()).
lame_als for longitudinal networks,
ame_als_bootstrap for bootstrap uncertainty,
ame for the full MCMC estimator.
Y <- matrix(rnorm(400), 20, 20); diag(Y) <- NA fit <- ame_als(Y, R = 1, family = "normal", verbose = FALSE) coef(fit)Y <- matrix(rnorm(400), 20, 20); diag(Y) <- NA fit <- ame_als(Y, R = 1, family = "normal", verbose = FALSE) coef(fit)
Computes bootstrap standard errors and percentile confidence intervals for
a fast AME fit produced by ame_als or
lame_als. Two strategies are available:
parametric(default) Simulates fresh outcomes from the
fitted model and refits. For normal and IRLS (binary,
poisson) fits the simulation is on the calibrated response scale;
for a non-normal transform fit – whose estimator is a Gaussian
fit to a fixed transformed response – it is on the Gaussian working
scale. The fitted residual variance is df-corrected (mean-model degrees
of freedom) at fit time, so simulating with it keeps the replicates
centred on the point estimate.
Available for both cross-sectional and longitudinal fits.
blockResamples time slices with replacement. With
block_length = 1 slices are resampled independently;
block_length > 1 draws contiguous blocks (a moving-block
bootstrap), which preserves short-run temporal dependence. Longitudinal
fits only (requires T > 1); with few slices its intervals are
necessarily coarse.
Every replicate is refit by ame_als_refit, warm-started
from the original point estimate so that replicates do not drift to
different local optima. Replicates that error or return non-finite values
are dropped and counted (n_valid / n_total). Standard errors
are replicate column standard deviations; confidence intervals use the
percentile method.
ame_als_bootstrap( object, R = 200, type = c("parametric", "block"), block_length = 1, seed = NULL, verbose = TRUE ) boot_ame( object, R = 200, type = c("parametric", "block"), block_length = 1, seed = NULL, verbose = TRUE )ame_als_bootstrap( object, R = 200, type = c("parametric", "block"), block_length = 1, seed = NULL, verbose = TRUE ) boot_ame( object, R = 200, type = c("parametric", "block"), block_length = 1, seed = NULL, verbose = TRUE )
object |
|
R |
integer number of bootstrap replicates (default 200). |
type |
|
block_length |
block length for the block bootstrap: |
seed |
optional integer random seed. |
verbose |
logical; print progress (default |
Choice of inference. The Social Influence Regression paper of
Hoff & Minhas (2025) derives its primary standard errors from the observed
Hessian (classical and the sandwich/robust estimator
). Two features of the AME model make a Hessian-based
variance awkward here. First, without an explicit gauge fix the rank-R
multiplicative term is identified only up to a full
rotation/reflection (, ), leaving the
joint Hessian rank-deficient. Second, even with a gauge fixed, the non-normal
families are fit on a Gaussian working response, so a Hessian computed from
that working objective is not calibrated to the family likelihood. The
bootstrap side-steps both issues and is the recommended uncertainty tool
here, mirroring sir::boot_sir().
Alignment-sensitive quantities. The regression coefficients
beta, the additive effects a, b and the variance
components are rotation-invariant and are aggregated directly. The
multiplicative factors U, V are not: each replicate is
Procrustes-aligned to the original fit before its standard errors are
computed. The object stores both the raw and aligned replicate factors so
the effect of alignment can be inspected. The alignment is well-determined
only when the multiplicative singular values are well separated; with
near-equal singular values the per-column U/V standard errors
reflect an unstable rotation, and the subspace — or, for symmetric models,
the eigenvalues L — is the summary of record. For a symmetric model
the eigenvalues L of the multiplicative term are aggregated and
reported as the primary multiplicative-uncertainty summary.
The parametric bootstrap is a full parametric bootstrap of the AME
model: each replicate draws fresh additive random effects a, b
from their fitted dispersion (va, vb, cab) and fresh
residuals, holding mu, beta and the multiplicative term fixed.
Regenerating the additive effects (rather than holding the fitted a,
b fixed) is what gives the intercept and node-covariate standard
errors their actor-level sampling-variability component.
Assumptions. The block bootstrap treats the time slices as
exchangeable replicates of the static-effects model — appropriate for that
model, but not for strongly trended or serially dependent series (use the
dynamic lame there); with only a few time slices it is
necessarily coarse, its intervals correspondingly imprecise and somewhat
anti-conservative, so parametric is the default. A variance component
fit with R > 0 can still carry a small residual parametric-bootstrap
bias (the low-rank refit re-absorbs simulated noise); summary() flags
any point estimate that falls outside its interval. A binary IRLS fit can
carry a finite-sample (incidental-parameters) bias in the point estimator
itself, which the bootstrap reproduces rather than removes. The MCMC
ame / lame path gives posterior summaries when
that is the target.
An object of class "boot_ame" with components including
coefs (replicate intercept + regression coefficients), se,
ci_lo, ci_hi, point_est, param_names;
vc_* for the variance components; a_coefs, b_coefs,
se_a, se_b; U_aligned, V_aligned,
U_raw, V_raw, se_U, se_V (when R > 0);
and n_valid, n_total, type, family.
Cassy Dorff, Shahryar Minhas, Tosin Salau
Minhas, S. and Hoff, P. D. (2025). Decomposing Network Dynamics: Social
Influence Regression. Political Analysis. The block and parametric
bootstrap follow the inference scheme of sir::boot_sir() developed
for the SIR estimator.
ame_als and lame_als, both of
which accept bootstrap = N, bootstrap_type,
bootstrap_block_length, bootstrap_seed to do this
work in a single call when you are about to fit the model
anyway. ame_als_bootstrap() is the post-hoc path
(bootstrap an already-fit object without refitting from
scratch). ame_als_refit for warm-start refits;
confint.boot_ame for the bootstrap CI extractor.
Y <- replicate(6, { m <- matrix(rnorm(225), 15, 15); diag(m) <- NA; m }, simplify = FALSE) fit <- lame_als(Y, R = 1, family = "normal", verbose = FALSE) # post-hoc bootstrap of an existing fit: bt <- ame_als_bootstrap(fit, R = 50, type = "block", seed = 1, verbose = FALSE) # equivalent one-shot call: # fit_b <- lame_als(Y, R = 1, family = "normal", verbose = FALSE, # bootstrap = 50, bootstrap_type = "block", # bootstrap_seed = 1) print(bt)Y <- replicate(6, { m <- matrix(rnorm(225), 15, 15); diag(m) <- NA; m }, simplify = FALSE) fit <- lame_als(Y, R = 1, family = "normal", verbose = FALSE) # post-hoc bootstrap of an existing fit: bt <- ame_als_bootstrap(fit, R = 50, type = "block", seed = 1, verbose = FALSE) # equivalent one-shot call: # fit_b <- lame_als(Y, R = 1, family = "normal", verbose = FALSE, # bootstrap = 50, bootstrap_type = "block", # bootstrap_seed = 1) print(bt)
Refits an AME model by iterative block coordinate descent, initialised
(“warm-started”) from an existing ame_als fit. This is the
workhorse of ame_als_bootstrap: every bootstrap replicate
is refit from the original point estimate rather than from a cold random
start, which prevents replicates from converging to different local optima
or rotations and is essential for meaningful bootstrap standard errors.
ame_als_refit( object, Y_new = NULL, X_new = NULL, Z_new = NULL, max_iter = 30, tol = 1e-05, verbose = FALSE )ame_als_refit( object, Y_new = NULL, X_new = NULL, Z_new = NULL, max_iter = 30, tol = 1e-05, verbose = FALSE )
object |
an |
Y_new |
optional canonical outcome array |
X_new |
optional canonical design array |
Z_new |
optional canonical working-response array
|
max_iter |
maximum block coordinate descent iterations (default 30; fewer are needed than for a cold start). |
tol |
convergence tolerance (default |
verbose |
logical; print progress (default |
The estimation algorithm is the iterative block coordinate descent estimator
of the Social Influence Regression model of Hoff & Minhas
(sir::sir_alsfit()), adapted to the AME model, with each bootstrap
replicate warm-started from the original point estimate.
An object of class "ame_als"; see ame_als.
Cassy Dorff, Shahryar Minhas, Tosin Salau
Minhas, S. and Hoff, P. D. (2025). Decomposing Network Dynamics: Social
Influence Regression. Political Analysis. The iterative block
coordinate descent estimator refit here originates with that work
(implemented in sir::sir_alsfit()).
Y <- matrix(rnorm(400), 20, 20); diag(Y) <- NA fit <- ame_als(Y, R = 1, family = "normal", verbose = FALSE) refit <- ame_als_refit(fit, verbose = FALSE) coef(refit)Y <- matrix(rnorm(400), 20, 20); diag(Y) <- NA fit <- ame_als(Y, R = 1, family = "normal", verbose = FALSE) refit <- ame_als_refit(fit, verbose = FALSE) coef(refit)
Shows estimated memory usage for networks of given size. Memory optimization is automatic, so this is informational only.
ame_memory_settings(n_nodes, R = 2)ame_memory_settings(n_nodes, R = 2)
n_nodes |
Number of nodes in network |
R |
Rank of multiplicative effects (default: 2) |
Memory levers available in the package:
Run compact_ame() on a fitted model to drop empty slots and,
for genuinely sparse posterior means, use sparse storage via
use_sparse_matrices = TRUE
Increase odens in ame()/lame() to store fewer
posterior draws
Pass posterior_opts = list(thin_UV = ..., thin_ab = ...) to thin
the stored latent-factor and additive-effect draws
Invisibly returns memory estimates
Cassy Dorff, Shahryar Minhas, Tosin Salau
Calculate memory usage of AME model components
ame_memory_usage(fit = NULL, detailed = TRUE)ame_memory_usage(fit = NULL, detailed = TRUE)
fit |
Fitted AME model |
detailed |
Logical; show detailed breakdown (default TRUE) |
Invisibly returns data.frame with memory usage
Cassy Dorff, Shahryar Minhas, Tosin Salau
Configure options for fitting AME models. Memory efficiency is now handled automatically based on network size.
ame_options( parallel_chains = 1, verbose = TRUE, odens = 25, use_sparse_matrices = FALSE )ame_options( parallel_chains = 1, verbose = TRUE, odens = 25, use_sparse_matrices = FALSE )
parallel_chains |
Number of parallel chains to run (default: 1) |
verbose |
Logical; print progress information (default: TRUE) |
odens |
Output density - save every odens iterations (default: 25) |
use_sparse_matrices |
Logical; use sparse matrices for storing results (default: FALSE). Set to TRUE if your network is actually sparse (many zero/NA entries) and memory is a concern. |
Memory optimization features:
Redundant matrices (EZ, UVPM) are never stored - they can be reconstructed if needed
use_sparse_matrices = TRUE: Converts large matrices to sparse format
Posterior samples are always thinned appropriately
When to use sparse matrices:
Your network has < 10\
Memory usage is a critical concern
You're willing to trade computational speed for memory efficiency
Note: For dense networks (most edges observed), sparse matrices will be slower and may use more memory than dense storage.
List of options to pass to ame()
Cassy Dorff, Shahryar Minhas, Tosin Salau
# Configure options opts <- ame_options(verbose = TRUE, odens = 25) opts# Configure options opts <- ame_options(verbose = TRUE, odens = 25) opts
Run AME model with multiple parallel chains
ame_parallel( Y, n_chains = 4, cores = n_chains, combine_method = c("pool", "list"), fitter = c("auto", "ame", "lame"), ... )ame_parallel( Y, n_chains = 4, cores = n_chains, combine_method = c("pool", "list"), fitter = c("auto", "ame", "lame"), ... )
Y |
Network data matrix |
n_chains |
Number of parallel chains to run (default = 4) |
cores |
Number of CPU cores to use for parallel processing. Default is n_chains. Use 1 for sequential processing. |
combine_method |
Method for combining chains: "pool" (default) or "list" |
fitter |
Which fitter to use: |
... |
Additional arguments passed to |
If combine_method = "pool": A single ame object with pooled chains If combine_method = "list": A list of ame objects, one per chain
Cassy Dorff, Shahryar Minhas, Tosin Salau
lame_multi for the unrelated multi-panel
wrapper that fits K distinct networks with shared regression
coefficients. ame_parallel / lame_parallel run K MCMC
chains of the same model (for R-hat / ESS diagnostics);
lame_multi runs one chain across K panels with pooled beta.
# Run 2 chains sequentially data(YX_nrm) fit_parallel <- ame_parallel(YX_nrm$Y, Xdyad = YX_nrm$X, n_chains = 2, cores = 1, nscan = 100, burn = 10, odens = 1, verbose = FALSE)# Run 2 chains sequentially data(YX_nrm) fit_parallel <- ame_parallel(YX_nrm$Y, Xdyad = YX_nrm$X, n_chains = 2, cores = 1, nscan = 100, burn = 10, odens = 1, verbose = FALSE)
Convert array to list.
array_to_list(arrayObj, actorList, sliceLabel)array_to_list(arrayObj, actorList, sliceLabel)
arrayObj |
3d array object |
actorList |
list of actor names |
sliceLabel |
labels for array slices |
array in list format
Shahryar Minhas
Lightweight S3 generic so calls of the form as_draws(fit) dispatch
through R's S3 system even when the posterior package is not loaded.
When posterior is loaded, its generic of the same name is
resolved first by R's namespace search; this fallback only fires for
bare-namespace use.
as_draws(x, ...)as_draws(x, ...)
x |
a fitted |
... |
passed to the relevant method. |
An object dispatched by the relevant method (typically a
posterior::draws_array for an ame / lame fit).
Reshapes the BETA + VC posterior draws stored on an ame or
lame fit into a posterior::draws_array (or
draws_df-equivalent) suitable for downstream packages that
consume that representation. Multi-chain fits
(ame(..., n_chains = N)) are reshaped with chain as a separate
dimension; single-chain fits are returned as a single-chain
draws_array.
## S3 method for class 'ame' as_draws(x, include = c("beta", "vc"), ...) ## S3 method for class 'lame' as_draws(x, include = c("beta", "vc"), ...) ## S3 method for class 'ame_als' as_draws(x, ...)## S3 method for class 'ame' as_draws(x, include = c("beta", "vc"), ...) ## S3 method for class 'lame' as_draws(x, include = c("beta", "vc"), ...) ## S3 method for class 'ame_als' as_draws(x, ...)
x |
an |
include |
character; which parameter blocks to include. Default
|
... |
ignored. |
The reshape uses fit$chain_indicator (set when n_chains > 1)
to keep chain identity separate so within-chain Rhat / ESS estimates and
chain-coloured traceplots resolve correctly.
A posterior::draws_array (when posterior is
available) or otherwise a plain 3-D array with named dimnames.
Convenience wrapper that takes an igraph or network object and
returns the kind of matrix that ame / lame
expect: a numeric adjacency matrix with NA on the diagonal (self-ties
not modelled) and (if available) actor names preserved on the row/column
dimnames.
as_lame_y(x, na_diag = TRUE)as_lame_y(x, na_diag = TRUE)
x |
an |
na_diag |
logical: replace the diagonal with |
Plain matrices and data.frames are accepted too; data.frames are coerced
to a numeric matrix and only the diagonal is rewritten to NA.
A numeric matrix suitable to pass as Y to
ame / lame.
# plain matrices are returned with the diagonal set to NA m <- matrix(rbinom(25, 1, 0.4), 5, 5, dimnames = list(letters[1:5], letters[1:5])) as_lame_y(m) if (requireNamespace("igraph", quietly = TRUE)) { g <- igraph::sample_gnp(8, 0.3) Y <- as_lame_y(g) dim(Y) }# plain matrices are returned with the diagonal set to NA m <- matrix(rbinom(25, 1, 0.4), 5, 5, dimnames = list(letters[1:5], letters[1:5])) as_lame_y(m) if (requireNamespace("igraph", quietly = TRUE)) { g <- igraph::sample_gnp(8, 0.3) Y <- as_lame_y(g) dim(Y) }
Coefficient point-and-interval plot for an ame_als or
lame_als fit. The body builds the same frame
autoplot.lame uses, sourcing the point estimate from
coef(fit) and the interval from confint(fit) (sandwich
or bootstrap, depending on which is available). which =
"beta" is the only mode supported; which = "uv" /
"ab" return an informative error.
## S3 method for class 'ame_als' autoplot(object, which = c("beta", "uv", "ab"), conf.level = 0.95, ...) ## S3 method for class 'lame_als' autoplot(object, which = c("beta", "uv", "ab"), conf.level = 0.95, ...)## S3 method for class 'ame_als' autoplot(object, which = c("beta", "uv", "ab"), conf.level = 0.95, ...) ## S3 method for class 'lame_als' autoplot(object, which = c("beta", "uv", "ab"), conf.level = 0.95, ...)
object |
A fitted |
which |
One of |
conf.level |
Confidence level for the interval. Default
|
... |
Passed to |
A ggplot object.
For a lame fit with dynamic_beta on, returns a faceted
ggplot of the posterior mean coefficient path per period with a 95
percent credible-interval ribbon. For a static fit (no
dynamic_beta), falls back to a tidy()-driven horizontal
coefplot with posterior-mean point estimate and credible-interval
bars so that autoplot(fit) returns a ggplot regardless of fit
type.
## S3 method for class 'lame' autoplot( object, which = c("beta", "ab", "uv"), probs = c(0.025, 0.5, 0.975), coefs = NULL, ... ) ## S3 method for class 'ame' autoplot( object, which = c("beta", "ab", "uv"), probs = c(0.025, 0.5, 0.975), coefs = NULL, ... )## S3 method for class 'lame' autoplot( object, which = c("beta", "ab", "uv"), probs = c(0.025, 0.5, 0.975), coefs = NULL, ... ) ## S3 method for class 'ame' autoplot( object, which = c("beta", "ab", "uv"), probs = c(0.025, 0.5, 0.975), coefs = NULL, ... )
object |
A fitted |
which |
One of |
probs |
Length-3 vector of quantiles to plot. Default
|
coefs |
Optional character vector of coefficient names to subset. |
... |
Ignored. |
A ggplot2 object that can be further customised.
data(YX_bin_list) fit <- lame(YX_bin_list$Y, YX_bin_list$X, family = "binary", R = 0, dynamic_beta = "dyad", nscan = 60, burn = 15, odens = 5, verbose = FALSE) if (requireNamespace("ggplot2", quietly = TRUE)) { autoplot(fit) }data(YX_bin_list) fit <- lame(YX_bin_list$Y, YX_bin_list$X, family = "binary", R = 0, dynamic_beta = "dyad", nscan = 60, burn = 15, odens = 5, verbose = FALSE) if (requireNamespace("ggplot2", quietly = TRUE)) { autoplot(fit) }
A boot_ame stores replicate-level distributional summaries, not
per-cell predictions or residuals. These methods exist only to refuse the
call clearly (instead of falling through to stats::fitted.default /
stats::residuals.default, which would silently return NULL).
Apply fitted / residuals to the underlying
ame_als fit instead.
## S3 method for class 'boot_ame' fitted(object, ...) ## S3 method for class 'boot_ame' residuals(object, ...)## S3 method for class 'boot_ame' fitted(object, ...) ## S3 method for class 'boot_ame' residuals(object, ...)
object |
a |
... |
ignored. |
Never returns; raises an error.
Internal validation function that checks the format and consistency of input data for longitudinal AME models. Ensures that network data and covariates are properly formatted as lists with consistent dimensions across time periods.
check_format(Y, Xdyad=NULL, Xrow=NULL, Xcol=NULL)check_format(Y, Xdyad=NULL, Xrow=NULL, Xcol=NULL)
Y |
a list of T network matrices, where T is the number of time periods. Each element should be an n x m matrix representing the network at time t. |
Xdyad |
an optional list of T dyadic covariates. Each element can be either an n x m matrix (single covariate) or an n x m x p array (p covariates). Must have the same length as Y if provided. |
Xrow |
an optional list of T matrices of row/sender covariates. Each element should be an n x pr matrix where pr is the number of row covariates. Must have the same length as Y if provided. |
Xcol |
an optional list of T matrices of column/receiver covariates. Each element should be an m x pc matrix where pc is the number of column covariates. Must have the same length as Y if provided. |
Validates input data for longitudinal network analysis:
Verifying Y is a non-empty list of matrices
Checking that all covariates (if provided) are lists of appropriate length
Validating data types for all elements
Warning about dimension inconsistencies across time periods
The function uses informative error messages via the cli package to help users identify and correct data formatting issues.
Invisible TRUE if all checks pass. Throws an error with an informative message if any validation fails.
This is an internal function primarily used by lame() but exported
for advanced users who want to validate their data before model fitting.
Cassy Dorff, Shahryar Minhas, Tosin Salau
Extract beta path from a penalised-ALS object
## S3 method for class 'als_dynamic_beta' coef(object, ...)## S3 method for class 'als_dynamic_beta' coef(object, ...)
object |
An |
... |
Ignored. |
The matrix of estimates.
Returns posterior means of regression coefficients from a fitted AME or LAME model.
## S3 method for class 'ame' coef(object, ...) ## S3 method for class 'lame' coef(object, ...)## S3 method for class 'ame' coef(object, ...) ## S3 method for class 'lame' coef(object, ...)
object |
Fitted AME model (class |
... |
Additional arguments (ignored). |
For a static fit (the default, and any model with dynamic_beta = FALSE),
coefficients are returned as a named numeric vector computed as
colMeans(fit$BETA).
For a dynamic fit (lame(..., dynamic_beta = ...) where some
coefficient is time-varying), fit$BETA is a 3-dimensional array
[n_stored, p, T] and coef.lame returns a [p, T]
matrix of per-period posterior means. Rownames are the coefficient names;
colnames are the period labels (from names(Y) or t1, t2, ...).
Static coefficients in a dynamic fit are constant across the columns.
For binary models, these are on the probit (latent) scale. Use
predict.ame with type = "response" to get predicted
probabilities.
What coef() does not return. The multiplicative latent
positions , are not part of the coefficient vector;
they live on fit$U and fit$V (or as 3-D arrays
[n, R, T] when dynamic_uv is on). The additive
sender / receiver effects are on fit$APM and
fit$BPM. For a tidy frame of latent positions use
latent_positions; for sender / receiver lollipops use
ab_plot.
Named numeric vector (static fit) or p x T matrix
(dynamic_beta fit) of posterior mean coefficients.
vcov.ame for the posterior covariance matrix,
confint.ame for credible intervals,
summary.ame for a full summary table
Returns the point-estimated regression coefficients (intercept first) of an
ame_als fit. There is no posterior here; for uncertainty use
ame_als_bootstrap.
## S3 method for class 'ame_als' coef(object, ...)## S3 method for class 'ame_als' coef(object, ...)
object |
an |
... |
ignored. |
A named numeric vector of coefficients.
Returns the intercept and regression coefficient point estimates carried by
a boot_ame object (the estimates the bootstrap quantifies). For their
bootstrap standard errors and intervals see confint.boot_ame
and vcov.boot_ame.
## S3 method for class 'boot_ame' coef(object, ...)## S3 method for class 'boot_ame' coef(object, ...)
object |
a |
... |
ignored. |
A named numeric vector of coefficient point estimates.
Positive and negative relations between countries during the cold war
A list including the following dyadic and nodal variables:
cc: a socioarray of ordinal levels of military
cooperation (positive) and conflict (negative), every 5 years;
distance: between-country distance (in thousands of kilometers);
gdp: country gdp in dollars every 5 years;
polity: country polity every 5 years.
Xun Cao : https://polisci.la.psu.edu/people/xuc11/
Combine multiple AME chains
combine_ame_chains(chain_list, diagnostics = TRUE)combine_ame_chains(chain_list, diagnostics = TRUE)
chain_list |
List of ame fit objects from multiple chains |
diagnostics |
Logical; whether to compute convergence diagnostics (default TRUE) |
A single ame object with combined chains
Cassy Dorff, Shahryar Minhas, Tosin Salau
Optimizes AME model storage by converting matrices to sparse format.
compact_ame(fit, use_sparse_matrices = FALSE)compact_ame(fit, use_sparse_matrices = FALSE)
fit |
Fitted AME model |
use_sparse_matrices |
Logical; whether to use sparse matrix storage (default: FALSE) |
When use_sparse_matrices = TRUE, the posterior-mean matrices
YPM and EZ are converted to sparse storage via the
Matrix package, but only when a matrix's nonzero density is below
0.5 – converting a dense posterior-mean matrix would grow memory,
so denser matrices are left as ordinary dense matrices. For lame
fits, where YPM/EZ are per-period lists, the check and
conversion are applied per element. The additive-effect summaries
APM/BPM are named numeric vectors and are never converted.
Names and dimnames are preserved.
Memory-optimized AME model object
Cassy Dorff, Shahryar Minhas, Tosin Salau
Computes Gelman-Rubin R-hat and effective sample size (ESS) across two or
more independently-seeded chains, for both the regression coefficients
(BETA) and the variance components (VC). ESS is computed on
the pooled draws, so genuinely non-converged chains report a low ESS rather
than an inflated one.
compute_mcmc_diagnostics(chain_list)compute_mcmc_diagnostics(chain_list)
chain_list |
a list of fitted |
A list with rhat, ess, param_names (over
BETA and VC), n_chains and n_samples.
Cassy Dorff, Shahryar Minhas, Tosin Salau
Replaces the O(T x p^2 x n^2) nested R loop for bipartite XtX and Xty computation with a single C++ call.
compute_XtX_Xty_bip_cpp(Xlist, resid, p)compute_XtX_Xty_bip_cpp(Xlist, resid, p)
Xlist |
List of T arrays, each nA x nB x p |
resid |
3D array of residuals nA x nB x T |
p |
Number of covariates |
List with XtX (p x p) and Xty (p vector)
Eleven years of import and export data between 229 countries. The data use the SITC Rev. 1 commodity classification, aggregated at the first level (AG1).
A list consisting of a socioarray Trade and a vector
dollars2010 of inflation rates. The socioarray gives
yearly trade volume (exports and imports)
in dollars for 10 different commodity classes
for eleven years between 229 countries. This gives a five-way
array. The first index is the reporting country, so
Trade[i,j,t,k,1] is what i reports for exports to
j, but in general this is not the same as
Trade[j,i,t,k,2], what j reports as importing from i.
https://comtrade.un.org/, https://www.measuringworth.com/
Returns posterior equal-tailed quantile-based credible intervals
(not highest-posterior-density, HPD). Built directly from
quantile(object$BETA, c(alpha/2, 1-alpha/2)) and
quantile(object$VC, ...). These are Bayesian credible intervals, not
frequentist confidence intervals.
## S3 method for class 'ame' confint(object, parm = NULL, level = 0.95, ...) ## S3 method for class 'lame' confint(object, parm = NULL, level = 0.95, ...)## S3 method for class 'ame' confint(object, parm = NULL, level = 0.95, ...) ## S3 method for class 'lame' confint(object, parm = NULL, level = 0.95, ...)
object |
fitted AME / LAME model. |
parm |
character vector of parameter names, or numeric indices. When
|
level |
credible level (default 0.95). |
... |
additional arguments (ignored). |
Matrix with one row per parameter and two columns
(e.g. "2.5%", "97.5%").
These are equal-tailed quantile intervals, not HPD. For an HPD interval use
e.g. coda::HPDinterval on the columns of object$BETA and
object$VC directly.
Wald confidence intervals for the intercept and dyadic-covariate
coefficients of an ame_als fit, built from the conditional
sandwich covariance (vcov.ame_als).
## S3 method for class 'ame_als' confint(object, parm = NULL, level = 0.95, ...)## S3 method for class 'ame_als' confint(object, parm = NULL, level = 0.95, ...)
object |
an |
parm |
character vector of parameter names, or integer indices; if
|
level |
confidence level (default 0.95). |
... |
passed to |
These intervals are a fast convenience. They are conditional (the
additive and multiplicative effects are held fixed) and therefore
anti-conservative, and they cover only the regression coefficients the
sandwich covariance is defined for – not the node-covariate, additive or
multiplicative parameters. For fully-propagated intervals on all parameters,
use ame_als_bootstrap and confint.boot_ame.
A matrix with one row per coefficient and lower/upper bound columns.
ame_als_bootstrap for bootstrap intervals on all
parameters.
Bootstrap confidence intervals for the intercept and regression coefficients of a fast AME fit.
## S3 method for class 'boot_ame' confint( object, parm = NULL, level = 0.95, ci_type = c("percentile", "basic"), which = c("all", "beta", "vc", "a", "b", "U", "V"), ... )## S3 method for class 'boot_ame' confint( object, parm = NULL, level = 0.95, ci_type = c("percentile", "basic"), which = c("all", "beta", "vc", "a", "b", "U", "V"), ... )
object |
a |
parm |
character vector of parameter names, or integer indices. If
|
level |
confidence level (default 0.95). |
ci_type |
interval type: |
which |
which uncertainty channel to return:
|
... |
ignored. |
A matrix with one row per parameter and lower/upper bound columns.
Computes the design socioarray of covariate values for an AME fit
design_array_listwisedel(Xrow=NULL,Xcol=NULL,Xdyad=NULL,intercept=TRUE,n)design_array_listwisedel(Xrow=NULL,Xcol=NULL,Xdyad=NULL,intercept=TRUE,n)
Xrow |
an n x pr matrix of row covariates |
Xcol |
an n x pc matrix of column covariates |
Xdyad |
an n x n x pd array of dyadic covariates |
intercept |
logical |
n |
number of rows/columns |
an n x n x (pr+pc+pd+intercept) 3-way array
Cassy Dorff, Shahryar Minhas, Tosin Salau
For each dynamic coefficient in a dynamic_beta fit, compares the
posterior distribution of the maximum scaled first-difference
to a Monte-Carlo
approximation of the same statistic under the AR(1) prior. The returned
bf column is the tail-ratio score
, where is the 95\
quantile of . It is kept under the historical column name
for compatibility, but it is not a marginal-likelihood Bayes factor. Use it
to surface posterior temporal jumps that the AR(1) prior cannot comfortably
accommodate.
detect_change_point( fit, coefs = NULL, n_prior_sims = 2000L, threshold_bf = 10, seed = NULL )detect_change_point( fit, coefs = NULL, n_prior_sims = 2000L, threshold_bf = 10, seed = NULL )
fit |
A fitted |
coefs |
Optional character vector of coefficient names to check. Defaults to every dynamic coefficient on the fit. |
n_prior_sims |
Number of prior simulations for the null distribution.
Default |
threshold_bf |
Cutoff for the "warn" column. Default |
seed |
Optional seed for reproducibility. |
A data frame with one row per dynamic coefficient: coef,
bf (the heuristic tail-ratio score), m_post_mean (posterior
mean of ), m_prior_q95 (95\
), t_hat (period of the largest scaled jump), warn
(logical, bf > threshold_bf).
data(YX_bin_list) fit <- lame(YX_bin_list$Y, YX_bin_list$X, family = "binary", R = 0, dynamic_beta = "dyad", nscan = 60, burn = 15, odens = 5, verbose = FALSE) detect_change_point(fit)data(YX_bin_list) fit <- lame(YX_bin_list$Y, YX_bin_list$X, family = "binary", R = 0, dynamic_beta = "dyad", nscan = 60, burn = 15, odens = 5, verbose = FALSE) detect_change_point(fit)
Longitudinal relational measurements and nodal characteristics of Dutch college students, described in van de Bunt, van Duijn, and Snijders (1999). The time interval between the first four measurements was three weeks, whereas the interval between the last three was six weeks.
A list consisting of a socioarray Y and a matrix
X of static nodal attributes. The relational
measurements range from -1 to 4, indicating the following:
-1 a troubled or negative relationship
0 don't know
1 neutral relationship
2 friendly
3 friendship
4 best friends
Originally available at http://moreno.ss.uci.edu/data.html#vdb
(site no longer accessible).
Draws ndraws sample paths of length n_periods from the
dynamic_beta prior (given a kind, AR(1) hyperparameters, and an
inverse-gamma on the innovation variance) and reports the implied
distribution of common summary statistics: maximum absolute first
difference, roughness (sum of squared first differences), path range, and
correlation with time. Use this before fitting to confirm that your prior
is loose / tight enough.
dynamic_beta_prior_summary( n_periods = 10L, ndraws = 5000L, kind = c("ar1", "rw1", "rw2", "matern32"), rho_mean = 0.8, rho_sd = 0.15, rho_lower = 0, rho_upper = 0.999, sigma_shape = 2, sigma_scale = 1, matern32_length_scale = 2, threshold = 1, seed = NULL )dynamic_beta_prior_summary( n_periods = 10L, ndraws = 5000L, kind = c("ar1", "rw1", "rw2", "matern32"), rho_mean = 0.8, rho_sd = 0.15, rho_lower = 0, rho_upper = 0.999, sigma_shape = 2, sigma_scale = 1, matern32_length_scale = 2, threshold = 1, seed = NULL )
n_periods |
Length of the path (default 10). |
ndraws |
Number of paths to draw (default 5000). |
kind |
One of |
rho_mean, rho_sd
|
Prior mean/SD on |
rho_lower, rho_upper
|
Truncation bounds (AR(1) only). Default
|
sigma_shape, sigma_scale
|
Inverse-Gamma shape / scale on
|
matern32_length_scale |
Length scale for the Matérn-3/2 covariance
( |
threshold |
Cutoff for the |
seed |
Optional integer seed for reproducibility. |
For kind = "ar1", rho_mean/rho_sd are translated to a
Beta prior on the standardised . For kind = "rw1",
is fixed and only is sampled. For
kind = "rw2", the second-difference variance is sampled
and the first two values use a diffuse initial prior.
A list with components:
summaryData frame with quantile rows for max-first-diff, roughness, path range, trend correlation.
prob_max_diff_gt_thresholdEmpirical probability that the
maximum absolute first difference exceeds threshold.
rhoLength ndraws vector of sampled rho values
(NA for kinds with fixed rho).
sigmaLength ndraws vector of sampled sigma values.
pathsndraws x n_periods matrix of sample paths.
# Default prior: AR(1) with rho_mean = 0.8, rho_sd = 0.15 s <- dynamic_beta_prior_summary(n_periods = 10, ndraws = 2000, seed = 1) s$summary # what's the probability that consecutive beta_t differ by more than 1? s$prob_max_diff_gt_threshold # Tighter prior on innovation variance s_tight <- dynamic_beta_prior_summary(sigma_scale = 0.1, seed = 1) s_tight$summary# Default prior: AR(1) with rho_mean = 0.8, rho_sd = 0.15 s <- dynamic_beta_prior_summary(n_periods = 10, ndraws = 2000, seed = 1) s$summary # what's the probability that consecutive beta_t differ by more than 1? s$prob_max_diff_gt_threshold # Tighter prior on innovation variance s_tight <- dynamic_beta_prior_summary(sigma_scale = 0.1, seed = 1) s_tight$summary
Construct a sociomatrix from an edgelist. Each row of el gives the
two endpoints of an edge and, optionally, a weight in a third column
(unweighted edges default to 1).
el2sm(el,directed=TRUE,nadiag=all(el[,1]!=el[,2]))el2sm(el,directed=TRUE,nadiag=all(el[,1]!=el[,2]))
el |
a matrix in which each row contains the indices of an edge and possibly the weight for the edge |
directed |
if FALSE, then a relation is placed in both entry ij and ji of the sociomatrix, for each edge ij (or ji) |
nadiag |
put NAs on the diagonal |
a sociomatrix
lame authors
Y<-matrix(rpois(10*10,.5),10,10) ; diag(Y)<-NA E<-sm2el(Y) el2sm(E) - YY<-matrix(rpois(10*10,.5),10,10) ; diag(Y)<-NA E<-sm2el(Y) el2sm(E) - Y
Computes family-appropriate held-out predictive scores given a fit and a logical mask of cells to score. The function does not split the data for you: it expects you to have either (a) refit on a training subset and now want to score the held-out cells of the same matrix, or (b) have predicted probabilities you want scored. Both AUROC and PR-AUC are reported when applicable, alongside Brier and mean log density.
evaluate_heldout(y_obs, y_pred, mask, family = "binary")evaluate_heldout(y_obs, y_pred, mask, family = "binary")
y_obs |
Observed outcomes. For longitudinal fits, a list of
per-period matrices; for cross-sectional, a single matrix. Cells
not in |
y_pred |
Predicted probabilities / means on the response scale.
Same shape as |
mask |
Logical mask of the same shape as |
family |
Family string; used to pick the scoring rule. Defaults
to |
Workflow. The typical pattern is: mask a random sample of
dyads to NA in Y, refit (lame() handles NA
internally via data augmentation), call
predict(fit, type = "response"), then pass that prediction
alongside the original Y and the held-out mask to this
function. See the examples.
Dependencies. AUROC / PR-AUC use precrec when available; if not installed, only Brier and mean log-density are computed and a one-line note is emitted.
A one-row data frame with columns appropriate to the family:
n_eval, plus auroc + auprc + brier +
logloss (binary / cbin), or rmse + mae +
mean_logdens (normal), or mean_logdens +
rmse (poisson).
set.seed(1) n <- 25; Y <- matrix(rbinom(n*n, 1, 0.3), n, n); diag(Y) <- NA rownames(Y) <- colnames(Y) <- paste0("a", sprintf("%02d", 1:n)) # mask 20% of dyads mask <- matrix(FALSE, n, n) obs_idx <- which(!is.na(Y)) set.seed(1) mask[sample(obs_idx, floor(0.2 * length(obs_idx)))] <- TRUE Y_train <- Y; Y_train[mask] <- NA fit <- ame(Y_train, R = 0, family = "binary", burn = 15, nscan = 60, odens = 5, verbose = FALSE, plot = FALSE) y_pred <- predict(fit, type = "response") evaluate_heldout(Y, y_pred, mask, family = "binary")set.seed(1) n <- 25; Y <- matrix(rbinom(n*n, 1, 0.3), n, n); diag(Y) <- NA rownames(Y) <- colnames(Y) <- paste0("a", sprintf("%02d", 1:n)) # mask 20% of dyads mask <- matrix(FALSE, n, n) obs_idx <- which(!is.na(Y)) set.seed(1) mask[sample(obs_idx, floor(0.2 * length(obs_idx)))] <- TRUE Y_train <- Y; Y_train[mask] <- NA fit <- ame(Y_train, R = 0, family = "binary", burn = 15, nscan = 60, odens = 5, verbose = FALSE, plot = FALSE) y_pred <- predict(fit, type = "response") evaluate_heldout(Y, y_pred, mask, family = "binary")
Returns the posterior mean of the network on the response scale (YPM). For binary models, these are predicted probabilities between 0 and 1. For normal models, these are predicted continuous values. For Poisson models, these are predicted counts.
## S3 method for class 'ame' fitted(object, ...)## S3 method for class 'ame' fitted(object, ...)
object |
Fitted AME model object (class "ame"). |
... |
Additional arguments (not used). |
An n x n matrix (unipartite) or nA x nB matrix (bipartite) of
fitted values on the response scale. Diagonal entries are NA for
unipartite networks.
Cassy Dorff, Shahryar Minhas, Tosin Salau
predict.ame for predictions with type control,
residuals.ame for residuals
Returns response-scale fitted values: a single matrix for a cross-sectional
(ame_als) fit, or a list of matrices for a longitudinal
(lame_als) fit.
## S3 method for class 'ame_als' fitted(object, ...)## S3 method for class 'ame_als' fitted(object, ...)
object |
an |
... |
ignored. |
A matrix or list of matrices of fitted values.
Extract fitted values from LAME model
## S3 method for class 'lame' fitted(object, ...)## S3 method for class 'lame' fitted(object, ...)
object |
Fitted LAME model |
... |
Additional arguments |
List of fitted value matrices (one per time point)
For a fit with at least one dynamic component, evaluates how well the
h-step posterior-predictive distribution covers the actually
observed outcomes at the corresponding period(s). A well-calibrated
forecast produces approximately Uniform(0, 1) PIT values.
forecast_pit(fit, y_future, h = NULL, n_draws = NULL)forecast_pit(fit, y_future, h = NULL, n_draws = NULL)
fit |
A fitted |
y_future |
A list of length |
h |
The forecast horizon (length of |
n_draws |
Number of posterior draws to use for the forecast. Default uses all stored draws. |
Workflow: fit on periods 1:(T - h), forecast h steps
ahead, score against the held-out T - h + 1 : T observations.
Returns a numeric vector of PIT values (one per observed dyad in the
held-out periods), plus a one-row summary with the Kolmogorov-Smirnov
statistic against Uniform(0, 1) and a fraction-of-observed-dyads
coverage diagnostic.
Families. For family = "normal", the
PIT is computed analytically from the per-draw forecast variance. For
discrete families ("binary", "poisson", "ordinal")
the randomised PIT of Czado, Gneiting & Held (2009) is used. For rank
families ("cbin", "frn") PIT is not
implemented; the function returns NULL with an informational note.
Plotting. The companion plot() method on the returned
object renders a histogram with a uniform reference line. Use
ggplot2::ggplot(pit$pit) + geom_histogram() for custom plots.
A list of class forecast_pit with components
pit (numeric vector), ks_stat (KS statistic against
Uniform), ks_p (KS p-value), cover_95 (fraction of
PIT values in [0.025, 0.975]).
Czado, C., Gneiting, T., & Held, L. (2009). Predictive model assessment for count data. Biometrics, 65(4), 1254-1261.
data(YX_bin_list) Y_train <- YX_bin_list$Y[1:3] Y_test <- YX_bin_list$Y[4] X_train <- YX_bin_list$X[1:3] fit <- lame(Y_train, Xdyad = X_train, family = "binary", R = 0, dynamic_beta = "dyad", nscan = 60, burn = 15, odens = 5, verbose = FALSE) pit <- forecast_pit(fit, y_future = Y_test) pit$ks_p plot(pit)data(YX_bin_list) Y_train <- YX_bin_list$Y[1:3] Y_test <- YX_bin_list$Y[4] X_train <- YX_bin_list$X[1:3] fit <- lame(Y_train, Xdyad = X_train, family = "binary", R = 0, dynamic_beta = "dyad", nscan = 60, burn = 15, odens = 5, verbose = FALSE) pit <- forecast_pit(fit, y_future = Y_test) pit$ks_p plot(pit)
ame() and lame() use named arguments (Xrow, Xcol,
Xdyad, symmetric, etc.) rather than a formula interface. The
summary() output renders a pseudo-formula for diagnostic display, but
it is not a valid R formula and cannot be passed back to a fitting function.
## S3 method for class 'ame' formula(x, ...) ## S3 method for class 'lame' formula(x, ...)## S3 method for class 'ame' formula(x, ...) ## S3 method for class 'lame' formula(x, ...)
x |
an |
... |
ignored. |
Never returns; raises an error.
Create design array for replicate data
get_design_rep(Y, Xdyad, Xrow, Xcol, actorSet, intercept, n, N, pr, pc, pd)get_design_rep(Y, Xdyad, Xrow, Xcol, actorSet, intercept, n, N, pr, pc, pd)
Y |
dependent variable in array format |
Xdyad |
dyadic covariates in array format |
Xrow |
sender covariates in array format |
Xcol |
receiver covariates in array format |
actorSet |
vector of actors |
intercept |
logical indicating whether to include intercept |
n |
number of actors |
N |
number of replicates |
pr |
number of receiver covariates |
pc |
number of sender covariates |
pd |
number of dyadic covariates |
returns list of design array values necessary for ame_repL
Shahryar Minhas
Rebuild the (n x n x T) or (nA x nB x T) EZ cube using a per-period beta vector. Mirrors get_EZ_cpp / get_EZ_bip_cpp but accepts a (T x p) beta matrix where each row is the beta for that period.
get_EZ_dynamic_beta_cpp( Xlist, beta_full_path, a_mat, b_mat, U_cube, V_cube, G, bipartite, symmetric )get_EZ_dynamic_beta_cpp( Xlist, beta_full_path, a_mat, b_mat, U_cube, V_cube, G, bipartite, symmetric )
Xlist |
T-length list of design arrays (each n x n x p or nA x nB x p). |
beta_full_path |
(T x p) matrix of per-period beta. For coefficients that are not in the dynamic block, the rows are identical (the static beta replicated across all periods). |
a_mat |
(n_a x T) row effects (or repmat-ed static effects). |
b_mat |
(n_b x T) column effects. |
U_cube |
(n_u x R x T) row latent positions (or replicated-static). |
V_cube |
(n_v x R x T) column latent positions. |
G |
(R x R or RA x RB) interaction matrix (bipartite); identity for unipartite. |
bipartite |
TRUE/FALSE. |
symmetric |
TRUE/FALSE. |
n_a x n_b x T cube of EZ values.
Get fitted object from MCMC results
get_fit_object( APS, BPS, UVPS, YPS, BETA, VC, GOF, Xlist, actorByYr, colActorByYr = NULL, start_vals, symmetric, tryErrorChecks, model.name = NULL, U = NULL, V = NULL, dynamic_uv = FALSE, dynamic_ab = FALSE, bip = FALSE, rho_ab = NULL, rho_uv = NULL, family = NULL, odmax = NULL, nA = NULL, nB = NULL, n_time = NULL, Y_obs = NULL, G = NULL, dynamic_beta = FALSE, beta_dynamic_mask = NULL, beta_dynamic_groups = NULL, rho_beta = NULL, sigma_beta = NULL, RHO_BETA = NULL, SIGMA_BETA = NULL, dynamic_rho = FALSE, RHO = NULL, rho_path = NULL )get_fit_object( APS, BPS, UVPS, YPS, BETA, VC, GOF, Xlist, actorByYr, colActorByYr = NULL, start_vals, symmetric, tryErrorChecks, model.name = NULL, U = NULL, V = NULL, dynamic_uv = FALSE, dynamic_ab = FALSE, bip = FALSE, rho_ab = NULL, rho_uv = NULL, family = NULL, odmax = NULL, nA = NULL, nB = NULL, n_time = NULL, Y_obs = NULL, G = NULL, dynamic_beta = FALSE, beta_dynamic_mask = NULL, beta_dynamic_groups = NULL, rho_beta = NULL, sigma_beta = NULL, RHO_BETA = NULL, SIGMA_BETA = NULL, dynamic_rho = FALSE, RHO = NULL, rho_path = NULL )
APS |
summed additive sender random effects (or matrix for dynamic) |
BPS |
summed additive receiver random effects (or matrix for dynamic) |
UVPS |
summed multiplicative random effects |
YPS |
summed Y posterior predictive values |
BETA |
Matrix of draws for regression coefficient estimates |
VC |
Matrix of draws for variance estimates |
GOF |
Matrix of draws for goodness of fit calculations |
Xlist |
List based version of design array |
actorByYr |
List of actors by time point. In bipartite mode this is the per-year list of row actors. |
colActorByYr |
Bipartite only. List of column actors by time point;
defaults to |
start_vals |
start_vals for future model run |
symmetric |
logical indicating whether model is symmetric |
tryErrorChecks |
list with counts of MCMC errors |
model.name |
Name of the model (optional) |
U |
Latent sender positions (optional, for dynamic UV) |
V |
Latent receiver positions (optional, for dynamic UV) |
dynamic_uv |
logical indicating whether UV effects are dynamic |
dynamic_ab |
logical indicating whether additive effects are dynamic |
bip |
logical indicating whether the network is bipartite |
rho_ab |
temporal correlation parameter for additive effects (optional) |
rho_uv |
temporal correlation parameter for multiplicative effects (optional) |
family |
character string specifying the model family (e.g., "binary", "normal", "poisson") |
odmax |
vector of maximum ranks for ordinal or fixed rank nomination families |
nA |
number of actors in first mode (for bipartite networks) |
nB |
number of actors in second mode (for bipartite networks) |
n_time |
number of time periods (for longitudinal models) |
Y_obs |
original observed network (stored for residuals computation) |
G |
bipartite interaction matrix mapping row to column latent spaces |
dynamic_beta |
logical or scalar; whether the BETA storage is 3-D
(dynamic_beta path). Default |
beta_dynamic_mask |
logical vector marking which coefficients are dynamic. |
beta_dynamic_groups |
character vector of per-coefficient block labels
("intercept", "dyad", "row", "col"); |
rho_beta |
named numeric vector of per-block AR(1) rho values (one per dynamic block). |
sigma_beta |
named numeric vector of per-block AR(1) innovation standard deviations. |
RHO_BETA |
matrix of per-iteration rho_beta draws (rows = MCMC draw, cols = dynamic block). |
SIGMA_BETA |
matrix of per-iteration sigma_beta draws. |
dynamic_rho |
logical indicating whether residual dyadic reciprocity varies by period. |
RHO |
matrix of per-iteration, per-period dyadic reciprocity draws. |
rho_path |
numeric vector of period-specific dyadic reciprocity values. |
Fitted AME object
Shahryar Minhas
Get fitted object from MCMC results
get_start_vals( start_vals, Y, family, xP, rvar, cvar, R, odmax = NULL, bip = FALSE )get_start_vals( start_vals, Y, family, xP, rvar, cvar, R, odmax = NULL, bip = FALSE )
start_vals |
List object that is null or contains starting values |
Y |
dependent variable in array format |
family |
character vector (e.g. 'bin', 'nrm') specifying family type |
xP |
number of exogenous covariates |
rvar |
logical indicating whether to include sender random effects |
cvar |
logical indicating whether to include receiver random effects |
R |
Number of dimensions for multiplicative effects |
odmax |
vector of maximum ranks for cbin/frn families (optional) |
bip |
logical; |
In addition to the slots listed below, any of the dynamic
hyperparameter scalars rho_uv, sigma_uv, rho_ab,
and sigma_ab present in start_vals (for example from
als_start_vals) are passed through so a dynamic MCMC run
can warm-start them.
List of starting values for MCMC
Shahryar Minhas
glance
Light-weight fallback so glance(fit) dispatches through S3
even when broom or generics is not loaded.
glance(x, ...)glance(x, ...)
x |
An object to glance at. |
... |
Passed to the method. |
A one-row data frame.
ame / lame objectsOne-row data frame summarising model-level statistics, in the
broom idiom. Used by modelsummary::modelsummary() and
similar tabling tools to populate the lower goodness-of-fit panel of
a regression table.
## S3 method for class 'ame' glance(x, ...) ## S3 method for class 'lame' glance(x, ...)## S3 method for class 'ame' glance(x, ...) ## S3 method for class 'lame' glance(x, ...)
x |
A fitted |
... |
Ignored. |
A one-row data frame with columns:
nobs – number of observed dyads (NA cells excluded).
n_actors – number of distinct actors; for bipartite
fits this is the row-actor count (a 12 x 9 fit reports 12).
n_row_actors, n_col_actors – row and column
actor counts for bipartite fits (NA for unipartite).
n_periods – number of time periods (1 for ame).
n_stored – number of stored MCMC draws.
family – outcome family, such as "normal" or
"binary".
mode – "unipartite" or "bipartite".
R – latent-space dimension (or max of R_row,
R_col for bipartite).
dynamic_uv, dynamic_ab, dynamic_beta –
logicals; whether each component is time-varying.
elpd_loo – leave-one-out expected log predictive
density. Populated only when a loo object has been cached
on the fit: fit with save_log_lik = TRUE, then attach it
via fit$loo <- loo(fit). NA otherwise (calling
loo(fit) alone does not modify the fit object).
data(YX_bin_list) fit <- lame(YX_bin_list$Y, YX_bin_list$X, family = "binary", R = 0, nscan = 100, burn = 20, odens = 5, verbose = FALSE) glance(fit)data(YX_bin_list) fit <- lame(YX_bin_list$Y, YX_bin_list$X, family = "binary", R = 0, nscan = 100, burn = 20, odens = 5, verbose = FALSE) glance(fit)
ame_als / lame_als objectsOne-row data frame summarising an ALS fit, compatible with broom / modelsummary. Reports observation count, actor count, latent dimension, family, mode, ALS convergence flag, and iteration count.
## S3 method for class 'ame_als' glance(x, ...) ## S3 method for class 'lame_als' glance(x, ...)## S3 method for class 'ame_als' glance(x, ...) ## S3 method for class 'lame_als' glance(x, ...)
x |
A fitted |
... |
Ignored. |
One-row data frame with columns nobs,
n_actors, n_periods, family, mode,
R, converged, iterations, se_source.
data(YX_bin_list) Y1 <- 1 * (YX_bin_list$Y[[1]] > 0); diag(Y1) <- NA fit <- ame_als(Y = Y1, Xdyad = YX_bin_list$X[[1]], family = "binary", R = 1, verbose = FALSE) glance(fit)data(YX_bin_list) Y1 <- 1 * (YX_bin_list$Y[[1]] > 0); diag(Y1) <- NA fit <- ame_als(Y = Y1, Xdyad = YX_bin_list$X[[1]], family = "binary", R = 1, verbose = FALSE) glance(fit)
Computes goodness-of-fit statistics after model estimation by generating
posterior predictive networks from the saved MCMC samples. This is useful
when the model was fitted with gof = FALSE to speed up MCMC sampling,
or when you want to evaluate custom GOF statistics without re-running the model.
gof(fit, Y = NULL, custom_gof = NULL, nsim = 100, verbose = TRUE)gof(fit, Y = NULL, custom_gof = NULL, nsim = 100, verbose = TRUE)
fit |
An ame model object that was run with posterior sampling enabled |
Y |
Original data. For ame objects, an n x n matrix (or nA x nB for bipartite). For lame objects, a list of matrices (one per time period). If NULL, extracted from the fit object. |
custom_gof |
Optional custom GOF function(s) - same format as for ame() |
nsim |
Number of posterior predictive simulations to generate (default 100). If NULL, uses all available posterior samples. |
verbose |
Logical; print progress information |
This function requires that the model was estimated with posterior sampling of the parameters needed to generate posterior predictive datasets. Specifically, it needs:
BETA: regression coefficients
VC: variance components
For models with random effects: samples of a, b
For models with latent factors: U_samples, V_samples
To enable posterior sampling during model estimation, use:
posterior_opts = posterior_options(save_UV = TRUE, save_ab = TRUE)
Computing GOF post-hoc has several advantages:
Faster MCMC sampling (no GOF overhead)
Can experiment with different GOF statistics without re-running model
Can control number of posterior predictive simulations independently
A matrix of GOF statistics with the same format as if gof=TRUE was used during model estimation. First row contains observed statistics, subsequent rows contain posterior predictive statistics.
Cassy Dorff, Shahryar Minhas, Tosin Salau
# Run model without GOF during fitting data(YX_nrm) fit <- ame(YX_nrm$Y, Xdyad = YX_nrm$X, R = 2, gof = FALSE, nscan = 100, burn = 10, odens = 1, verbose = FALSE) # Compute GOF post-hoc gof_result <- gof(fit)# Run model without GOF during fitting data(YX_nrm) fit <- ame(YX_nrm$Y, Xdyad = YX_nrm$X, R = 2, gof = FALSE, nscan = 100, burn = 10, odens = 1, verbose = FALSE) # Compute GOF post-hoc gof_result <- gof(fit)
Plots observed network statistics against their posterior predictive distributions to assess model fit.
gof_plot( fit, type = c("auto", "static", "longitudinal"), statistics = NULL, credible.level = 0.95, ncol = 2, point.size = 2, line.size = 1, title = NULL, ... )gof_plot( fit, type = c("auto", "static", "longitudinal"), statistics = NULL, credible.level = 0.95, ncol = 2, point.size = 2, line.size = 1, title = NULL, ... )
fit |
An object of class "ame" or "lame" containing GOF statistics |
type |
Character string: "auto" (default), "static", or "longitudinal". If "auto", determined by model class. |
statistics |
Character vector of statistics to plot, or |
credible.level |
Numeric between 0 and 1; credible interval level for longitudinal plots (default 0.95) |
ncol |
Number of columns for faceted plot layout (default 2) |
point.size |
Size of points in longitudinal plots (default 2) |
line.size |
Width of lines in plots (default 1) |
title |
Optional title for the plot |
... |
Additional arguments forwarded to the ALS-specific
|
Overview:
Goodness-of-fit (GOF) assessment is crucial for network models because standard residual diagnostics are often inadequate for capturing network dependencies. This function implements posterior predictive checking by:
Computing key network statistics from the observed data
Generating multiple networks from the model's posterior predictive distribution
Computing the same statistics on simulated networks
Visualizing the comparison to identify model inadequacies
Network Statistics Evaluated:
For unipartite (square) networks:
sd.row (Out-degree heterogeneity)Standard deviation of row means. High values indicate substantial variation in how active nodes are as senders/initiators. If the model underestimates this, it may be missing important sender effects or covariates.
sd.col (In-degree heterogeneity)Standard deviation of column means. High values indicate substantial variation in node popularity as receivers. Underestimation suggests missing receiver effects or popularity-related covariates.
dyad.dep (Reciprocity/Mutuality)Correlation between Y[i,j] and Y[j,i]. Positive values indicate reciprocity
(mutual ties are more likely). The AME model captures this through the
dyadic correlation parameter rho. Poor fit here points to adjusting
the dcor parameter.
triad.dep (Transitivity/Clustering)Measures tendency for triadic closure (friend of a friend is a friend).
Calculated as correlation between Y[i,j] and sum(Y[i,k]*Y[k,j])/sqrt(n-2).
AME captures this through multiplicative effects (U,V). Poor fit suggests
increasing the latent dimension R.
For bipartite (rectangular) networks:
sd.row (Type A activity variation)Standard deviation of row means for Type A nodes. Indicates heterogeneity in how actively Type A nodes connect to Type B nodes.
sd.col (Type B popularity variation)Standard deviation of column means for Type B nodes. Indicates heterogeneity in how popular Type B nodes are with Type A nodes.
four.cycles (Bipartite clustering)Count of 4-cycles (rectangular paths A1-B1-A2-B2-A1). High values indicate that pairs of Type A nodes tend to connect to the same Type B nodes. Captured through bipartite multiplicative effects with appropriate R_row, R_col.
Interpretation Guide:
Histogram plots (static models):
Dashed orange vertical line (Okabe-Ito #D55E00): observed statistic
value (dual-encoded on colour and linetype)
Grey histogram: distribution from posterior predictive simulations
Good fit: orange line falls within the bulk of the histogram
Poor fit: orange line in the tail or outside the distribution
Common model inadequacies and solutions:
Model underestimates degree heterogeneity. Solutions: Add row/column covariates (Xrow, Xcol), enable random effects (rvar=TRUE, cvar=TRUE), or increase their variance.
Reciprocity not captured well. Solutions: For positive reciprocity, ensure dcor=TRUE. For negative, consider transformation or different family.
Clustering/transitivity underestimated. Solutions: Increase latent dimension R, add network covariates that capture homophily, or consider including community structure covariates.
Fundamental model misspecification. Solutions: Change family, add missing covariates, or consider different model class.
Mathematical Details:
The posterior predictive p-value for statistic s is:
where Y_rep is drawn from the posterior predictive distribution. Values near 0 or 1 indicate poor fit. The function visualizes the full distribution rather than just p-values for richer diagnostics.
Customization:
The function accepts custom GOF statistics through the model's custom_gof argument. These are automatically included in the plot. Custom statistics should capture network features important for your specific application.
Computational Notes:
GOF computation involves simulating multiple networks, which can be computationally intensive. The model uses the networks simulated during MCMC if gof=TRUE was specified. For post-hoc GOF, use the gof() function which generates new simulations.
Good model fit is indicated when:
Observed statistics fall within the central 95% of posterior predictive distributions
No systematic patterns of over/underestimation across statistics
Custom statistics (if provided) also show adequate fit
For longitudinal models, observed trajectories track within credible bands
A ggplot2 object that can be further customized
Cassy Dorff, Shahryar Minhas, Tosin Salau
# Fit an AME model data(YX_nrm) fit_ame <- ame(YX_nrm$Y, Xdyad = YX_nrm$X, gof = TRUE, nscan = 100, burn = 10, odens = 1, verbose = FALSE) # Basic GOF plot gof_plot(fit_ame) # Plot only degree-related statistics gof_plot(fit_ame, statistics = c("sd.row", "sd.col"))# Fit an AME model data(YX_nrm) fit_ame <- ame(YX_nrm$Y, Xdyad = YX_nrm$X, gof = TRUE, nscan = 100, burn = 10, odens = 1, verbose = FALSE) # Basic GOF plot gof_plot(fit_ame) # Plot only degree-related statistics gof_plot(fit_ame, statistics = c("sd.row", "sd.col"))
Bootstrap-style analogue of the MCMC gof_plot: draws
nsim simulated networks from the fitted ALS model, computes the
standard network statistics (sd.rowmean, sd.colmean,
dyad.dep, cycle.dep, trans.dep for unipartite;
sd.rowmean, sd.colmean, four.cycles for bipartite) on
each replicate, and overlays the observed value on a histogram of replicate
values.
gof_plot.ame_als(fit, nsim = 100, seed = NULL, ...)gof_plot.ame_als(fit, nsim = 100, seed = NULL, ...)
fit |
an |
nsim |
integer; number of replicates (default 100). |
seed |
optional RNG seed. |
... |
reserved. |
Uses simulate.ame_als for the replicates and is therefore
conditional on the fitted point estimates: the noise is resampled, but
mu, beta, a, b, U, V are held fixed. The MCMC gof_plot.ame
also averages over posterior movement in those parameters.
A ggplot (or patchwork) object.
Calculates goodness of fit statistics for relational data matrices, evaluating second-order (dyadic) and third-order (triadic) dependence patterns. Can handle both unipartite and bipartite networks.
gof_stats(Y, mode = NULL, custom_gof = NULL)gof_stats(Y, mode = NULL, custom_gof = NULL)
Y |
a relational data matrix. For unipartite networks, a square n x n matrix where Y\[i,j\] represents the relationship from node i to node j. For bipartite networks, an nA x nB matrix where Y\[i,j\] represents the relationship from node i in set A to node j in set B. Missing values (NA) are allowed and will be handled appropriately. |
mode |
character string specifying the network type: "unipartite" or "bipartite". If NULL (default), attempts to infer from matrix dimensions (rectangular = bipartite, square = unipartite). Note: square bipartite networks must specify mode="bipartite". |
custom_gof |
optional function or list of functions to compute custom GOF statistics. Each function should take Y as input and return a named numeric value or vector. Custom statistics will be added to the standard statistics. |
The function computes network statistics that capture different aspects of network structure beyond simple density. These statistics are particularly useful for:
Model checking: comparing observed statistics to those from simulated networks
Model selection: choosing between models that better capture network dependencies
Descriptive analysis: summarizing key structural features of the network
For bipartite networks with square dimensions (nA = nB), you must explicitly specify mode="bipartite" to ensure correct statistics are calculated.
Missing values in Y are handled by pairwise deletion for correlations and are excluded from matrix products in triadic calculations.
A named numeric vector containing goodness-of-fit statistics. For unipartite networks:
Standard deviation of row means. Measures the heterogeneity in out-degree centrality (sender effects).
Standard deviation of column means. Measures the heterogeneity in in-degree centrality (receiver effects).
Dyadic dependence/reciprocity correlation.
Cyclic/transitive triadic dependence.
Transitive triadic dependence.
For bipartite networks:
Standard deviation of row means (sender heterogeneity).
Standard deviation of column means (receiver heterogeneity).
Count of four-cycles in the bipartite network.
If custom_gof is provided, additional statistics will be included with their user-specified names.
Naming note. The columns above are the internal names used by
gof_stats() and stored on fit$GOF. gof_plot
exposes a shorter user-facing alias for some of them; the mapping is:
| internal (this column) | gof_plot alias |
sd.rowmean |
sd.row |
sd.colmean |
sd.col |
dyad.dep |
dyad.dep |
cycle.dep |
triad.dep |
trans.dep |
trans.dep |
four.cycles (bipartite) |
four.cycles
|
Cassy Dorff, Shahryar Minhas, Tosin Salau
data(YX_nrm) # Auto-detect unipartite gof_stats(YX_nrm$Y) # Bipartite (rectangular) networks are auto-detected; mode can also # be given explicitly (required when a bipartite network is square) Y_bip <- matrix(rnorm(120), 10, 12) gof_stats(Y_bip, mode = "bipartite") # Custom GOF function my_stat <- function(Y) { c(my_measure = sum(Y > 0, na.rm = TRUE)) } gof_stats(YX_nrm$Y, custom_gof = my_stat)data(YX_nrm) # Auto-detect unipartite gof_stats(YX_nrm$Y) # Bipartite (rectangular) networks are auto-detected; mode can also # be given explicitly (required when a bipartite network is square) Y_bip <- matrix(rnorm(120), 10, 12) gof_stats(Y_bip, mode = "bipartite") # Custom GOF function my_stat <- function(Y) { c(my_measure = sum(Y > 0, na.rm = TRUE)) } gof_stats(YX_nrm$Y, custom_gof = my_stat)
Calculates goodness of fit statistics specifically designed for bipartite networks, evaluating degree heterogeneity and higher-order dependencies.
gof_stats_bipartite(Y, warn_square = TRUE)gof_stats_bipartite(Y, warn_square = TRUE)
Y |
a bipartite relational data matrix (nA x nB rectangular matrix) where Y\[i,j\] represents the relationship from node i in set A to node j in set B. Missing values (NA) are allowed and will be handled appropriately. |
warn_square |
logical; if |
For bipartite networks, reciprocity and triadic closure are not meaningful concepts since edges only exist between the two node sets. Instead, this function focuses on:
Degree heterogeneity in both node sets
Four-cycles as the simplest higher-order dependence pattern
A named numeric vector containing bipartite-specific goodness-of-fit statistics:
Standard deviation of row means. Measures the heterogeneity in out-degree from set A nodes (sender effects). Higher values indicate more variation in how active A nodes are.
Standard deviation of column means. Measures the heterogeneity in in-degree to set B nodes (receiver effects). Higher values indicate more variation in how popular B nodes are.
Count of four-cycles (also called 4-paths or squares) in the bipartite network. A four-cycle occurs when two nodes from set A (e.g., i and k) both connect to the same two nodes in set B (e.g., j and l), forming a closed path: i->j->k->l->i. This measures the tendency for pairs of A-nodes to share multiple common B-node connections, capturing a form of clustering specific to bipartite networks. High four-cycle counts indicate that connections are not random but show patterns of shared preferences or co-occurrence. For example, in a user-item network, many four-cycles suggest that users who like one item tend to also like other items that co-occur with it.
Cassy Dorff, Shahryar Minhas, Tosin Salau
# Create a random bipartite network Y <- matrix(rnorm(10*12), 10, 12) # Calculate GOF statistics gof_stats_bipartite(Y)# Create a random bipartite network Y <- matrix(rnorm(10*12), 10, 12) # Calculate GOF statistics gof_stats_bipartite(Y)
Calculates goodness of fit statistics specifically for unipartite (square) networks, evaluating second-order (dyadic) and third-order (triadic) dependence patterns.
gof_stats_unipartite(Y)gof_stats_unipartite(Y)
Y |
a square n x n relational data matrix where |
This function computes network statistics that capture different aspects of network structure beyond simple density. These statistics are particularly useful for evaluating how well a model captures the observed network patterns.
The dyadic dependence statistic captures reciprocity - the tendency for relationships to be mutual. The triadic statistics capture different forms of triadic closure that are common in social networks.
Missing values in Y are handled by pairwise deletion for correlations and are excluded from matrix products in triadic calculations.
A named numeric vector containing five goodness-of-fit statistics:
Standard deviation of row means. Measures the heterogeneity in out-degree centrality (sender effects).
Standard deviation of column means. Measures the heterogeneity in in-degree centrality (receiver effects).
Dyadic dependence/reciprocity correlation. Measures the
correlation between Y[i,j] and Y[j,i], capturing reciprocity patterns.
Cyclic triadic dependence. Measures the tendency for directed cycles (i->j->k->i) in the network.
Transitive triadic dependence. Measures the tendency for transitivity (if i->j and j->k, then i->k) in the network.
Cassy Dorff, Shahryar Minhas, Tosin Salau
# Create a random unipartite network Y <- matrix(rnorm(100), 10, 10) diag(Y) <- NA gof_stats_unipartite(Y)# Create a random unipartite network Y <- matrix(rnorm(100), 10, 10) diag(Y) <- NA gof_stats_unipartite(Y)
For a fitted lame object, computes a network statistic
(density, reciprocity, or transitivity) at each
observed period, fits a least-squares linear trend on period index,
and compares the observed slope to slopes from posterior-predictive
replicates. The two-sided value is p_pp = 2 * min(p_up, 1 - p_up),
which runs from 0 (observed slope in the extreme tail) to 1 (observed
slope dead-centre). A static fit on truly trending data yields
p_pp near 0; a dynamic fit that captures the trend yields
p_pp near 1.
gof_temporal( fit, stat = c("auto", "density", "mean", "reciprocity", "transitivity"), n_rep = 500, seed = NULL )gof_temporal( fit, stat = c("auto", "density", "mean", "reciprocity", "transitivity"), n_rep = 500, seed = NULL )
fit |
A fitted |
stat |
One of |
n_rep |
Number of posterior-predictive replicates to draw (each
replicate is a full |
seed |
Optional RNG seed. |
A list with
stat (chosen statistic name),
slope_obs (observed slope of stat on period index),
slope_rep (length-n_rep vector of replicate slopes),
p_pp (two-sided posterior-predictive p-value),
stat_obs_by_t, stat_rep_by_t (per-period statistics)
data(YX_bin_list) fit <- lame(YX_bin_list$Y, YX_bin_list$X, family = "binary", R = 0, dynamic_beta = "dyad", nscan = 60, burn = 15, odens = 5, verbose = FALSE) gof_temporal(fit, stat = "density", n_rep = 50)data(YX_bin_list) fit <- lame(YX_bin_list$Y, YX_bin_list$X, family = "binary", R = 0, dynamic_beta = "dyad", nscan = 60, burn = 15, odens = 5, verbose = FALSE) gof_temporal(fit, stat = "density", n_rep = 50)
Initialize dynamic additive effects with AR(1) structure
init_dynamic_ab_cpp(n, Tn, rho_ab, sigma_ab, mean_a = 0, mean_b = 0)init_dynamic_ab_cpp(n, Tn, rho_ab, sigma_ab, mean_a = 0, mean_b = 0)
n |
Number of actors |
Tn |
Number of time points |
rho_ab |
AR(1) parameter |
sigma_ab |
Innovation standard deviation |
mean_a |
Mean for row effects |
mean_b |
Mean for column effects |
List with initialized a and b matrices
Initialize dynamic latent positions with AR(1) structure
init_dynamic_positions(n, R, Tn, rho_uv, sigma_uv)init_dynamic_positions(n, R, Tn, rho_uv, sigma_uv)
n |
Number of actors |
R |
Latent dimension |
Tn |
Number of time points |
rho_uv |
AR(1) parameter |
sigma_uv |
Innovation standard deviation |
3D array of latent positions (n x R x Tn)
A relational dataset recording a variety of nodal and dyadic variables on countries in the 1990s, including information on conflicts, trade and other variables. Except for the conflict variable, the variables are averages across the decade.
A list consisting of a socioarray dyadvars of
dyadic variables and matrix nodevars of nodal variables.
The dyadic variables include
total number of conflicts;
exports (in billions of dollars);
distance (in thousands of kilometers);
number of shared IGOs (averages across the years);
polity interaction.
The nodal variables include
population (in millions);
gdp (in billions of dollars);
polity
Michael Ward.
An MCMC routine providing a fit to an additive and multiplicative effects
(AME) regression model to longitudinal (time-series) relational data of
various types. Supports both unipartite (square) and bipartite (rectangular)
network structures. For cross-sectional (single time point) networks,
use the ame function.
lame( Y, Xdyad = NULL, Xrow = NULL, Xcol = NULL, rvar = TRUE, cvar = TRUE, dcor = !symmetric, nvar = TRUE, R = 0, R_row = NULL, R_col = NULL, mode = c("unipartite", "bipartite"), dynamic_uv = FALSE, dynamic_ab = FALSE, dynamic_G = FALSE, dynamic_beta = FALSE, dynamic_rho = FALSE, dynamic_beta_kind = c("ar1", "rw1", "rw2", "matern32"), dynamic_uv_kind = c("ar1", "snap", "t"), family = "normal", intercept = !(family == "ordinal"), symmetric = FALSE, odmax = NULL, prior = list(), g = NA, seed = 6886, nscan = 10000, burn = 500, odens = 25, plot = FALSE, verbose = FALSE, gof = TRUE, start_vals = NULL, periodic_save = FALSE, out_file = NULL, save_interval = 0.25, model.name = NULL, save_log_lik = FALSE, posterior_opts = NULL, log_lik_path = NULL, log_lik_chunk_size = 10000L, keep_snap_draws = c("none", "summary", "draws", "chunked"), freeze_call = FALSE, dynamic_beta_pool = c("none", "rho", "sigma", "both"), dynamic_beta_per_actor = NULL, per_actor_covariate_idx = 1L, per_actor_identifiability = c("center", "exact_center", "drop_population"), keep_per_actor = c("auto", "draws", "summary", "none"), time_index = NULL, period_exposure = NULL, max_seconds = Inf, checkpoint_path = NULL, checkpoint_every = 100L, log_lik_method = c("observed_exact", "observed_ghk", "augmented"), ordinal_cutpoints = c("data_induced", "explicit"), method = c("mcmc", "als"), als_stability = c("none", "quick", "validation"), als_max_iter = 1000L, als_tol = NULL, multistart = c("none", "cheap", "full"), bootstrap = 0L, bootstrap_type = c("parametric", "block"), bootstrap_block_length = 1L, bootstrap_seed = NULL, resume_from = NULL, print )lame( Y, Xdyad = NULL, Xrow = NULL, Xcol = NULL, rvar = TRUE, cvar = TRUE, dcor = !symmetric, nvar = TRUE, R = 0, R_row = NULL, R_col = NULL, mode = c("unipartite", "bipartite"), dynamic_uv = FALSE, dynamic_ab = FALSE, dynamic_G = FALSE, dynamic_beta = FALSE, dynamic_rho = FALSE, dynamic_beta_kind = c("ar1", "rw1", "rw2", "matern32"), dynamic_uv_kind = c("ar1", "snap", "t"), family = "normal", intercept = !(family == "ordinal"), symmetric = FALSE, odmax = NULL, prior = list(), g = NA, seed = 6886, nscan = 10000, burn = 500, odens = 25, plot = FALSE, verbose = FALSE, gof = TRUE, start_vals = NULL, periodic_save = FALSE, out_file = NULL, save_interval = 0.25, model.name = NULL, save_log_lik = FALSE, posterior_opts = NULL, log_lik_path = NULL, log_lik_chunk_size = 10000L, keep_snap_draws = c("none", "summary", "draws", "chunked"), freeze_call = FALSE, dynamic_beta_pool = c("none", "rho", "sigma", "both"), dynamic_beta_per_actor = NULL, per_actor_covariate_idx = 1L, per_actor_identifiability = c("center", "exact_center", "drop_population"), keep_per_actor = c("auto", "draws", "summary", "none"), time_index = NULL, period_exposure = NULL, max_seconds = Inf, checkpoint_path = NULL, checkpoint_every = 100L, log_lik_method = c("observed_exact", "observed_ghk", "augmented"), ordinal_cutpoints = c("data_induced", "explicit"), method = c("mcmc", "als"), als_stability = c("none", "quick", "validation"), als_max_iter = 1000L, als_tol = NULL, multistart = c("none", "cheap", "full"), bootstrap = 0L, bootstrap_type = c("parametric", "block"), bootstrap_block_length = 1L, bootstrap_seed = NULL, resume_from = NULL, print )
Y |
a T length list of relational matrices, or a 3D array of dimensions
|
Xdyad |
a T length list of n x n x pd arrays of covariates |
Xrow |
a T length list of n x pr matrices of nodal row covariates |
Xcol |
a T length list of n x pc matrices of nodal column covariates |
rvar |
logical: fit row random effects (asymmetric case)? |
cvar |
logical: fit column random effects (asymmetric case)? |
dcor |
logical: fit a dyadic correlation (asymmetric case)? |
nvar |
logical: fit nodal random effects (symmetric case)? |
R |
integer: dimension of the multiplicative effects (can be zero) |
R_row |
integer: for bipartite networks, dimension of row node multiplicative effects (defaults to R) |
R_col |
integer: for bipartite networks, dimension of column node multiplicative effects (defaults to R) |
mode |
character: either "unipartite" (default) for square networks or "bipartite" for rectangular networks |
dynamic_uv |
logical: fit dynamic multiplicative effects (latent
factors). The transition model is selected by |
dynamic_ab |
logical: fit dynamic additive effects (sender/receiver effects) that
evolve over time using AR(1) processes. When TRUE, the row effects (a) and column
effects (b) become time-varying, following |
dynamic_G |
logical (bipartite only). When TRUE the bipartite
interaction matrix |
dynamic_beta |
logical, character, integer, or logical-vector flag selecting which regression coefficients evolve over time via independent AR(1) processes. Default FALSE keeps every coefficient static (the historical behaviour). Accepted forms:
Each dynamic-coefficient block (one per distinct intercept / dyad / row /
col label that has at least one dynamic coefficient) gets its own AR(1)
parameters |
dynamic_rho |
logical. For directed unipartite normal models, allow the
residual dyadic reciprocity parameter |
dynamic_beta_kind |
character: state-space prior on the dynamic
coefficient block(s). |
dynamic_uv_kind |
Character string selecting the transition model for
dynamic multiplicative latent positions when |
family |
character: one of "normal","binary","ordinal","cbin","frn","poisson" - see the details below |
intercept |
logical: fit model with an intercept? |
symmetric |
logical: is the sociomatrix symmetric? Not available for
the |
odmax |
a scalar integer or vector of length n giving the maximum number of nominations that each node may make - used for "frn" and "cbin" families |
prior |
a list containing hyperparameters for the prior distributions. Available options and their defaults:
Common usage: prior = list(Sab0 = diag(c(1, 1)), eta0 = 10) for stronger shrinkage, or prior = list(rho_uv_mean = 0.95) for higher temporal persistence, or prior = list(rho_beta_mean = 0.95, sigma_beta_scale = 0.1) for very smooth time-varying coefficients with tight innovations. |
g |
optional scalar or vector for g-prior on regression coefficients. Default is p^2 where p is the number of regression parameters. The g-prior controls the variance of regression coefficients: larger values allow for larger coefficient values. Can be a vector of length p for parameter-specific control. |
seed |
random seed for the MCMC sampler (default 6886). The sampler
is seeded internally with this value, so results are reproducible by
default and an external |
nscan |
number of iterations of the Markov chain (beyond burn-in) |
burn |
burn in for the Markov chain |
odens |
output density for the Markov chain |
plot |
logical: plot results while running? |
verbose |
logical: print progress while running? Default FALSE. |
gof |
logical: calculate goodness of fit statistics? |
start_vals |
list of parameter starting values for the MCMC chain.
Use |
periodic_save |
logical: indicating whether to periodically save MCMC results |
out_file |
character vector indicating name and path in which file should be stored if periodic_save is selected. For example, on an Apple OS out_file="~/Desktop/ameFit.rda". |
save_interval |
quantile interval indicating when to save during the post-burn-in period. |
model.name |
optional string for model selection output |
save_log_lik |
one of |
posterior_opts |
optional list of posterior draw-storage options,
usually built with |
log_lik_path |
directory to write log-lik chunks to when
|
log_lik_chunk_size |
column-width of each on-disk chunk when
|
keep_snap_draws |
controls storage of post-burn-in MCMC snap-shift
indicators when |
freeze_call |
logical: if |
dynamic_beta_pool |
one of |
dynamic_beta_per_actor |
optional, one of |
per_actor_covariate_idx |
positive integer; index into the
dyadic covariate cube to slope on for the per-actor extension.
Default |
per_actor_identifiability |
one of |
keep_per_actor |
one of |
time_index |
optional numeric vector of length |
period_exposure |
optional non-negative numeric vector of length
|
max_seconds |
optional positive scalar; if the MCMC wall-clock
time exceeds this many seconds, the chain terminates cleanly and
|
checkpoint_path |
optional file path. When set, the chain
periodically writes a snapshot of |
checkpoint_every |
positive integer; iterations between
checkpoint writes. Default |
log_lik_method |
one of |
ordinal_cutpoints |
character: cutpoint convention for
|
method |
character: |
als_stability |
character (only used when |
als_max_iter |
positive integer (only used when |
als_tol |
optional positive scalar (only used when
|
multistart |
character (only used when |
bootstrap |
integer (only used when |
bootstrap_type |
character (only used when |
bootstrap_block_length |
integer: block length for the block bootstrap. |
bootstrap_seed |
optional integer seed for the bootstrap. |
resume_from |
optional path to a checkpoint file produced by a
previous |
print |
Deprecated. Use |
This command provides posterior inference for parameters in AME models of longitudinal relational data, assuming one of eight possible data types/models. The model supports both unipartite networks (square adjacency matrices) and bipartite networks (rectangular adjacency matrices with distinct row and column node sets) across multiple time points.
Dynamic Effects Implementation:
The dynamic_uv and dynamic_ab parameters enable time-varying latent representations through autoregressive processes. These extensions are particularly useful for understanding how network structure evolves over time.
Dynamic Multiplicative Effects (dynamic_uv=TRUE):
The latent factors U and V evolve according to the transition selected by
dynamic_uv_kind. The default "ar1" model uses Gaussian AR(1)
drift:
where , i indexes actors, k indexes
latent dimensions, and t indexes time. The parameter controls
temporal persistence (values near 1 indicate slow evolution). This captures
time-varying homophily, latent community structure, and transitivity dynamics.
The "snap" transition uses a mixture of AR(1) drift and discontinuous
reset transitions, while "t" uses heavy-tailed Student-t innovations
represented by local transition scales. On the MCMC path, snap and t
transitions are supported for unipartite directed and symmetric models. With
method = "als", Student-t dynamic UV is also supported for bipartite
normal, binary, and Poisson panels, and snap ALS is supported for normal
unipartite and bipartite panels, including named panels where actors enter or
exit.
Key references:
Sewell & Chen (2015): Introduced dynamic latent space models with actor-specific evolution rates
Durante & Dunson (2014): Nonparametric Bayesian approach allowing flexible evolution of network structure
Hoff (2011): Hierarchical multilinear models providing theoretical foundation for temporal dependencies
Dynamic Additive Effects (dynamic_ab=TRUE): The sender (a) and receiver (b) effects evolve as:
where . This models
time-varying individual activity levels (outdegree) and popularity (indegree).
Dynamic additive effects are useful when sender activity and receiver
popularity change over time rather than staying fixed across the whole panel.
A dynamic_ab fit returns the posterior-mean paths on
fit$a_dynamic / fit$b_dynamic (actor x period) and their
per-period posterior standard deviations on fit$a_dynamic_sd /
fit$b_dynamic_sd; ab_plot(fit, plot_type = "ribbon") uses the
latter to draw a credible band around each actor's path.
Prior Specification for Dynamic Parameters:
:
Ensures stationarity of AR(1) process
:
Controls innovation variance
Default priors ( mean=0.9, mean=0.8)
favor smooth evolution
Adjust rho_*_mean closer to 1 for slower evolution, closer to 0 for more rapid changes
Computational Considerations:
Dynamic effects increase computation by roughly 30 to 50 percent per iteration
Memory usage scales as O(nRT) for dynamic_uv, O(n*T) for dynamic_ab
C++ implementation is substantially faster than a pure R loop
Convergence diagnostics: Monitor rho and sigma parameters carefully
Effective sample sizes typically lower due to temporal correlation
Recommend burn >= 1000 and nscan >= 20000 for dynamic models
Model Selection Guidelines: Use both dynamic_uv and dynamic_ab when:
Networks show clear temporal trends in density or clustering
Individual node behavior changes systematically over time
Community structure evolves (merging, splitting, drift)
Use only dynamic_uv when:
Latent structure/communities change but individual effects are stable
Focus is on evolving homophily or clustering patterns
Network shows structural reconfiguration over time
Use only dynamic_ab when:
Individual heterogeneity varies but overall structure is stable
Actors' activity/popularity changes over observation period
Focus is on individual-level temporal dynamics
Bipartite Network Models:
When mode="bipartite", the model handles rectangular adjacency matrices Y with dimensions n_A x n_B, where n_A and n_B represent the number of row and column nodes respectively.
Static Bipartite Case: The model uses separate latent factor matrices:
U: n_A x R_row matrix of row node latent positions
V: n_B x R_col matrix of column node latent positions
G: R_row x R_col interaction matrix mapping between latent spaces
Multiplicative term: U G V' captures bipartite community structure
Dynamic Bipartite Case: When dynamic_uv=TRUE for bipartite networks:
where i indexes row nodes, j indexes column nodes, k indexes latent dimensions.
When dynamic_G = TRUE the bipartite interaction matrix varies
by period (a separate matrix at every
time slice) and is returned as fit$G_cube. The MCMC estimator samples
with a Carter-Kohn/FFBS update; method = "als" estimates a
penalized point path for normal, binary, and Poisson bipartite panels,
including named changing-composition panels. The marginal
linear predictor is the
identified object; individual entries can shift under equivalent
rotations and scalings of and . dynamic_G = TRUE
is bipartite only.
Key Differences from Unipartite Models:
No dyadic correlation (rho): Bipartite edges are inherently directed
Separate dimensions: R_row and R_col can differ for row/column spaces
Rectangular structure: Network density patterns differ from square matrices
Community interpretation: Captures affiliation patterns between node types
Standard AME Model Types:
The following describes the six standard data types/models available:
"normal": A normal AME model.
"binary": A binary probit AME model.
"ordinal": An ordinal probit AME model. An intercept is not identifiable in this model.
"cbin": An AME model for censored binary data. The value of 'odmax' specifies the maximum number of links each row may have.
"frn": An AME model for fixed rank nomination networks. A higher value of the rank indicates a stronger relationship. The value of 'odmax' specifies the maximum number of links each row may have.
"poisson": An overdispersed Poisson AME model for count data:
with ,
a lognormal-mixed Poisson. The conditional mean given the latent is
; the marginal mean is , not
. On sparse count matrices (only a few dozen nonzero
cells per period) the multiplicative factors are weakly identified:
UVPM can differ across seeds while the fit is otherwise stable, and
the level of the latent log-rates mixes slowly (the longitudinal sampler
does not yet have the joint level move that ame uses). For such data compare seeds, use long chains, check
sum(unlist(fit$YPM)) against the observed total, and prefer
R = 0 unless the factors reproduce.
BETA |
posterior samples of regression coefficients. A
2-dimensional matrix Migration from amen. Under |
VC |
posterior samples of the variance parameters |
APM |
posterior mean of additive row effects a |
BPM |
posterior mean of additive column effects b |
U |
posterior mean of multiplicative row effects u. For dynamic_uv=TRUE, this is a 3D array (n x R x T) |
V |
posterior mean of multiplicative column effects v (asymmetric case). For dynamic_uv=TRUE, this is a 3D array (n x R x T) |
UVPM |
posterior mean of UV |
ULUPM |
posterior mean of ULU (symmetric case) |
L |
posterior mean of L (symmetric case) |
EZ |
estimate of expectation of Z
matrix. For |
YPM |
posterior mean of Y (for imputing missing values) |
GOF |
observed (first row) and posterior predictive (remaining rows)
values of four goodness-of-fit statistics.
See |
start_vals |
Final parameter values from MCMC, can be used as the input for a future model run. |
model.name |
Name of the model (if provided) |
Cassy Dorff, Shahryar Minhas, Tosin Salau
ame for cross-sectional models,
lame_als for the fast MCMC-free point estimator,
lame_snap_als for the approximate dynamic snap-shift
point estimator,
als_dynamic_beta for a regression-only penalised
smoother on the time-varying coefficient path,
lame_resume for resuming saved checkpoints,
gof for post-hoc goodness-of-fit computation,
gof_plot for visualizing GOF results,
latent_positions for extracting latent positions as a tidy data frame,
procrustes_align for Procrustes alignment of latent positions,
summary.lame for model summaries,
coef.lame for coefficient extraction.
Long-format edgelists and covariates can be prepared with
netify::netify() and passed directly to lame(), or converted
explicitly with netify::to_lame(lame = TRUE).
data(YX_bin_list) fit<-lame(YX_bin_list$Y,YX_bin_list$X,burn=5,nscan=5,odens=1,family="binary") # you should run the Markov chain much longer than this ## Time-varying regression coefficients (dynamic_beta). ## Make every dyadic coefficient evolve as an AR(1): fit_dyn <- lame(YX_bin_list$Y, YX_bin_list$X, family = "binary", R = 0, nscan = 60, burn = 15, odens = 5, dynamic_beta = "dyad") dim(fit_dyn$BETA) # [n_stored, p, T] -- 3-D when dynamic coef(fit_dyn) # [p, T] posterior-mean coefficient paths confint(fit_dyn) # per-period 95% credible intervals summary(fit_dyn) # prints a "Dynamic coefficients per period" blockdata(YX_bin_list) fit<-lame(YX_bin_list$Y,YX_bin_list$X,burn=5,nscan=5,odens=1,family="binary") # you should run the Markov chain much longer than this ## Time-varying regression coefficients (dynamic_beta). ## Make every dyadic coefficient evolve as an AR(1): fit_dyn <- lame(YX_bin_list$Y, YX_bin_list$X, family = "binary", R = 0, nscan = 60, burn = 15, odens = 5, dynamic_beta = "dyad") dim(fit_dyn$BETA) # [n_stored, p, T] -- 3-D when dynamic coef(fit_dyn) # [p, T] posterior-mean coefficient paths confint(fit_dyn) # per-period 95% credible intervals summary(fit_dyn) # prints a "Dynamic coefficients per period" block
Fits an additive and multiplicative effects (AME) model to a longitudinal
(replicated) network by iterative block coordinate descent,
producing a fast point estimate with no MCMC and no credible intervals.
This is the longitudinal counterpart of ame_als; the
estimated effects (mu, beta, a, b, U,
V) are static (pooled across time), as in a non-dynamic
lame fit.
The estimation algorithm adapts the iterative block coordinate descent
estimator of the Social Influence Regression model of Hoff & Minhas
(sir::sir_alsfit()) to the AME model; it is a port and adaptation,
not original lame methodology. See ame_als for the
algorithm details.
lame_als( Y, Xdyad = NULL, Xrow = NULL, Xcol = NULL, R = 0, family = "normal", mode = c("unipartite", "bipartite"), symmetric = FALSE, max_iter = 200, tol = 1e-06, lowrank_method = c("mm", "als", "hybrid"), non_normal_method = c("irls", "transform"), link = c("probit", "logit"), linear_solver = c("eigen", "qr", "auto"), multistart = c("none", "cheap", "full"), bootstrap = 0L, bootstrap_type = c("parametric", "block"), bootstrap_block_length = 1L, bootstrap_seed = NULL, verbose = TRUE, seed = 6886 )lame_als( Y, Xdyad = NULL, Xrow = NULL, Xcol = NULL, R = 0, family = "normal", mode = c("unipartite", "bipartite"), symmetric = FALSE, max_iter = 200, tol = 1e-06, lowrank_method = c("mm", "als", "hybrid"), non_normal_method = c("irls", "transform"), link = c("probit", "logit"), linear_solver = c("eigen", "qr", "auto"), multistart = c("none", "cheap", "full"), bootstrap = 0L, bootstrap_type = c("parametric", "block"), bootstrap_block_length = 1L, bootstrap_seed = NULL, verbose = TRUE, seed = 6886 )
Y |
a list of |
Xdyad |
a list of |
Xrow |
a list of |
Xcol |
a list of |
R |
integer dimension of the multiplicative effects (default |
family |
one of |
mode |
|
symmetric |
logical; fit a symmetric (undirected) model. Unipartite only. |
max_iter |
maximum number of block coordinate descent iterations (default 200). |
tol |
convergence tolerance on the relative change in residual sum of
squares (default |
lowrank_method |
inner solver for the multiplicative (low-rank) block:
|
non_normal_method |
for the non-normal ALS families, |
link |
link for |
linear_solver |
solver for the regression block: |
multistart |
for |
bootstrap |
integer: if > 0, additionally run |
bootstrap_type |
character: |
bootstrap_block_length |
integer: block length for the block
bootstrap; only used when |
bootstrap_seed |
optional integer seed for the bootstrap (the point
fit uses |
verbose |
logical; print progress (default |
seed |
random seed (default |
An object of class "ame_als"; see ame_als.
Cassy Dorff, Shahryar Minhas, Tosin Salau
Minhas, S. and Hoff, P. D. (2025). Decomposing Network Dynamics: Social
Influence Regression. Political Analysis. The iterative block
coordinate descent estimator adapted here originates with that work
(implemented in sir::sir_alsfit()).
ame_als, ame_als_bootstrap,
lame for the full MCMC estimator,
lame_snap_als for the approximate dynamic snap-shift
point estimator,
als_dynamic_beta for a regression-only smoother
that estimates only a time-varying (no
; not a special case of this function).
Y <- replicate(4, { m <- matrix(rnorm(400), 20, 20); diag(m) <- NA; m }, simplify = FALSE) fit <- lame_als(Y, R = 1, family = "normal", verbose = FALSE) coef(fit)Y <- replicate(4, { m <- matrix(rnorm(400), 20, 20); diag(m) <- NA; m }, simplify = FALSE) fit <- lame_als(Y, R = 1, family = "normal", verbose = FALSE) coef(fit)
Fits K independent lame() models (one per panel) and pools
the per-panel beta posteriors into a precision-weighted shared
posterior. Returns a list with the per-panel fits, the pooled
beta posterior, and the panel-specific deviations.
lame_multi(Y_list, Xdyad_list, ...)lame_multi(Y_list, Xdyad_list, ...)
Y_list |
A list of length K, each element a list (or 3-D array) of T per-panel network observations. |
Xdyad_list |
A list of length K, each element a list of T dyadic covariate arrays. |
... |
Arguments forwarded to |
This is an R-level wrapper: it fits each panel with its own MCMC and pools the results afterwards. The pooling is exact when the panels are conditionally independent given beta, which is the standard assumption.
A list with
fits: list of K per-panel lame fits.
beta_shared: pooled posterior mean of beta
(per-period when dynamic).
beta_deviations: list of K panel-specific deviations
from beta_shared.
K: number of panels.
Class "lame_multi".
lame_parallel for the unrelated multi-chain
wrapper that runs K MCMC chains of the same model (used for
R-hat / ESS diagnostics and pooled effective sample size).
lame_multi is for K distinct panels with shared
regression coefficients; lame_parallel is for K chains of
one model.
data(YX_bin_list) fit_multi <- lame_multi( Y_list = list(YX_bin_list$Y, YX_bin_list$Y), Xdyad_list = list(YX_bin_list$X, YX_bin_list$X), family = "binary", R = 0, nscan = 100, burn = 25, odens = 5, verbose = FALSE) dim(fit_multi$beta_shared)data(YX_bin_list) fit_multi <- lame_multi( Y_list = list(YX_bin_list$Y, YX_bin_list$Y), Xdyad_list = list(YX_bin_list$X, YX_bin_list$X), family = "binary", R = 0, nscan = 100, burn = 25, odens = 5, verbose = FALSE) dim(fit_multi$beta_shared)
Thin wrapper around ame_parallel that forces
fitter = "lame". Use this for longitudinal data; in particular,
multi-chain dynamic_beta / dynamic_uv / dynamic_ab
fits are reached through here. The combined fit's $BETA is a 3-D
array when dynamic_beta is on, and posterior::rhat(as_draws(fit))
gives R-hat across chains for every per-period coefficient.
lame_parallel( Y, n_chains = 4, cores = n_chains, combine_method = c("pool", "list"), ... )lame_parallel( Y, n_chains = 4, cores = n_chains, combine_method = c("pool", "list"), ... )
Y |
Longitudinal network: list of T relational matrices, or a 3-D
array |
n_chains |
Number of parallel chains (default 4). |
cores |
CPU cores to use (default |
combine_method |
|
... |
Additional arguments forwarded to |
Same as ame_parallel: a combined lame fit (when
combine_method = "pool") or a list of fits.
data(YX_bin_list) fit_pll <- lame_parallel(YX_bin_list$Y, Xdyad = YX_bin_list$X, family = "binary", n_chains = 2, cores = 1, nscan = 50, burn = 10, odens = 5, dynamic_beta = "dyad", verbose = FALSE) dim(fit_pll$BETA) # [iter * n_chains, p, T] fit_pll$chain_indicator # length iter * n_chains if (requireNamespace("posterior", quietly = TRUE)) { posterior::summarise_draws(posterior::as_draws(fit_pll)) }data(YX_bin_list) fit_pll <- lame_parallel(YX_bin_list$Y, Xdyad = YX_bin_list$X, family = "binary", n_chains = 2, cores = 1, nscan = 50, burn = 10, odens = 5, dynamic_beta = "dyad", verbose = FALSE) dim(fit_pll$BETA) # [iter * n_chains, p, T] fit_pll$chain_indicator # length iter * n_chains if (requireNamespace("posterior", quietly = TRUE)) { posterior::summarise_draws(posterior::as_draws(fit_pll)) }
lame() MCMC run from a checkpointFor a fit started with lame(..., checkpoint_path = "X.rds")
that terminated early (either via max_seconds or an external
interruption), continues the chain from the most recent checkpoint.
The implementation is pragmatic: it loads the saved RNG state and
re-invokes lame() with the original call arguments. The
result is a fresh fit that picks up where the previous one left
off in the random-number stream; the underlying MCMC counter
restarts at 1.
lame_resume(path, nscan_more = NULL, ..., .envir = NULL)lame_resume(path, nscan_more = NULL, ..., .envir = NULL)
path |
Checkpoint file path (the one passed as
|
nscan_more |
Optional integer, the new |
... |
Additional arguments forwarded to |
.envir |
Environment in which to evaluate the saved call's data
arguments. Defaults to the caller's frame; used internally when
|
Equivalent consolidated entry point.
lame(resume_from = path, ...) short-circuits to this
function with the user-supplied overrides forwarded; pass
nscan = K on the resume call to request K
additional stored draws. Both call shapes are supported. The
lame_resume(path, ...) form is safer for nested calls: the
consolidated form re-evaluates the
saved lame() call in parent.frame(), which is
the lame() frame whose required formal arguments
(Y, Xdyad, etc.) were not supplied on the
resume call. Prefer lame_resume(path, ...) when calling
from inside other functions or from non-global scopes.
Use nscan_more = K to override the nscan value to
K for the continuation. Other arguments can be overridden by
passing them to ....
A fitted lame object.
ck <- tempfile(fileext = ".rds") data(YX_bin_list) # short run with very-aggressive max_seconds to force early termination fit1 <- lame(YX_bin_list$Y, YX_bin_list$X, family = "binary", R = 0, nscan = 5000, burn = 50, odens = 5, checkpoint_path = ck, checkpoint_every = 50L, max_seconds = 0.5, verbose = FALSE) if (isTRUE(fit1$terminated_early)) { fit2 <- lame_resume(ck, nscan_more = 200) dim(fit2$BETA) }ck <- tempfile(fileext = ".rds") data(YX_bin_list) # short run with very-aggressive max_seconds to force early termination fit1 <- lame(YX_bin_list$Y, YX_bin_list$X, family = "binary", R = 0, nscan = 5000, burn = 50, odens = 5, checkpoint_path = ck, checkpoint_every = 50L, max_seconds = 0.5, verbose = FALSE) if (isTRUE(fit1$terminated_early)) { fit2 <- lame_resume(ck, nscan_more = 200) dim(fit2$BETA) }
Fits a fast point-estimator approximation to the dynamic snap-shift
latent-factor model for longitudinal normal-valued networks.
It targets the same drift-versus-reset transition estimand as
lame with dynamic_uv = TRUE and
dynamic_uv_kind = "snap", but returns ALS snap scores rather than
MCMC draws.
lame_snap_als( Y, Xdyad = NULL, Xrow = NULL, Xcol = NULL, R = 2L, R_row = NULL, R_col = NULL, family = "normal", mode = c("unipartite", "bipartite"), symmetric = FALSE, max_iter = 200L, tol = 1e-06, snap_kappa = 2, snap_pi_prior = c(a = 1, b = 9), snap_update = c("soft", "hard", "annealed"), snap_damping = 0.7, estimate_rho_uv = TRUE, estimate_sigma_uv = TRUE, rho_uv = NULL, sigma_uv = NULL, hyper_update = c("robust", "em"), drift_quantile = 0.05, drift_min_transitions = 50, rho_prior_mean = 0.98, rho_prior_weight = 25, align = c("sequential", "global", "none"), threshold = 0.5, min_sigma = 1e-04, sigma_floor_fraction = 0.75, ridge = 1e-08, snap_stability_tol = 0.05, snap_convergence = c("quantile", "max", "classification"), snap_delta_quantile = 0.95, snap_class_change_tol = 0.005, unstable_top_n = 10L, stability = c("none", "quick", "validation"), verbose = TRUE, seed = 6886 )lame_snap_als( Y, Xdyad = NULL, Xrow = NULL, Xcol = NULL, R = 2L, R_row = NULL, R_col = NULL, family = "normal", mode = c("unipartite", "bipartite"), symmetric = FALSE, max_iter = 200L, tol = 1e-06, snap_kappa = 2, snap_pi_prior = c(a = 1, b = 9), snap_update = c("soft", "hard", "annealed"), snap_damping = 0.7, estimate_rho_uv = TRUE, estimate_sigma_uv = TRUE, rho_uv = NULL, sigma_uv = NULL, hyper_update = c("robust", "em"), drift_quantile = 0.05, drift_min_transitions = 50, rho_prior_mean = 0.98, rho_prior_weight = 25, align = c("sequential", "global", "none"), threshold = 0.5, min_sigma = 1e-04, sigma_floor_fraction = 0.75, ridge = 1e-08, snap_stability_tol = 0.05, snap_convergence = c("quantile", "max", "classification"), snap_delta_quantile = 0.95, snap_class_change_tol = 0.005, unstable_top_n = 10L, stability = c("none", "quick", "validation"), verbose = TRUE, seed = 6886 )
Y |
a list of relational matrices, or a 3D array. Unipartite fits use
|
Xdyad |
optional list of dyadic covariate matrices/arrays, or
|
Xrow, Xcol
|
not supported by this fast snap-shift estimator; pass
|
R |
positive integer latent rank. For bipartite fits, used as the
default for |
R_row, R_col
|
positive integer latent ranks for bipartite row and
column positions. Defaults to |
family |
currently only |
mode |
|
symmetric |
logical; if |
max_iter |
maximum block-coordinate iterations. |
tol |
convergence tolerance on the relative change of the tracked
|
snap_kappa |
diffuse snap-prior standard deviation. |
snap_pi_prior |
length-two vector |
snap_update |
one of |
snap_damping |
scalar in |
estimate_rho_uv, estimate_sigma_uv
|
logical flags for updating the AR drift persistence and innovation scale. |
rho_uv, sigma_uv
|
optional fixed/initial AR drift parameters. |
hyper_update |
one of |
drift_quantile |
lower-tail transition quantile used by
|
drift_min_transitions |
minimum effective number of transitions retained by the lower-tail update. This keeps the default from overfitting the smooth-drift scale on small panels. |
rho_prior_mean, rho_prior_weight
|
weak regularization for the persistence estimate. The defaults encode the snap-shift model's intended persistent, low-innovation drift baseline. |
align |
initialization alignment mode; |
threshold |
hard-classification threshold for |
min_sigma |
lower bound for the drift scale. |
sigma_floor_fraction |
for robust hyperparameter updates, the iterative
drift scale cannot fall below this fraction of the initial
|
ridge |
small ridge added to latent-position normal equations. |
snap_stability_tol |
tolerance for declaring soft snap scores stable.
This is separate from |
snap_convergence |
convergence criterion for snap scores.
|
snap_delta_quantile |
quantile of actor-period score changes used by
|
snap_class_change_tol |
maximum share of eligible actor-periods whose
|
unstable_top_n |
number of largest actor-period snap-score changes to store in convergence diagnostics. |
stability |
optional start-sensitivity preset. |
verbose |
logical; print progress. |
seed |
integer seed for initialization perturbations. |
The raw snap-ALS intercept mu is not separately identified
from the uncentered multiplicative term: a constant level can be absorbed
into (bipartite:
), so fit$mu on its own is
arbitrary. After convergence the estimator therefore computes a post-hoc
identified level: fit$mu_t stores the per-period level
(named by period) and
fit$mu_identified is the mean of fit$mu_t. Interpret the
network level through mu_identified; the latent trajectories and
the covariate coefficients are unaffected by this shift and remain
reliable outputs of this estimator.
On longer panels, the default align = "sequential" keeps the
period-to-period movement in view. align = "global" can help on very
short panels, but on longer panels it can pull each period back toward the
pooled static fit and make early jumps look too strong. If you have a fixed
drift scale, pass rho_uv and sigma_uv with
estimate_rho_uv = FALSE and estimate_sigma_uv = FALSE.
The convergence output separates the usual score summary from the worst
moving actor-period. By default, convergence uses the 95th percentile of
score changes and the share of class changes. final_max_snap_delta
and unstable_transitions still show the largest local moves. Read
snap_prob as an ALS snap score. It is useful for rankings and
heuristic classifications; it is not a Bayesian posterior probability.
For unipartite fits, the tracked objective (fit$objective_trace,
fit$convergence$final_objective) is the exact
variational free energy of the snap/drift mixture model, including the
Gaussian log-normalizers, the responsibility entropy, and the beta prior
on the snap rate. The exact block updates descend it monotonically; small
increases can come from damped snap scores or the robust hyperparameter
updates. Because it carries log-variance normalizers it can be negative
and is not a deviance; fit$param_trace$sse tracks raw data fit
directly.
In bipartite mode, the fitted multiplicative term is
with one static interaction matrix . The returned
snap_prob matrix contains row-actor snap scores and
snap_prob_v contains column-actor snap scores. Bipartite snap ALS
does not estimate node covariates, dynamic coefficients, or a dynamic
; those combinations need a separate model.
An object of class "lame_snap_als" with dynamic latent
positions, snap scores, fitted values, residuals, and
convergence diagnostics.
set.seed(1) Y_bip <- lapply(seq_len(3), function(t) { m <- matrix(rnorm(6 * 5), 6, 5) rownames(m) <- paste0("r", seq_len(6)) colnames(m) <- paste0("c", seq_len(5)) m }) fit_bip <- lame_snap_als(Y_bip, R = 1, mode = "bipartite", max_iter = 3, verbose = FALSE) dim(fit_bip$snap_prob_v)set.seed(1) Y_bip <- lapply(seq_len(3), function(t) { m <- matrix(rnorm(6 * 5), 6, 5) rownames(m) <- paste0("r", seq_len(6)) colnames(m) <- paste0("c", seq_len(5)) m }) fit_bip <- lame_snap_als(Y_bip, R = 1, mode = "bipartite", max_iter = 3, verbose = FALSE) dim(fit_bip$snap_prob_v)
Extracts multiplicative latent factor positions (U and V) from a fitted
ame, lame or ame_als model and returns them as a
tidy data frame suitable for plotting and analysis. Optionally applies
Procrustes alignment for dynamic models and includes posterior standard
deviations when posterior samples are available.
latent_positions(object, ...) ## S3 method for class 'ame' latent_positions(object, align = FALSE, ...) ## S3 method for class 'lame' latent_positions(object, align = TRUE, ...) ## S3 method for class 'ame_als' latent_positions(object, align = FALSE, ...)latent_positions(object, ...) ## S3 method for class 'ame' latent_positions(object, align = FALSE, ...) ## S3 method for class 'lame' latent_positions(object, align = TRUE, ...) ## S3 method for class 'ame_als' latent_positions(object, align = FALSE, ...)
object |
A fitted |
... |
Additional arguments (currently unused). |
align |
Logical. For dynamic models ( |
Alignment only ever happens across the periods of one fit: with
align = TRUE the fit is passed to procrustes_align,
which rotates each period onto the one before it. Nothing here aligns two
different fits (two chains, or the same model with and without a
covariate) to a common orientation, so their latent positions are not
directly comparable. To compare fits that way, stack their U
matrices into an [n, R, 2] array (same actors in the same order,
same R) and call procrustes_align(U = that_array) on it.
A data frame with columns:
Character. Actor name (from rownames of U or V).
Integer. Latent dimension index (1 to R).
Character. Time period label. Dynamic fits use the time
labels from the input; static (cross-sectional) fits return
"1" for every row so downstream filtering by time
behaves the same in both cases.
Numeric. The posterior mean latent position.
Numeric. Posterior standard deviation of the latent
position, or NA if posterior samples are not available.
To enable, fit the model with
posterior_opts = posterior_options(save_UV = TRUE).
Character. "U" for sender/row positions,
"V" for receiver/column positions. Symmetric models have
only "U".
Returns a zero-row data frame with correct column names if R = 0.
Cassy Dorff, Shahryar Minhas, Tosin Salau
procrustes_align for standalone Procrustes alignment,
uv_plot for visualizing latent positions,
posterior_options for enabling posterior sampling of U/V
data(YX_nrm) fit <- ame(YX_nrm$Y, Xdyad = YX_nrm$X, R = 2, burn = 5, nscan = 5, odens = 1, verbose = FALSE) lp <- latent_positions(fit) head(lp)data(YX_nrm) fit <- ame(YX_nrm$Y, Xdyad = YX_nrm$X, R = 2, burn = 5, nscan = 5, odens = 1, verbose = FALSE) lp <- latent_positions(fit) head(lp)
Several nodal and dyadic variables measured on 71 attorneys in a law firm.
A list consisting of a socioarray Y and a nodal attribute matrix X.
The dyadic variables in Y include three binary networks: advice, friendship
and co-worker status.
The categorical nodal attributes in X are coded as follows:
status (1=partner, 2=associate)
office (1=Boston, 2=Hartford, 3=Providence)
practice (1=litigation, 2=corporate)
law school (1=Harvard or Yale, 2=UConn, 3=other)
seniority and age are given in years, and female is
a binary indicator.
Originally available at http://moreno.ss.uci.edu/data.html#lazega
(site no longer accessible).
For a fitted lame object with periods, refits the
model on the first periods (for each in
periods) and computes the expected log predictive density
(elpd) of period under the refit. Returns the summed elpd
across all leave-out periods, along with per-period contributions.
lfo(fit, periods = NULL, refit = TRUE, ...)lfo(fit, periods = NULL, refit = TRUE, ...)
fit |
A fitted |
periods |
Integer vector of leave-out periods to evaluate.
Default is the last 3 periods ( |
refit |
Logical; if |
... |
Passed to the refit |
A list with elpd_lfo (total summed elpd), pointwise
(per-dyad log-density at each leave-out period; a list of numeric
vectors, one per period – unlist(pointwise) gives a flat vector
suitable for loo::loo_compare()-style stacking),
p_lfo (effective number of parameters), per_period
(data frame with period, elpd, n_obs), and
periods (the periods evaluated).
data(YX_bin_list) fit <- lame(YX_bin_list$Y, YX_bin_list$X, family = "binary", R = 0, dynamic_beta = "dyad", nscan = 60, burn = 15, odens = 5, verbose = FALSE) lfo_res <- lfo(fit, periods = 4L, refit = TRUE, nscan = 50, burn = 10, odens = 5, verbose = FALSE) print(lfo_res)data(YX_bin_list) fit <- lame(YX_bin_list$Y, YX_bin_list$X, family = "binary", R = 0, dynamic_beta = "dyad", nscan = 60, burn = 15, odens = 5, verbose = FALSE) lfo_res <- lfo(fit, periods = 4L, refit = TRUE, nscan = 50, burn = 10, odens = 5, verbose = FALSE) print(lfo_res)
Convert list to array
list_to_array(actors, Y, Xdyad, Xrow, Xcol)list_to_array(actors, Y, Xdyad, Xrow, Xcol)
actors |
vector of actors |
Y |
dv in list format |
Xdyad |
dyadic covariates in list format |
Xrow |
sender covariates in list format |
Xcol |
receiver covariates in list format |
transforms Y, Xdyad, Xrow, and Xcol to arrays
Shahryar Minhas
ame() and lame() produce a posterior sample, not a maximum-
likelihood point. A pointwise log-likelihood is computable from the
posterior draws but is not stored on the fit object, so logLik()
(and the AIC / BIC generics that dispatch through it) error out
informatively rather than return a misleading number.
## S3 method for class 'ame' logLik(object, ...) ## S3 method for class 'lame' logLik(object, ...)## S3 method for class 'ame' logLik(object, ...) ## S3 method for class 'lame' logLik(object, ...)
object |
an |
... |
ignored. |
For Bayesian model comparison use posterior-predictive checks via
gof / gof_plot, or compute WAIC / LOO yourself
from the per-draw log-likelihoods (e.g. via the loo package on the
BETA / VC chains).
Never returns; raises an error.
The fast estimator minimises a (working-response) least-squares objective,
not a family likelihood, so it has no log-likelihood and AIC / BIC
are undefined. Calling logLik() raises an informative error rather
than returning a misleading number.
## S3 method for class 'ame_als' logLik(object, ...)## S3 method for class 'ame_als' logLik(object, ...)
object |
an |
... |
ignored. |
Never returns; raises an error.
Lightweight S3 generics so calls of the form loo(fit) dispatch
through R's S3 system even when the loo package is not loaded.
When loo is loaded, its generic resolves first; this
fallback only fires for bare-namespace use.
loo(x, ...) waic(x, ...)loo(x, ...) waic(x, ...)
x |
a fitted |
... |
passed to the relevant method. |
A loo / waic object.
S3 method for loo that uses the per-iteration
pointwise log-likelihood stored on the fit object (fit$log_lik) when
the model was fit with save_log_lik = TRUE. Returns the standard
loo object with Pareto-k diagnostics.
## S3 method for class 'ame' loo(x, ...) ## S3 method for class 'lame' loo(x, ...) ## S3 method for class 'ame_als' loo(x, ...)## S3 method for class 'ame' loo(x, ...) ## S3 method for class 'lame' loo(x, ...) ## S3 method for class 'ame_als' loo(x, ...)
x |
A fitted |
... |
Additional arguments forwarded to |
What log_lik measures. For family in
{normal, binary, cbin, poisson, ordinal} the stored
pointwise log-likelihood is the exact family-specific Y density on
the response scale, so elpd_loo is directly comparable to a
loo() output from Stan / brms fit to the same family. For
the rank likelihood frn the exact marginal
needs GHK Monte Carlo (Halton sequence); on the longitudinal
lame() path you can opt in with log_lik_method =
"observed_ghk", on the cross-sectional ame() path the
fallback is the augmented-Z normal approximation (with a one-time
warning). Inspect fit$log_lik_method on any fit to see which
branch was used.
Chunked log-lik portability. When fit with
save_log_lik = "chunked", the on-disk chunk files default to
tempdir(), which is cleared at the end of the R session.
If you intend to saveRDS() the fit and reload it in a fresh
session, supply an explicit persistent log_lik_path (e.g.
"./loglik_chunks") so the chunks survive the round trip.
A loo object.
data(YX_nrm) fit <- ame(YX_nrm$Y, Xdyad = YX_nrm$X, R = 0, nscan = 60, burn = 15, odens = 5, save_log_lik = TRUE, verbose = FALSE) if (requireNamespace("loo", quietly = TRUE)) { loo_res <- loo::loo(fit) print(loo_res) }data(YX_nrm) fit <- ame(YX_nrm$Y, Xdyad = YX_nrm$X, R = 0, nscan = 60, burn = 15, odens = 5, save_log_lik = TRUE, verbose = FALSE) if (requireNamespace("loo", quietly = TRUE)) { loo_res <- loo::loo(fit) print(loo_res) }
Computes the symmetric square root of a positive definite matrix
mhalf(M)mhalf(M)
M |
a positive definite matrix |
a matrix H such that H^2 equals M
Cassy Dorff, Shahryar Minhas, Tosin Salau
Number of finite (non-missing) cells in Y, summed over time slices
for longitudinal fits. Useful as a denominator for sample-size reporting
and as the basis for AIC/BIC if you also have a log-likelihood
(which ame() / lame() do not directly expose; see
logLik.ame).
## S3 method for class 'ame' nobs(object, ...) ## S3 method for class 'lame' nobs(object, ...)## S3 method for class 'ame' nobs(object, ...) ## S3 method for class 'lame' nobs(object, ...)
object |
an |
... |
ignored. |
Integer: number of observed dyads in Y.
Mirrors nobs.ame so the MCMC and ALS fits expose the same
accessor.
## S3 method for class 'ame_als' nobs(object, ...)## S3 method for class 'ame_als' nobs(object, ...)
object |
an |
... |
ignored. |
Integer: number of observed dyads.
nodematch(x) returns an n x n matrix with 1 where
x[i] == x[j] and 0 otherwise – the AME analogue of ERGM's
nodematch term, suitable for Xdyad as a single
homophily covariate. absdiff(x) returns the absolute difference
|x[i] - x[j]|, the AME analogue of ERGM's absdiff.
nodefactor(x) returns the dyadic matrix of x[i] + x[j] for
a numeric x (or, for a factor / character x, a named list
with one matrix per level giving the dyadic co-membership count
(x[i] == level) + (x[j] == level), with entries 0, 1, or 2, the
ERGM nodefactor semantics).
nodematch(x, na_diag = TRUE) absdiff(x, na_diag = TRUE) nodefactor(x, na_diag = TRUE)nodematch(x, na_diag = TRUE) absdiff(x, na_diag = TRUE) nodefactor(x, na_diag = TRUE)
x |
a numeric, factor, or character vector of length |
na_diag |
logical: set the diagonal to |
All helpers return a matrix or list of matrices that is ready to
wrap into an n x n x p Xdyad array via simplify2array
or array().
An n x n numeric matrix (or, for a factor x passed
to nodefactor, a named list of such matrices).
n <- 12 grp <- sample(letters[1:3], n, replace = TRUE) age <- rnorm(n, 40, 10) # build a single same-group homophily covariate Xdyad <- array(nodematch(grp), dim = c(n, n, 1), dimnames = list(NULL, NULL, "same_group")) # combine homophily + age difference Xdyad <- array(c(nodematch(grp), absdiff(age)), dim = c(n, n, 2), dimnames = list(NULL, NULL, c("same_group", "age_diff")))n <- 12 grp <- sample(letters[1:3], n, replace = TRUE) age <- rnorm(n, 40, 10) # build a single same-group homophily covariate Xdyad <- array(nodematch(grp), dim = c(n, n, 1), dimnames = list(NULL, NULL, "same_group")) # combine homophily + age difference Xdyad <- array(c(nodematch(grp), absdiff(age)), dim = c(n, n, 2), dimnames = list(NULL, NULL, c("same_group", "age_diff")))
Computes a smoothed per-actor time-varying slope coefficient on a
slice of the combined dyadic design array (fit$Xlist). For
kind = "row", each row-actor gets a length- slope
path on the across-column mean of design slice
covariate_idx, fit by ridge-penalised least squares on the
residual after the main MCMC linear predictor; kind = "col" uses
the across-row mean for each column-actor.
per_actor_slopes(fit, kind = c("row", "col"), covariate_idx = 1L, lambda = 1)per_actor_slopes(fit, kind = c("row", "col"), covariate_idx = 1L, lambda = 1)
fit |
A fitted |
kind |
|
covariate_idx |
Integer index into the third (covariate) dimension
of the combined dyadic design array |
lambda |
Non-negative smoothing parameter (first-difference
penalty across periods). Default |
A list with slopes (an
matrix), kind, covariate_idx, lambda,
and label. Class "per_actor_slopes".
data(YX_bin_list) fit <- lame(YX_bin_list$Y, YX_bin_list$X, family = "binary", R = 0, nscan = 100, burn = 25, odens = 5, verbose = FALSE) # post-MCMC per-row-actor slopes on the first dyadic covariate pas <- per_actor_slopes(fit, kind = "row", lambda = 1) dim(pas$slopes)data(YX_bin_list) fit <- lame(YX_bin_list$Y, YX_bin_list$X, family = "binary", R = 0, nscan = 100, burn = 25, odens = 5, verbose = FALSE) # post-MCMC per-row-actor slopes on the first dyadic covariate pas <- per_actor_slopes(fit, kind = "row", lambda = 1) dim(pas$slopes)
Provides a quick visual summary of an AME model fit, focusing on key convergence diagnostics. For more detailed diagnostics, use the specific plotting functions: trace_plot(), gof_plot(), ab_plot(), and uv_plot().
## S3 method for class 'ame' plot(x, ...)## S3 method for class 'ame' plot(x, ...)
x |
an object of class "ame" from fitting an AME model |
... |
additional arguments passed to trace_plot() |
By default, this function simply calls trace_plot() to show MCMC trace plots and posterior distributions for key parameters. This provides a quick check of model convergence and mixing.
For more detailed visualizations, use the specialized functions:
MCMC diagnostics and posterior distributions
Goodness-of-fit assessment
Additive sender/receiver effects
Multiplicative latent factors
A ggplot2 object from trace_plot() (invisibly)
Cassy Dorff, Shahryar Minhas, Tosin Salau
ame, trace_plot, gof_plot,
ab_plot, uv_plot
# Fit an AME model data(YX_nrm) fit <- ame(YX_nrm$Y, Xdyad = YX_nrm$X, R = 2, gof = TRUE, nscan = 100, burn = 10, odens = 1, verbose = FALSE) # Quick diagnostic plot (shows trace plots) plot(fit)# Fit an AME model data(YX_nrm) fit <- ame(YX_nrm$Y, Xdyad = YX_nrm$X, R = 2, gof = TRUE, nscan = 100, burn = 10, odens = 1, verbose = FALSE) # Quick diagnostic plot (shows trace plots) plot(fit)
Plots the block coordinate descent deviance/SSE history – a convergence
diagnostic for an ame_als or lame_als
fit. For substantive plots see uv_plot, ab_plot
and gof_plot.
## S3 method for class 'ame_als' plot(x, ...)## S3 method for class 'ame_als' plot(x, ...)
x |
an |
... |
further arguments passed to the underlying plot. |
x, invisibly.
Creates diagnostic plots for a LAME (Longitudinal Additive and Multiplicative Effects) model, including MCMC diagnostics, parameter evolution over time, and longitudinal goodness-of-fit checks. This is the default plot method for LAME objects.
## S3 method for class 'lame' plot( x, which = c(1, 2, 3, 4), time.points = NULL, ask = FALSE, pages = c("single", "multiple"), ... )## S3 method for class 'lame' plot( x, which = c(1, 2, 3, 4), time.points = NULL, ask = FALSE, pages = c("single", "multiple"), ... )
x |
an object of class "lame" from fitting a LAME model |
which |
numeric or character vector specifying which plots to produce: 1 or "trace" = MCMC trace plots, 2 or "density" = posterior density plots, 3 or "gof" = longitudinal goodness-of-fit plots, 4 or "effects" = additive and multiplicative effects, 5 or "network" = network snapshots at selected times. Default is c(1,2,3,4) to show main diagnostic plots. |
time.points |
numeric vector of time points for network snapshots (only used if "network" in which). Default is c(1, middle, last). |
ask |
logical; if TRUE, user is prompted before each plot page |
pages |
character string specifying how to arrange plots: "single" = one combined page (default), "multiple" = separate pages for each plot type |
... |
additional arguments (currently not used) |
The function produces a multi-panel plot containing:
Shows mixing and convergence of key parameters
Density plots of regression coefficients and variance components
Time series of observed network statistics with posterior predictive intervals
Evolution of additive effects across time periods (if applicable)
Visualization of network at selected time points
The plot adapts to the longitudinal structure:
Shows temporal trends in network statistics
Highlights composition changes if actors enter/exit
Displays credible intervals for time-varying statistics
NULL (invisibly). Plots are displayed as side effects.
Cassy Dorff, Shahryar Minhas, Tosin Salau
lame, trace_plot, gof_plot,
ab_plot, uv_plot
# Create simple longitudinal network data set.seed(6886) n <- 10 nms <- paste0("n", 1:n) Y_list <- list( matrix(rnorm(n * n), n, n, dimnames = list(nms, nms)), matrix(rnorm(n * n), n, n, dimnames = list(nms, nms)) ) diag(Y_list[[1]]) <- diag(Y_list[[2]]) <- NA fit <- lame(Y_list, family = "normal", nscan = 50, burn = 10, odens = 1, verbose = FALSE, plot = FALSE) # default combined plot plot(fit)# Create simple longitudinal network data set.seed(6886) n <- 10 nms <- paste0("n", 1:n) Y_list <- list( matrix(rnorm(n * n), n, n, dimnames = list(nms, nms)), matrix(rnorm(n * n), n, n, dimnames = list(nms, nms)) ) diag(Y_list[[1]]) <- diag(Y_list[[2]]) <- NA fit <- lame(Y_list, family = "normal", nscan = 50, burn = 10, odens = 1, verbose = FALSE, plot = FALSE) # default combined plot plot(fit)
Options for saving posterior samples during MCMC
posterior_options(save_UV = FALSE, save_ab = FALSE, thin_UV = 10, thin_ab = 10)posterior_options(save_UV = FALSE, save_ab = FALSE, thin_UV = 10, thin_ab = 10)
save_UV |
Logical; whether to save samples of U and V matrices (default FALSE) |
save_ab |
Logical; whether to save samples of additive effects a and b (default FALSE) |
thin_UV |
Integer; thinning interval for U/V samples (default 10) |
thin_ab |
Integer; thinning interval for a/b samples (default 10) |
List of posterior saving options, to be passed to the
posterior_opts argument of ame or lame:
ame(Y, ..., posterior_opts = posterior_options(save_UV = TRUE)) or
lame(Y, ..., posterior_opts = posterior_options(save_UV = TRUE)).
With save_UV = TRUE, static fits store U_samples /
V_samples (plus G_samples for bipartite fits) and
dynamic_uv fits store the per-period trajectory in
U_draws / V_draws; see latent_positions and
simulate_posterior for summarising them.
Cassy Dorff, Shahryar Minhas, Tosin Salau
Extract posterior quantiles for model components
posterior_quantiles( fit, component = c("beta", "UV", "ab"), probs = c(0.025, 0.5, 0.975) )posterior_quantiles( fit, component = c("beta", "UV", "ab"), probs = c(0.025, 0.5, 0.975) )
fit |
Fitted ame model object |
component |
Character; which component: "beta", "UV", "ab" |
probs |
Numeric vector of probabilities for quantiles |
Matrix or array of posterior quantiles
Cassy Dorff, Shahryar Minhas, Tosin Salau
Generate predictions from fitted AME models, including point estimates and predictive distributions.
## S3 method for class 'ame' predict( object, newdata = NULL, type = c("response", "link", "distribution"), n_samples = 100, include_uncertainty = TRUE, ... )## S3 method for class 'ame' predict( object, newdata = NULL, type = c("response", "link", "distribution"), n_samples = 100, include_uncertainty = TRUE, ... )
object |
Fitted AME model object |
newdata |
Optional dyadic covariates for prediction: a single
3-D array ( |
type |
Character; type of prediction:
|
n_samples |
For type="distribution", number of posterior samples |
include_uncertainty |
Logical; include parameter uncertainty (default TRUE) |
... |
Additional arguments (not used) |
Depending on type:
"response"/"link": Matrix of predictions
"distribution": Array of posterior predictive samples
Cassy Dorff, Shahryar Minhas, Tosin Salau
# Fit model data(YX_nrm) fit <- ame(YX_nrm$Y, Xdyad = YX_nrm$X, R = 2, nscan = 100, burn = 10, odens = 1, verbose = FALSE) # Point predictions Y_pred <- predict(fit) # Predictions on link scale Y_link <- predict(fit, type = "link")# Fit model data(YX_nrm) fit <- ame(YX_nrm$Y, Xdyad = YX_nrm$X, R = 2, nscan = 100, burn = 10, odens = 1, verbose = FALSE) # Point predictions Y_pred <- predict(fit) # Predictions on link scale Y_link <- predict(fit, type = "link")
Returns predictions from an ame_als or
lame_als fit: the fitted linear predictor on the link
scale (type = "link") or the response scale (type = "response",
the default).
## S3 method for class 'ame_als' predict(object, newdata = NULL, type = c("response", "link"), ...)## S3 method for class 'ame_als' predict(object, newdata = NULL, type = c("response", "link"), ...)
object |
an |
newdata |
optional dyadic covariate array matching |
type |
|
... |
ignored. |
With newdata = NULL the training-data fitted values are returned.
Supplying newdata – a dyadic covariate array with the same
actors and dimensions as the fitted design – substitutes the dyadic
covariate contribution while holding the intercept, additive effects and
multiplicative term fixed; it predicts counterfactual dyadic covariates for
the same network, not out-of-sample actors.
A matrix (cross-sectional) or list of matrices (longitudinal).
Generate predictions from a fitted longitudinal AME model. Returns a list of matrices (one per time point) on the requested scale.
## S3 method for class 'lame' predict( object, newdata = NULL, type = c("response", "link"), h = 0L, by_draw = FALSE, interval = c("none", "credible"), probs = c(0.025, 0.975), newexposure = NULL, n_draws = NULL, seed = NULL, ... )## S3 method for class 'lame' predict( object, newdata = NULL, type = c("response", "link"), h = 0L, by_draw = FALSE, interval = c("none", "credible"), probs = c(0.025, 0.975), newexposure = NULL, n_draws = NULL, seed = NULL, ... )
object |
Fitted LAME model object. |
newdata |
Optional list of |
type |
Character; |
h |
Integer >= 0: forecast horizon. When |
by_draw |
When |
interval |
One of |
probs |
Length-2 vector of lower / upper quantiles for the
credible interval when |
newexposure |
Optional length- |
n_draws |
Number of posterior draws to use when |
seed |
Optional RNG seed for the |
... |
Additional arguments (not used). |
List of prediction matrices (one per time point).
Returns a long-format data frame with one row per
(draw, i, j, period) combination, giving the per-draw linear
predictor (or response-scale prediction) at each dyad and period.
Only the regression coefficients vary across .draw: the
additive (a, b) and multiplicative (U, V)
effects are held at their posterior means, so the spread across draws
reflects coefficient uncertainty only, not the full posterior of the
linear predictor.
Intended for marginaleffects- / tidybayes-style
downstream summarisation: column names follow the
.draw / .chain / .iteration / .value
convention so that tidybayes::spread_draws() and
marginaleffects::posterior_draws() auto-dispatch on the
returned data frame. Actor and period names from fit$Y's
dimnames are carried forward into the actor_i,
actor_j, period_label columns.
prediction_draws_long( object, newdata = NULL, type = c("link", "response"), n_draws = 100L, seed = NULL )prediction_draws_long( object, newdata = NULL, type = c("link", "response"), n_draws = 100L, seed = NULL )
object |
A fitted |
newdata |
Optional list of |
type |
One of |
n_draws |
Number of posterior draws to use. Default 100. |
seed |
Optional RNG seed. |
A long-format data frame with columns .chain,
.iteration, .draw, period, period_label,
i, j, actor_i, actor_j, .value.
Returned as a tibble when the tibble package is available;
otherwise a plain data frame.
Print method for penalised ALS time-varying beta
## S3 method for class 'als_dynamic_beta' print(x, digits = 4, ...)## S3 method for class 'als_dynamic_beta' print(x, digits = 4, ...)
x |
An |
digits |
Number of significant digits. |
... |
Ignored. |
x, invisibly. Called for its side effect of printing a
summary of the penalised ALS time-varying coefficient estimates.
Displays a formatted summary of a fitted AME (Additive and Multiplicative Effects) model. This method provides a concise overview of model structure, parameter estimates, and goodness-of-fit statistics without generating new data.
## S3 method for class 'ame' print(x, ...)## S3 method for class 'ame' print(x, ...)
x |
an object of class "ame" from fitting an AME model |
... |
additional arguments (not currently used) |
The print method displays:
Model type (unipartite/bipartite, symmetric/asymmetric)
Network dimensions and observation count
Family and link function used
Number of MCMC iterations
Parameter counts for regression coefficients and latent factors
Basic convergence diagnostics if available
Unlike simulate, this method only formats existing results
for display and does not perform any new computations or data generation.
Invisibly returns the input object (for method chaining)
Cassy Dorff, Shahryar Minhas, Tosin Salau
summary.ame for detailed summaries,
simulate.ame for generating new networks,
predict.ame for predictions
# Fit model data(YX_nrm) fit <- ame(YX_nrm$Y, Xdyad = YX_nrm$X, R = 2, nscan = 100, burn = 10, odens = 1, verbose = FALSE) # Display summary print(fit)# Fit model data(YX_nrm) fit <- ame(YX_nrm$Y, Xdyad = YX_nrm$X, R = 2, nscan = 100, burn = 10, odens = 1, verbose = FALSE) # Display summary print(fit)
Print an ame_als object
## S3 method for class 'ame_als' print(x, digits = 4, ...)## S3 method for class 'ame_als' print(x, digits = 4, ...)
x |
an |
digits |
number of digits to display. |
... |
ignored. |
x, invisibly.
Print methods for AME and LAME simulation objects
## S3 method for class 'ame.sim' print(x, ...) ## S3 method for class 'lame.sim' print(x, ...)## S3 method for class 'ame.sim' print(x, ...) ## S3 method for class 'lame.sim' print(x, ...)
x |
simulation object of class "ame.sim" or "lame.sim" |
... |
additional arguments (not used) |
the simulation object invisibly
Shahryar Minhas
Print bootstrap results for a fast AME fit
## S3 method for class 'boot_ame' print(x, digits = max(3L, getOption("digits") - 3L), ...)## S3 method for class 'boot_ame' print(x, digits = max(3L, getOption("digits") - 3L), ...)
x |
a |
digits |
number of digits to display. |
... |
ignored. |
x, invisibly.
Print method for gof_temporal output
## S3 method for class 'gof_temporal' print(x, ...)## S3 method for class 'gof_temporal' print(x, ...)
x |
A |
... |
Ignored. |
x, invisibly. Called for its side effect of printing a
summary of the temporal-trend posterior-predictive check.
Provides a concise print output for fitted LAME models. When the fit has
two or more dynamic effects active simultaneously
(dynamic_uv + dynamic_ab + dynamic_beta in any combination), a
compact joint table summarising the AR(1) hyperparameters of each
dynamic block is printed instead of a separate paragraph per component.
Disable the compact mode by passing compact = FALSE.
## S3 method for class 'lame' print(x, compact = TRUE, digits = 3, ...)## S3 method for class 'lame' print(x, compact = TRUE, digits = 3, ...)
x |
an object of class "lame" |
compact |
logical: when |
digits |
Number of digits to display in the compact table. Default 3. |
... |
additional arguments (not used) |
the lame object invisibly
Cassy Dorff, Shahryar Minhas, Tosin Salau
Print method for lame_multi
## S3 method for class 'lame_multi' print(x, digits = 3, ...)## S3 method for class 'lame_multi' print(x, digits = 3, ...)
x |
A |
digits |
Number of significant digits. |
... |
Ignored. |
x, invisibly. Called for its side effect of printing a
summary of the pooled multi-panel fit.
Print method for lfo() results
## S3 method for class 'lfo_lame' print(x, ...)## S3 method for class 'lfo_lame' print(x, ...)
x |
A |
... |
Ignored. |
x, invisibly. Called for its side effect of printing a
summary of the leave-future-out cross-validation results.
Print method for per_actor_slopes
## S3 method for class 'per_actor_slopes' print(x, digits = 3, ...)## S3 method for class 'per_actor_slopes' print(x, digits = 3, ...)
x |
A |
digits |
Number of significant digits. |
... |
Ignored. |
x, invisibly. Called for its side effect of printing a
summary of the per-actor time-varying slopes.
Prints a formatted summary of an AME model fit
## S3 method for class 'summary.ame' print(x, digits = 3, ...)## S3 method for class 'summary.ame' print(x, digits = 3, ...)
x |
a summary.ame object |
digits |
number of digits to display (default: 3) |
... |
additional arguments (not used) |
the summary.ame object invisibly
Print a fast AME summary
## S3 method for class 'summary.ame_als' print(x, digits = 4, ...)## S3 method for class 'summary.ame_als' print(x, digits = 4, ...)
x |
a |
digits |
number of digits to display. |
... |
ignored. |
x, invisibly.
Prints a formatted summary of a LAME model fit
## S3 method for class 'summary.lame' print(x, digits = 3, ...)## S3 method for class 'summary.lame' print(x, digits = 3, ...)
x |
a summary.lame object |
digits |
number of digits to display (default: 3) |
... |
additional arguments (not used) |
the summary.lame object invisibly
Bayesian-hygiene helper modelled on rstanarm::prior_summary().
Prints the priors that were actually in effect for a fit, with defaults
filled in. For ame_als fits it just states that the estimator is a
frequentist point estimator and there are no priors.
prior_summary(object, ...) ## Default S3 method: prior_summary(object, ...) ## S3 method for class 'ame' prior_summary(object, ...) ## S3 method for class 'lame' prior_summary(object, ...) ## S3 method for class 'ame_als' prior_summary(object, ...)prior_summary(object, ...) ## Default S3 method: prior_summary(object, ...) ## S3 method for class 'ame' prior_summary(object, ...) ## S3 method for class 'lame' prior_summary(object, ...) ## S3 method for class 'ame_als' prior_summary(object, ...)
object |
a fitted |
... |
ignored. |
object, invisibly.
Aligns dynamic latent positions across time periods to remove arbitrary rotational indeterminacy. This is essential for interpreting temporal trajectories of latent positions, since the latent space is only identified up to rotation at each time point.
Uses Procrustes rotation: at each time step, finds the orthogonal rotation matrix that best aligns the current sender coordinates to the preceding period, then applies it sequentially through the series.
procrustes_align( object = NULL, U = NULL, V = NULL, G = NULL, return_fit = FALSE, per_draw = FALSE, ... )procrustes_align( object = NULL, U = NULL, V = NULL, G = NULL, return_fit = FALSE, per_draw = FALSE, ... )
object |
A fitted |
U |
Optional 3D array |
V |
Optional 3D array |
G |
Optional |
return_fit |
Logical. If TRUE and |
per_draw |
Logical. When TRUE, run Procrustes alignment per
posterior draw rather than on the posterior-mean trajectory. This
uses |
... |
Additional arguments (currently unused). |
For unipartite networks, U and V are aligned independently using separate Procrustes rotations. For symmetric networks, only U is present and aligned.
For bipartite networks, U and V are aligned jointly: separate rotation
matrices are computed for U and V, and the G interaction matrix is updated
as G_aligned = t(R_U) %*% G %*% R_V to preserve the product
U %*% G %*% t(V).
If U is a 2D matrix (static model with a single time point), it is returned unchanged with an informational message.
Alignment is within one fit: each period of a single dynamic trajectory is
rotated onto the period before it. Two different fits are never aligned to
each other automatically. Because raw arrays are accepted, you can do that
explicitly: stack the two fits' U matrices into an [n, R, 2]
array (same actors in the same order, same R) and call
procrustes_align(U = that_array); the second slice comes back
rotated onto the first.
If return_fit = FALSE (default): a list with components
U (aligned sender positions), V (aligned receiver positions,
if applicable), and G (updated interaction matrix, for bipartite).
If return_fit = TRUE: a copy of object with aligned latent
positions replacing the originals.
Cassy Dorff, Shahryar Minhas, Tosin Salau
latent_positions for extracting aligned positions as
a tidy data frame, uv_plot for visualizing latent positions
data(YX_bin_list) # YX_bin_list$Y stores latent-scale values; threshold to 0/1 first Y_bin <- lapply(YX_bin_list$Y, function(y) 1 * (y > 0)) fit <- lame(Y_bin, Xdyad = YX_bin_list$X, R = 2, family = "binary", dynamic_uv = TRUE, burn = 5, nscan = 5, odens = 1, verbose = FALSE) aligned <- procrustes_align(fit) str(aligned$U) # aligned 3D array [n, R, T]data(YX_bin_list) # YX_bin_list$Y stores latent-scale values; threshold to 0/1 first Y_bin <- lapply(YX_bin_list$Y, function(y) 1 * (y > 0)) fit <- lame(Y_bin, Xdyad = YX_bin_list$X, R = 2, family = "binary", dynamic_uv = TRUE, burn = 5, nscan = 5, odens = 1, verbose = FALSE) aligned <- procrustes_align(fit) str(aligned$U) # aligned 3D array [n, R, T]
Single C++ function replacing the bipartite beta/a/b update block in lame.R
rbeta_ab_bip_gibbs_cpp( Z, Xlist, UV_eff, a_current, b_current, s2, g_prior, va, vb, rvar, cvar )rbeta_ab_bip_gibbs_cpp( Z, Xlist, UV_eff, a_current, b_current, s2, g_prior, va, vb, rvar, cvar )
Z |
3D array (nA x nB x T) |
Xlist |
List of T arrays (nA x nB x p) |
UV_eff |
nA x nB matrix (UGV' or U*V') |
a_current |
Current row effects (length nA) |
b_current |
Current column effects (length nB) |
s2 |
Dyadic variance |
g_prior |
G-prior parameter |
va |
Row effect variance (diagonal element of Sab) |
vb |
Column effect variance (diagonal element of Sab) |
rvar |
Whether to update row effects |
cvar |
Whether to update column effects |
List with beta, a, b
For fits run with save_log_lik = "chunked", the per-iteration
pointwise log-likelihood lives in per-column-chunk binary files instead
of fit$log_lik. This helper reconstitutes the
[n_stored, n_obs] matrix in memory by issuing one readBin
per chunk. loo.lame() / waic.lame() call this transparently.
read_log_lik(x)read_log_lik(x)
x |
A fitted |
The full [n_stored, n_obs] double matrix.
Helper functions to recover EZ (linear predictor) and UVPM (posterior
mean of the multiplicative product) matrices. When the fit stores the
quantity (UVPM on asymmetric fits, ULUPM on symmetric
fits), the stored posterior mean is returned directly; otherwise it is
reconstructed from the saved factors.
Note: EZ returns the linear predictor (), not the response:
For Gaussian: (identity link)
For Poisson: (can be negative)
For Binary: = probit inverse of p (can be any real value)
Use YPM for predictions on the response scale.
reconstruct_EZ(fit, X = NULL) reconstruct_UVPM(fit)reconstruct_EZ(fit, X = NULL) reconstruct_UVPM(fit)
fit |
Fitted AME model object |
X |
Covariate array (optional, will use fit$X if available) |
Fits that carry the stored posterior mean (UVPM or, for
symmetric fits, ULUPM) have it returned as-is; older fit objects
without one are rebuilt from the posterior factor means.
Reconstructed matrix
Cassy Dorff, Shahryar Minhas, Tosin Salau
Computes residuals as the difference between observed values and fitted
values. For type = "response", returns Y - fitted(object).
For type = "pearson", returns response residuals scaled by the
standard deviation implied by the family (e.g., sqrt(p*(1-p)) for
binary).
## S3 method for class 'ame' residuals(object, type = c("response", "pearson"), ...)## S3 method for class 'ame' residuals(object, type = c("response", "pearson"), ...)
object |
Fitted AME model object (class "ame"). |
type |
Character; |
... |
Additional arguments (not used). |
An n x n matrix (unipartite) or nA x nB matrix (bipartite) of
residuals. Entries where the original data was NA remain NA.
Cassy Dorff, Shahryar Minhas, Tosin Salau
Returns residuals from an ame_als or
lame_als fit.
## S3 method for class 'ame_als' residuals(object, type = c("response", "working"), ...)## S3 method for class 'ame_als' residuals(object, type = c("response", "working"), ...)
object |
an |
type |
|
... |
ignored. |
type = "response" (default) returns observed Y minus the
response-scale fitted values, so residuals() reconciles with
fitted(). type = "working" returns the Gaussian working-scale
residuals the estimator actually minimised (identical to "response"
for the normal family).
A matrix (cross-sectional) or list of matrices (longitudinal).
Extract residuals from LAME model
## S3 method for class 'lame' residuals(object, type = c("response", "pearson"), ...)## S3 method for class 'lame' residuals(object, type = c("response", "pearson"), ...)
object |
Fitted LAME model |
type |
Type of residuals ("response" or "pearson") |
... |
Additional arguments |
List of residual matrices (one per time point)
Given one or more multi-chain lame fits whose $BETA
is [n_iter, p, T], computes the multivariate R-hat per
coefficient treating the length- path as one
multivariate observation per iteration.
rhat_dynamic_beta(fit_list, coefs = NULL)rhat_dynamic_beta(fit_list, coefs = NULL)
fit_list |
A list of fitted |
coefs |
Optional character vector of coefficient names to
subset (matches |
For chain , let
be the path. With chains and iterations per
chain, define
where is the within-chain sample covariance of
path in chain . Then
and
.
For nearly degenerate covariances we add a tiny ridge to .
Data frame with one row per coefficient: coef,
rhat_mvt, rhat_max_univariate, n_chains,
n_iter_per_chain, n_periods. rhat_mvt is the
Brooks-Gelman multivariate statistic; rhat_max_univariate
is the max over per-(k,t) split-R-hat values for comparison.
data(YX_bin_list) # note: pass seed = to lame() -- an external set.seed() does not vary # the sampler, so it would produce identical chains fit_list <- lapply(c(1L, 2L), function(s) { lame(YX_bin_list$Y, YX_bin_list$X, family = "binary", R = 0, dynamic_beta = "dyad", seed = s, nscan = 60, burn = 15, odens = 5, verbose = FALSE) }) rhat_dynamic_beta(fit_list)data(YX_bin_list) # note: pass seed = to lame() -- an external set.seed() does not vary # the sampler, so it would produce identical chains fit_list <- lapply(c(1L, 2L), function(s) { lame(YX_bin_list$Y, YX_bin_list$X, family = "binary", R = 0, dynamic_beta = "dyad", seed = s, nscan = 60, burn = 15, odens = 5, verbose = FALSE) }) rhat_dynamic_beta(fit_list)
Simulates a matrix where the rows are i.i.d. samples from a multivariate normal distribution
rmvnorm(n, mu, Sigma, Sigma.chol = NULL)rmvnorm(n, mu, Sigma, Sigma.chol = NULL)
n |
sample size |
mu |
multivariate mean vector |
Sigma |
covariance matrix |
Sigma.chol |
Cholesky factorization of |
a matrix with n rows
Cassy Dorff, Shahryar Minhas, Tosin Salau
Gibbs sampling for the covariance matrix of additive row and column effects in the AME model. This function implements the inverse-Wishart posterior update for the covariance matrix Sab.
rSab_fc(a, b, Sab0=NULL, eta0=NULL, rvar=TRUE, cvar=TRUE, symmetric=FALSE)rSab_fc(a, b, Sab0=NULL, eta0=NULL, rvar=TRUE, cvar=TRUE, symmetric=FALSE)
a |
vector of row random effects (additive sender effects) |
b |
vector of column random effects (additive receiver effects) |
Sab0 |
prior scale matrix. Convention (Hoff/amen):
|
eta0 |
prior degrees of freedom for the prior distribution. Default is 4, which is the minimum for a proper prior with 2x2 matrix. |
rvar |
logical: should row variance be updated? (default TRUE) |
cvar |
logical: should column variance be updated? (default TRUE) |
symmetric |
logical: is this a symmetric network? (default FALSE) |
The function implements different update strategies:
Full update: When both rvar and cvar are TRUE, updates the full 2x2 covariance matrix using an inverse-Wishart distribution
Row variance only: When only rvar is TRUE, updates only Sab[1,1]
Column variance only: When only cvar is TRUE, updates only Sab[2,2]
Symmetric case: When symmetric is TRUE, draws a single shared variance for the row and column effects (inverse-gamma update) with zero covariance
Updated covariance matrix Sab (2x2 matrix with variances on diagonal and covariance off-diagonal)
Cassy Dorff, Shahryar Minhas, Tosin Salau
Replaces the nested R loops for bipartite dynamic_uv in lame.R. Uses direct 2x2 inverse formula for common R=2 case.
rUV_dynamic_bip_fc_cpp(U_cube, V_cube, E, G, rho_uv, sigma_uv, s2)rUV_dynamic_bip_fc_cpp(U_cube, V_cube, E, G, rho_uv, sigma_uv, s2)
U_cube |
3D array (nA x RA x T) |
V_cube |
3D array (nB x RB x T) |
E |
3D array of residuals (nA x nB x T) |
G |
Interaction matrix (RA x RB) |
rho_uv |
AR(1) persistence parameter |
sigma_uv |
Innovation standard deviation |
s2 |
Dyadic variance |
List with updated U_cube, V_cube
Updates latent factor positions U and V that evolve over time according to an AR(1) process: u_{i,t} = rho * u_{i,t-1} + epsilon_{i,t}
rUV_dynamic_fc(U, V, ET, rho_uv, sigma_uv, s2, shrink=TRUE, symmetric=FALSE)rUV_dynamic_fc(U, V, ET, rho_uv, sigma_uv, s2, shrink=TRUE, symmetric=FALSE)
U |
3D array of current U positions (n x R x T) |
V |
3D array of current V positions (n x R x T) |
ET |
3D array of residuals (n x n x T) |
rho_uv |
AR(1) autoregressive parameter for latent positions |
sigma_uv |
Innovation standard deviation for latent positions |
s2 |
dyadic variance |
shrink |
whether to apply shrinkage (default TRUE) |
symmetric |
whether the network is symmetric (default FALSE) |
list with updated U and V arrays
Cassy Dorff, Shahryar Minhas, Tosin Salau
Update dynamic latent positions using AR(1) process
rUV_dynamic_fc_cpp( U_current, V_current, ET, rho_uv, sigma_uv, s2, shrink, symmetric )rUV_dynamic_fc_cpp( U_current, V_current, ET, rho_uv, sigma_uv, s2, shrink, symmetric )
U_current |
Current 3D array of U positions (n x R x T) |
V_current |
Current 3D array of V positions (n x R x T) |
ET |
3D array of residuals (n x n x T) |
rho_uv |
AR(1) autoregressive parameter for latent positions |
sigma_uv |
Innovation standard deviation for latent positions |
s2 |
Dyadic variance |
shrink |
Whether to apply shrinkage |
symmetric |
Whether network is symmetric |
List with updated U and V arrays
Like rUV_dynamic_fc but lets each actor's latent position either drift
under the AR(1) prior or jump under a diffuse N(0, kappa^2) snap prior, chosen
per actor-period by a Gaussian log-marginal model selection.
rUV_dynamic_snap_fc( U, V, ET, rho_uv, sigma_uv, s2, kappa, pi_snap, delta_u_current = NULL, delta_v_current = NULL, shrink = TRUE, symmetric = FALSE )rUV_dynamic_snap_fc( U, V, ET, rho_uv, sigma_uv, s2, kappa, pi_snap, delta_u_current = NULL, delta_v_current = NULL, shrink = TRUE, symmetric = FALSE )
U |
3D array of current U positions (n x R x T) |
V |
3D array of current V positions (n x R x T) |
ET |
3D array of residuals (n x n x T) |
rho_uv |
AR(1) autoregressive parameter for the drift prior |
sigma_uv |
Innovation standard deviation for the drift prior |
s2 |
dyadic variance |
kappa |
diffuse snap-prior standard deviation |
pi_snap |
prior snap probability |
delta_u_current |
current sender-side snap indicators. If |
delta_v_current |
current receiver-side snap indicators. If |
shrink |
whether to apply shrinkage (default TRUE) |
symmetric |
whether the network is symmetric (default FALSE) |
list with updated U, V arrays and delta_u, delta_v snap indicators
Cassy Dorff, Shahryar Minhas, Tosin Salau
Like rUV_dynamic_fc_cpp but, for t > 0, chooses per actor between an AR(1) drift prior and a diffuse N(0, kappa^2 I) snap prior via a Gaussian log-marginal-likelihood model selection, drawing a Bernoulli snap indicator delta and sampling the latent position from the selected posterior.
rUV_dynamic_snap_fc_cpp( U_current, V_current, ET, rho_uv, sigma_uv, s2, kappa, pi_snap, delta_u_current, delta_v_current, shrink, symmetric )rUV_dynamic_snap_fc_cpp( U_current, V_current, ET, rho_uv, sigma_uv, s2, kappa, pi_snap, delta_u_current, delta_v_current, shrink, symmetric )
U_current |
Current 3D array of U positions (n x R x T) |
V_current |
Current 3D array of V positions (n x R x T) |
ET |
3D array of residuals (n x n x T) |
rho_uv |
AR(1) autoregressive parameter for the drift prior |
sigma_uv |
Innovation standard deviation for the drift prior |
s2 |
Dyadic variance |
kappa |
Diffuse snap-prior standard deviation (kappa^2 >> sigma_uv^2) |
pi_snap |
Prior snap probability |
delta_u_current |
Current sender-side snap indicators from the previous sweep |
delta_v_current |
Current receiver-side snap indicators from the previous sweep |
shrink |
Whether to apply shrinkage |
symmetric |
Whether network is symmetric |
List with updated U, V arrays and delta_u, delta_v snap indicators
Like rUV_dynamic_fc but the AR(1) innovations are Student-t via a
scale-mixture of normals, a continuous heavy-tailed alternative to snap-shift.
rUV_dynamic_t_fc( U, V, ET, rho_uv, sigma_uv, s2, nu, lambda_u = NULL, lambda_v = NULL, shrink = TRUE, symmetric = FALSE )rUV_dynamic_t_fc( U, V, ET, rho_uv, sigma_uv, s2, nu, lambda_u = NULL, lambda_v = NULL, shrink = TRUE, symmetric = FALSE )
U |
3D array of current U positions (n x R x T) |
V |
3D array of current V positions (n x R x T) |
ET |
3D array of residuals (n x n x T) |
rho_uv |
AR(1) autoregressive parameter |
sigma_uv |
Innovation scale |
s2 |
dyadic variance |
nu |
Student-t degrees of freedom |
lambda_u |
current local scales for U (n x T) |
lambda_v |
current local scales for V (n x T) |
shrink |
whether to apply shrinkage (default TRUE) |
symmetric |
whether the network is symmetric (default FALSE) |
list with updated U, V arrays and lambda_u, lambda_v local scales
Cassy Dorff, Shahryar Minhas, Tosin Salau
Like rUV_dynamic_fc_cpp but each AR(1) innovation is Student-t rather than
Gaussian, via a scale-mixture: the innovation for u[t, i] has variance
sigma^2 / lambda[t, i] with lambda[t, i] distributed as
Gamma(nu/2, nu/2). Provides a
continuous heavy-tailed alternative to the discrete snap-shift model.
rUV_dynamic_t_fc_cpp( U_current, V_current, ET, rho_uv, sigma_uv, s2, nu, lambda_u, lambda_v, shrink, symmetric )rUV_dynamic_t_fc_cpp( U_current, V_current, ET, rho_uv, sigma_uv, s2, nu, lambda_u, lambda_v, shrink, symmetric )
U_current |
Current 3D array of U positions (n x R x T) |
V_current |
Current 3D array of V positions (n x R x T) |
ET |
3D array of residuals (n x n x T) |
rho_uv |
AR(1) autoregressive parameter |
sigma_uv |
Innovation scale |
s2 |
Dyadic variance |
nu |
Student-t degrees of freedom |
lambda_u |
Current local scales for U (n x T) |
lambda_v |
Current local scales for V (n x T) |
shrink |
Whether to apply shrinkage |
symmetric |
Whether network is symmetric |
List with updated U, V arrays and lambda_u, lambda_v local scales
A Gibbs sampler for updating the multiplicative effect matrices U and V
in the symmetric case. In this case U%*%t(V) is symmetric, so
this is parameterized as V=U%*%L where L is the
diagonal matrix of eigenvalues of U%*%t(V).
rUV_sym_fc(E, U, V, s2 = 1, shrink=TRUE)rUV_sym_fc(E, U, V, s2 = 1, shrink=TRUE)
E |
square residual relational matrix |
U |
current value of U |
V |
current value of V |
s2 |
dyadic variance |
shrink |
adaptively shrink the factors with a hierarchical prior |
U |
a new value of U |
V |
a new value of V |
Cassy Dorff, Shahryar Minhas, Tosin Salau
U0<-matrix(rnorm(30,2),30,2) ; V0<-U0%*%diag(c(3,-2)) E<- U0%*%t(V0) + matrix(rnorm(30^2),30,30) rUV_sym_fcU0<-matrix(rnorm(30,2),30,2) ; V0<-U0%*%diag(c(3,-2)) E<- U0%*%t(V0) + matrix(rnorm(30^2),30,30) rUV_sym_fc
Vectorized probit update for bipartite binary networks without dyadic correlation.
rZ_bin_bip_batch_cpp(Z, EZ, Y)rZ_bin_bip_batch_cpp(Z, EZ, Y)
Z |
3D array of latent values (nA x nB x T) |
EZ |
3D array of expected values (nA x nB x T) |
Y |
3D array of observed values (nA x nB x T) |
Updated Z array
Replaces the per-time-period R loop with a single C++ call that loops internally, reducing R-to-C++ transition overhead.
rZ_nrm_batch_cpp(Z, EZ, rho, s2, Y)rZ_nrm_batch_cpp(Z, EZ, rho, s2, Y)
Z |
3D array of latent values (n x n x T) |
EZ |
3D array of expected values (n x n x T) |
rho |
Dyadic correlation parameter |
s2 |
Dyadic variance |
Y |
3D array of observed values (n x n x T) |
List with updated Z and E_nrm (residuals)
Simulates missing values of a sociomatrix under a normal AME model
rZ_nrm_fc(Z, EZ, rho,s2, Y)rZ_nrm_fc(Z, EZ, rho,s2, Y)
Z |
a square matrix, the current value of Z |
EZ |
expected value of Z |
rho |
dyadic correlation |
s2 |
dyadic variance |
Y |
square relational matrix |
a square matrix, equal to Y at non-missing values
Cassy Dorff, Shahryar Minhas, Tosin Salau
Updates the latent variable Z in a Poisson AME model using a Metropolis-Hastings step. The model assumes y_{i,j} ~ Poisson(exp(z_{i,j})) where z_{i,j} is the latent variable representing the log mean.
rZ_pois_fc(Z, EZ, rho, s2, Y)rZ_pois_fc(Z, EZ, rho, s2, Y)
Z |
a square matrix, the current value of the latent variable |
EZ |
expected value of Z (regression effects + random effects) |
rho |
dyadic correlation |
s2 |
dyadic variance (overdispersion parameter) |
Y |
square relational matrix of observed counts |
updated value of Z
Cassy Dorff, Shahryar Minhas, Tosin Salau
Forward-filter / backward-sample the AR(1) state-space model for the dynamic-block beta coefficients. Returns the joint draw of beta_dyn at every time period.
sample_beta_dynamic_cpp( Xdyn_list, Xstat_list, Z_list, offset_list, beta_static, rho_by_coef, sigma_by_coef, Lambda, beta0_mean, beta0_cov, s2, dyad_rho, bipartite, symmetric, use_dyad_rho )sample_beta_dynamic_cpp( Xdyn_list, Xstat_list, Z_list, offset_list, beta_static, rho_by_coef, sigma_by_coef, Lambda, beta0_mean, beta0_cov, s2, dyad_rho, bipartite, symmetric, use_dyad_rho )
Xdyn_list |
T-length list of (n*n) x p_dyn long-format design matrices for the dynamic block (column-major reshape per period). |
Xstat_list |
T-length list of (n*n) x p_static long-format design matrices for the static block. |
Z_list |
T-length list of (n x n) latent matrices. |
offset_list |
T-length list of (n x n) offset matrices (a_i + b_j + U_i'V_j contributions; everything that's not in X*beta). |
beta_static |
Length p_static current static beta vector. |
rho_by_coef |
Length p_dyn vector of AR(1) rho values for each dynamic coefficient. (Per-block but expanded per-column for vectorised indexing.) |
sigma_by_coef |
Length p_dyn vector of AR(1) innovation standard deviations for each dynamic coefficient. |
Lambda |
Block-diagonal innovation scale matrix (p_dyn x p_dyn). Combined with sigma^2 to give Q = sigma^2 * Lambda. |
beta0_mean |
Length p_dyn prior mean for the first state beta_1 (the prior is placed directly on beta_1, no predict step at t = 1). |
beta0_cov |
p_dyn x p_dyn prior covariance for beta_1. Must be a fixed matrix that does not depend on the current (rho, sigma) draw so the transition-only hyperparameter conditionals remain exact. |
s2 |
Dyadic variance. |
dyad_rho |
Dyadic correlation (ignored when use_dyad_rho=FALSE). |
bipartite |
Whether the network is bipartite. |
symmetric |
Whether the network is symmetric. |
use_dyad_rho |
Whether to use the dyad-corr branch (TRUE only for unipartite, asymmetric, with a non-zero rho). |
List with: path – a (T x p_dyn) matrix of beta draws (one row per period); chol_fail – integer count of Cholesky failures.
Conjugate Gaussian update for the static coefficient block, treating the
dynamic path as known. Uses a flat-ish ridge-style prior prior_prec on
the static beta (typically diag(1/g) to match the existing g-prior path).
sample_beta_static_cpp( Xdyn_list, Xstat_list, Z_list, offset_list, beta_dyn_path, prior_mean, prior_prec, s2, dyad_rho, bipartite, symmetric, use_dyad_rho )sample_beta_static_cpp( Xdyn_list, Xstat_list, Z_list, offset_list, beta_dyn_path, prior_mean, prior_prec, s2, dyad_rho, bipartite, symmetric, use_dyad_rho )
Xdyn_list |
T-length list of long-format dynamic design matrices. |
Xstat_list |
T-length list of long-format static design matrices. |
Z_list |
T-length list of latent (n x n) matrices. |
offset_list |
T-length list of (n x n) offsets. |
beta_dyn_path |
(T x p_dyn) dynamic path matrix. |
prior_mean |
Length p_static prior mean. |
prior_prec |
p_static x p_static prior precision. |
s2 |
Dyadic variance. |
dyad_rho |
Dyadic correlation. |
bipartite |
TRUE/FALSE. |
symmetric |
TRUE/FALSE. |
use_dyad_rho |
TRUE/FALSE. |
List with: beta – length p_static; chol_fail – integer.
Gibbs update of the per-period additive effects under the AR(1) state model with stationary initial condition. For each actor and period the full conditional combines the AR(1) bridge prior (stationary init at t = 1) with the dyadic residual likelihood: resid_ij = a_i + b_j + e_ij, e_ij ~ N(0, s2). The reciprocal effect (b_j for the a-step, the freshly updated a_i for the b-step) is subtracted from each residual, missing residuals are skipped, and for symmetric networks each dyad contributes exactly once (resid(i,j) = a_i + a_j + e_ij).
sample_dynamic_ab_cpp( a_current, b_current, Z_array, EZ_array, rho_ab, sigma_ab, s2, symmetric )sample_dynamic_ab_cpp( a_current, b_current, Z_array, EZ_array, rho_ab, sigma_ab, s2, symmetric )
a_current |
Current 2D array of row effects (n x T) |
b_current |
Current 2D array of column effects (n x T) |
Z_array |
3D array of latent positions (n x n x T) |
EZ_array |
3D array of expected values without additive effects (n x n x T) |
rho_ab |
AR(1) parameter for additive effects |
sigma_ab |
Innovation standard deviation |
s2 |
Dyadic residual variance |
symmetric |
Whether the network is symmetric |
List with updated a and b arrays
Sample AR(1) parameter for dynamic additive effects
sample_rho_ab_cpp( a_mat, b_mat, sigma_ab, rho_current, symmetric, prior_mean = 0, prior_sd = -1 )sample_rho_ab_cpp( a_mat, b_mat, sigma_ab, rho_current, symmetric, prior_mean = 0, prior_sd = -1 )
a_mat |
Matrix of row effects (n x T) |
b_mat |
Matrix of column effects (n x T) |
sigma_ab |
Innovation standard deviation |
rho_current |
Current value of rho |
symmetric |
Whether the network is symmetric |
prior_mean |
Prior mean for rho. Used only when |
prior_sd |
Prior SD for rho. |
Updated rho value
Truncated-Normal full conditional, one rho per block.
sample_rho_beta_cpp( beta_path, group_id, n_groups, Lambda_inv, sigma_by_coef, rho_current, rho_prior_mean, rho_prior_sd, rho_lower = 0, rho_upper = 0.999 )sample_rho_beta_cpp( beta_path, group_id, n_groups, Lambda_inv, sigma_by_coef, rho_current, rho_prior_mean, rho_prior_sd, rho_lower = 0, rho_upper = 0.999 )
beta_path |
(T x p_dyn) matrix of beta draws. |
group_id |
Length p_dyn integer vector (1-based) of block IDs. |
n_groups |
Number of distinct block IDs. |
Lambda_inv |
(p_dyn x p_dyn) inverse of the (full) Lambda scale. |
sigma_by_coef |
Length p_dyn vector of per-coef sigma (block-shared). |
rho_current |
Length n_groups vector of current rho values. |
rho_prior_mean |
Length n_groups vector of prior means. |
rho_prior_sd |
Length n_groups vector of prior SDs. |
rho_lower |
Lower truncation bound (typically 0). |
rho_upper |
Upper truncation bound (typically 0.999). |
Length n_groups vector of new rho values.
Independence Metropolis-Hastings update coherent with the stationary
AR(1) initial condition used by the dynamic UV kernels. The proposal is
the conjugate Normal implied by the transitions and the
Normal(prior_mean, prior_sd^2) prior, drawn truncated to (-0.99, 0.99)
via the inverse CDF; the acceptance ratio supplies the t = 1 stationary
factor proportional to (1 - rho^2)^(nR / 2) * exp(-(1 - rho^2) *
S1 / (2 * sigma^2))
that the Gaussian proposal omits. Defaults (prior_mean = 0,
prior_sd = 1) preserve the historical behaviour; lame::lame() passes
the user-set prior$rho_uv_mean / prior$rho_uv_sd explicitly.
sample_rho_uv( U_cube, V_cube, sigma_uv, rho_current, symmetric, prior_mean = 0, prior_sd = 1 )sample_rho_uv( U_cube, V_cube, sigma_uv, rho_current, symmetric, prior_mean = 0, prior_sd = 1 )
U_cube |
3D array of U positions (n x R x T) |
V_cube |
3D array of V positions (n x R x T) |
sigma_uv |
Innovation standard deviation |
rho_current |
Current value of rho |
symmetric |
Whether network is symmetric |
prior_mean |
Prior mean for rho (default 0) |
prior_sd |
Prior SD for rho (default 1) |
Updated rho value
Sample innovation variance for dynamic additive effects
sample_sigma_ab_cpp( a_mat, b_mat, rho_ab, symmetric, prior_shape = 2, prior_scale = 1 )sample_sigma_ab_cpp( a_mat, b_mat, rho_ab, symmetric, prior_shape = 2, prior_scale = 1 )
a_mat |
Matrix of row effects (n x T) |
b_mat |
Matrix of column effects (n x T) |
rho_ab |
AR(1) parameter |
symmetric |
Whether the network is symmetric |
prior_shape |
Shape parameter for inverse gamma prior |
prior_scale |
Scale parameter for inverse gamma prior |
Updated sigma_ab value
Inverse-Gamma full conditional, one sigma per block.
sample_sigma_beta_cpp( beta_path, group_id, n_groups, Lambda_inv, rho_by_group, prior_shape, prior_scale )sample_sigma_beta_cpp( beta_path, group_id, n_groups, Lambda_inv, rho_by_group, prior_shape, prior_scale )
beta_path |
(T x p_dyn) matrix. |
group_id |
Length p_dyn integer vector (1-based) of block IDs. |
n_groups |
Number of distinct block IDs. |
Lambda_inv |
(p_dyn x p_dyn) inverse of the (full) Lambda scale. |
rho_by_group |
Length n_groups vector of current rho values. |
prior_shape |
Length n_groups vector of IG shape parameters. |
prior_scale |
Length n_groups vector of IG scale parameters. |
Length n_groups vector of new sigma values.
Sample innovation variance for dynamic latent factors
sample_sigma_uv(U_cube, V_cube, rho_uv, symmetric)sample_sigma_uv(U_cube, V_cube, rho_uv, symmetric)
U_cube |
3D array of U positions (n x R x T) |
V_cube |
3D array of V positions (n x R x T) |
rho_uv |
AR(1) parameter |
symmetric |
Whether network is symmetric |
Updated sigma_uv value
Reports which estimation routine produced a fitted object and what
uncertainty information, if any, is available. Methods exist for
ame_als fits (the fast block coordinate descent estimator) and
boot_ame bootstrap objects.
sampler_describe(object, verbose = TRUE) ## S3 method for class 'ame_als' sampler_describe(object, verbose = TRUE) ## S3 method for class 'boot_ame' sampler_describe(object, verbose = TRUE) ## S3 method for class 'ame' sampler_describe(object, verbose = TRUE) ## S3 method for class 'lame' sampler_describe(object, verbose = TRUE)sampler_describe(object, verbose = TRUE) ## S3 method for class 'ame_als' sampler_describe(object, verbose = TRUE) ## S3 method for class 'boot_ame' sampler_describe(object, verbose = TRUE) ## S3 method for class 'ame' sampler_describe(object, verbose = TRUE) ## S3 method for class 'lame' sampler_describe(object, verbose = TRUE)
object |
a fitted object ( |
verbose |
logical; if |
The input object, invisibly.
Several dyadic variables measured on 18 members of a monastery.
A socioarray whose dimensions represent nominators, nominatees and relations.
Each monk was asked to rank up to three other monks on a variety of positive
and negative relations. A rank of three indicates the "highest" ranking for
a particular relational variable. The relations like_m1 and like_m2
are evaluations of liking at one and two timepoints previous to when the
other relations (including like) were measured. In the copy of this
array that circulated with amen, the three liking layers had their
monks in a different order from the array's row and column names; they
are re-aligned here so every layer follows the same actor labels.
Originally available at http://moreno.ss.uci.edu/data.html#sampson
(site no longer accessible).
Number of dominance encounters between 28 female bighorn sheep. Cell (i,j) records the number of times sheep i dominated sheep j. From Hass (1991).
A list consisting of the following:
dom: a directed socioarray recording the number of
dominance encounters.
age: the age of each sheep in years.
Originally available at http://moreno.ss.uci.edu/data.html#sheep
(site no longer accessible).
Simulate posterior distributions from fitted AME model
simulate_posterior( fit, component = c("UV", "ab", "beta", "Y"), n_samples = NULL, seed = NULL )simulate_posterior( fit, component = c("UV", "ab", "beta", "Y"), n_samples = NULL, seed = NULL )
fit |
Fitted ame model object |
component |
Character; which component to simulate: "UV", "ab", "beta", "Y" |
n_samples |
Number of posterior samples to return. Defaults to
|
seed |
Random seed for reproducibility |
This function can simulate posterior distributions even when they weren't saved during MCMC, by using the posterior means and variance components.
For more accurate posteriors, use posterior_options() during model fitting to save the actual MCMC samples.
Array or matrix of posterior samples
Cassy Dorff, Shahryar Minhas, Tosin Salau
# Fit a model with multiplicative effects data(YX_nrm) fit <- ame(YX_nrm$Y, Xdyad = YX_nrm$X, R = 2, nscan = 100, burn = 10, odens = 1, verbose = FALSE) # Get posterior samples of regression coefficients beta_post <- simulate_posterior(fit, "beta", n_samples = 50)# Fit a model with multiplicative effects data(YX_nrm) fit <- ame(YX_nrm$Y, Xdyad = YX_nrm$X, R = 2, nscan = 100, burn = 10, odens = 1, verbose = FALSE) # Get posterior samples of regression coefficients beta_post <- simulate_posterior(fit, "beta", n_samples = 50)
Generates multiple network realizations from a fitted AME model. This function performs conditional posterior predictive simulation: it draws from stored MCMC samples when they are available and uses posterior means for latent components that were not retained.
Unlike print.ame, which only displays fitted quantities,
simulate.ame draws new networks from the posterior predictive
distribution.
## S3 method for class 'ame' simulate( object, nsim = 100, seed = NULL, newdata = NULL, burn_in = 0, thin = 1, return_latent = FALSE, ... )## S3 method for class 'ame' simulate( object, nsim = 100, seed = NULL, newdata = NULL, burn_in = 0, thin = 1, return_latent = FALSE, ... )
object |
fitted model object of class "ame" |
nsim |
number of networks to simulate (default: 100) |
seed |
random seed for reproducibility |
newdata |
optional list containing new covariate data:
If NULL, uses covariates from original model fit |
burn_in |
number of initial MCMC samples to discard (default: 0, assumes burn-in already removed) |
thin |
thinning interval for MCMC samples (default: 1, use every sample) |
return_latent |
logical: return latent Z matrices in addition to Y? (default: FALSE) |
... |
additional arguments (not currently used) |
Model:
The AME model represents networks through a latent variable framework:
where F is the observation model (e.g., probit for binary) and Z is the latent network:
Components:
: regression coefficients for dyadic/nodal covariates
: additive sender and receiver random effects
: multiplicative latent factors (dimension R)
: dyadic random effects with correlation
Simulation:
For each simulated network k = 1, ..., nsim:
Parameter draw: Draw parameter set from MCMC chains:
Sample iteration s uniformly from stored MCMC samples
Extract , variance components
Random effects: Sample new random effects from posterior distributions:
for i = 1, ..., n (row effects)
for j = 1, ..., m (column effects)
Fresh draws from the posterior variance carry random-effect uncertainty into the simulated networks
Latent network: Build expected latent positions:
where are posterior mean latent factors
Dyadic correlation: Add correlated noise structure:
where has covariance structure:
Observation model: Generate the observed network:
Binary:
Normal:
Poisson:
Other families use appropriate link functions
Sources of uncertainty:
The simulation captures three types of uncertainty:
Parameter uncertainty: Different MCMC samples yield different
Random effect uncertainty: Fresh draws from for each simulation
Dyadic uncertainty: Correlated random noise
The resulting simulations propagate uncertainty from the stored parameter draws and from fresh dyadic/random-effect draws. Latent components that were not stored as MCMC draws are held at their posterior means.
Latent-factor draws:
Multiplicative effects (U, V) use posterior means unless the fit retained compatible latent-factor draws. Storing full latent-factor chains can require substantial additional memory.
Symmetric Networks:
For symmetric networks, the model enforces and ,
and the latent matrix Z is symmetrized before generating observations.
A list with components:
list of nsim simulated networks in the same format as the original data
if return_latent=TRUE, list of nsim latent Z matrices
the family of the model (binary, normal, etc.)
network mode (unipartite or bipartite)
Cassy Dorff, Shahryar Minhas, Tosin Salau
# Fit a model data(YX_bin) fit <- ame(YX_bin$Y, Xdyad = YX_bin$X, burn = 10, nscan = 100, odens = 1, family = "binary", verbose = FALSE) # Simulate 10 networks from posterior sims <- simulate(fit, nsim = 10)# Fit a model data(YX_bin) fit <- ame(YX_bin$Y, Xdyad = YX_bin$X, burn = 10, nscan = 100, odens = 1, family = "binary", verbose = FALSE) # Simulate 10 networks from posterior sims <- simulate(fit, nsim = 10)
Draws nsim replicates of Y from the fitted ALS mean structure:
mu, beta, a, b, U, V, and the
family-appropriate noise distribution. For directed unipartite normal and
binary fits, reciprocal dyads use the fitted residual rho. The returned
object has class
"ame.sim" so it is compatible with plot_ppc_*-style consumers
(where applicable).
## S3 method for class 'ame_als' simulate(object, nsim = 1, seed = NULL, ...)## S3 method for class 'ame_als' simulate(object, nsim = 1, seed = NULL, ...)
object |
an |
nsim |
integer; number of replicates to simulate (default 1). |
seed |
optional RNG seed. |
... |
ignored. |
ALS is a point estimator. simulate.ame_als holds
mu, beta, a, b, U, V at the point estimate and resamples the noise.
For uncertainty over the parameters themselves, use
ame_als_bootstrap (whose replicates each carry their own
resampled Y) and combine those simulations.
An object of class "ame.sim" with element Y – a list
of nsim simulated outcome arrays (one matrix for a cross-section,
one list-of-matrices per slice for a longitudinal fit).
Generates multiple longitudinal network realizations from a fitted LAME (Longitudinal AME) model. This function performs conditional posterior predictive simulation for dynamic networks: it draws from stored MCMC samples when available and uses posterior means for latent components that were not retained.
## S3 method for class 'lame' simulate( object, nsim = 100, seed = NULL, newdata = NULL, n_time = NULL, burn_in = 0, thin = 1, return_latent = FALSE, start_from = "posterior", ... )## S3 method for class 'lame' simulate( object, nsim = 100, seed = NULL, newdata = NULL, n_time = NULL, burn_in = 0, thin = 1, return_latent = FALSE, start_from = "posterior", ... )
object |
fitted model object of class "lame" |
nsim |
number of network trajectories to simulate (default: 100) |
seed |
random seed for reproducibility |
newdata |
optional list containing new covariate data:
If NULL, uses covariates from original model fit |
n_time |
number of time periods to simulate. If NULL, uses same as original data |
burn_in |
number of initial MCMC samples to discard (default: 0) |
thin |
thinning interval for MCMC samples (default: 1, use every sample) |
return_latent |
logical: return latent Z matrices in addition to Y? (default: FALSE) |
start_from |
character: how to initialize the simulation
|
... |
additional arguments (not currently used) |
Mathematical Framework for Longitudinal Networks:
The LAME model extends AME to multiple time periods T with potential temporal dependencies. For each time t = 1, ..., T:
where the latent network evolves as:
Temporal Dynamics:
LAME can incorporate three types of temporal dependencies:
Static Effects: Parameters constant over time
, for all t
, for all t
Dynamic Additive Effects: AR(1) process for random effects
where is the temporal correlation parameter
Dynamic Multiplicative Effects: AR(1) for latent factors
Uncertainty Quantification Process for Trajectories:
For each simulated trajectory k = 1, ..., nsim:
Step 1: Parameter Sampling
Draw MCMC iteration s uniformly from stored posterior samples
Extract static parameters: , variance components
Extract temporal parameters if applicable: ,
Step 2: Initialize at t = 1
Depending on start_from parameter:
"posterior": Use posterior means as starting values
"random": Draw from stationary distribution
For additive effects:
For multiplicative effects: Initialize from prior
Step 3: Evolve Through Time
For each t = 2, ..., T:
a) Update Dynamic Effects (if applicable):
where
The innovation variance ensures stationarity
b) Construct Latent Network:
c) Add Dyadic Noise:
with correlation structure preserved from AME model
d) Generate Observations: Apply appropriate link function based on family
Sources of Uncertainty in Longitudinal Context:
Cross-sectional uncertainty (as in AME):
Parameter uncertainty from MCMC
Random effect variability
Dyadic noise
Temporal uncertainty:
Uncertainty in temporal correlation parameters
Innovation noise in AR(1) processes
Propagation of uncertainty through time (compounds over periods)
Initial condition uncertainty:
Different starting values lead to different trajectories
Captured through start_from options
Interpretation of Multiple Trajectories:
Each simulated trajectory represents one possible evolution of the network conditional on the stored fit. Variation across trajectories captures:
Model parameter uncertainty
Stochastic variation in temporal evolution
Accumulated uncertainty over time periods
The ensemble of trajectories provides prediction intervals that widen over time, reflecting increasing uncertainty in longer-term forecasts.
Special Considerations:
Temporal Correlation: Higher values create smoother
trajectories with more persistence
Stationarity: The AR(1) innovation variance is scaled to maintain stationary marginal distributions
Missing Time Points: If simulating beyond observed data (n_time > T_observed), covariates are recycled or set to zero with appropriate warnings
Limitations:
As with simulate.ame, multiplicative effects use posterior means unless the
fit retained compatible latent-factor draws. Storing complete MCMC chains for
at all time points is memory-intensive for large
networks and long time series.
A list with components:
list of nsim simulated longitudinal network trajectories, each element is a list of T networks
if return_latent=TRUE, list of nsim latent Z trajectories
the family of the model (binary, normal, etc.)
network mode (unipartite or bipartite)
number of time periods
Shahryar Minhas
# Create simple longitudinal network data set.seed(1) n <- 10 nms <- paste0("n", 1:n) Y_list <- list( matrix(rnorm(n * n), n, n, dimnames = list(nms, nms)), matrix(rnorm(n * n), n, n, dimnames = list(nms, nms)) ) diag(Y_list[[1]]) <- diag(Y_list[[2]]) <- NA fit <- lame(Y_list, family = "normal", nscan = 50, burn = 10, odens = 1, verbose = FALSE, plot = FALSE) # Simulate 10 network trajectories from posterior sims <- simulate(fit, nsim = 10)# Create simple longitudinal network data set.seed(1) n <- 10 nms <- paste0("n", 1:n) Y_list <- list( matrix(rnorm(n * n), n, n, dimnames = list(nms, nms)), matrix(rnorm(n * n), n, n, dimnames = list(nms, nms)) ) diag(Y_list[[1]]) <- diag(Y_list[[2]]) <- NA fit <- lame(Y_list, family = "normal", nscan = 50, burn = 10, odens = 1, verbose = FALSE, plot = FALSE) # Simulate 10 network trajectories from posterior sims <- simulate(fit, nsim = 10)
Simulates a relational matrix from a Poisson distribution given the log mean values
simY_pois(EZ)simY_pois(EZ)
EZ |
square matrix giving the log expected values of the relational matrix |
a square matrix of counts
Cassy Dorff, Shahryar Minhas, Tosin Salau
Summarize snap indices by actor category
snap_category_summary(fit, groups, years = NULL, side = c("u", "v"))snap_category_summary(fit, groups, years = NULL, side = c("u", "v"))
fit |
a |
groups |
a named list mapping group names to actor names/indices, or a named vector whose values are group labels and whose names are actors. |
years |
optional year/period names or indices. Default uses every period. |
side |
|
A data frame with one row per group-year.
Computes draw-level averages of MCMC snap indicators over selected actors and
years. The result is useful for system-level rupture indices and focal-actor
rupture indices. Fits should be run with keep_snap_draws = "draws" for
posterior uncertainty. If only snap_prob is present, the function
returns a single score row and warns that intervals cannot be read as
posterior intervals.
snap_index_draws(fit, actors = NULL, years = NULL, side = c("u", "v"))snap_index_draws(fit, actors = NULL, years = NULL, side = c("u", "v"))
fit |
a |
actors |
optional actor names or indices. Default uses every actor on the selected side. |
years |
optional year/period names or indices. Default uses every period. |
side |
|
A data frame with columns draw, year, side,
n_actors, and snap_index.
Summarize posterior snap indices
snap_index_summary( fit, actors = NULL, years = NULL, side = c("u", "v"), probs = c(0.025, 0.1, 0.5, 0.9, 0.975) )snap_index_summary( fit, actors = NULL, years = NULL, side = c("u", "v"), probs = c(0.025, 0.1, 0.5, 0.9, 0.975) )
fit |
a |
actors |
optional actor names or indices. Default uses every actor on the selected side. |
years |
optional year/period names or indices. Default uses every period. |
side |
|
probs |
numeric quantiles to report. |
A data frame with one row per selected year.
Ranks year-level snap indices within each retained draw, with rank 1 assigned to the highest snap index.
snap_rank_summary(fit, actors = NULL, years = NULL, side = c("u", "v"))snap_rank_summary(fit, actors = NULL, years = NULL, side = c("u", "v"))
fit |
a |
actors |
optional actor names or indices. Default uses every actor on the selected side. |
years |
optional year/period names or indices. Default uses every period. |
side |
|
A data frame with year-level index means and rank probabilities.
Summarizes a fitted AME (Additive and Multiplicative Effects) model, including parameter estimates, standard errors, credible intervals, and model diagnostics.
## S3 method for class 'ame' summary(object, ...)## S3 method for class 'ame' summary(object, ...)
object |
an object of class "ame", typically the result of fitting an
AME model using the |
... |
additional parameters (currently not used) |
The summary includes:
Posterior means, posterior standard deviations, z-values, approximate p-values, and 95% credible intervals for dyadic, sender, and receiver covariates. Note: the z-values are computed as posterior mean / posterior SD, and the p-values are derived from a normal approximation. These are convenient screening statistics but are not formal frequentist test statistics. For rigorous inference, use the credible intervals or examine the full posterior via the BETA matrix directly.
Estimates and standard errors for:
Variance of additive sender/row effects (asymmetric networks)
Covariance between sender and receiver effects
Variance of additive receiver/column effects (asymmetric networks)
Dyadic correlation (reciprocity in directed networks)
Residual variance
For symmetric networks, only va and ve are estimated.
A list of class "summary.ame" containing:
call |
The original function call |
beta |
Matrix of regression coefficient estimates and statistics |
variance |
Matrix of variance component estimates |
Cassy Dorff, Shahryar Minhas, Tosin Salau
Summarize an ame_als object
## S3 method for class 'ame_als' summary(object, ...)## S3 method for class 'ame_als' summary(object, ...)
object |
an |
... |
ignored. |
A list of class "summary.ame_als", printed as a table.
Summary method for AME simulations
## S3 method for class 'ame.sim' summary(object, ...)## S3 method for class 'ame.sim' summary(object, ...)
object |
simulation object of class "ame.sim" |
... |
additional arguments (not used) |
summary statistics invisibly
Summarize bootstrap results for a fast AME fit
## S3 method for class 'boot_ame' summary(object, ...) ## S3 method for class 'summary.boot_ame' print(x, ...)## S3 method for class 'boot_ame' summary(object, ...) ## S3 method for class 'summary.boot_ame' print(x, ...)
object |
a |
... |
ignored. |
x |
a |
An object of class "summary.boot_ame", printed as a set of
tables.
Summarizes a fitted LAME (Longitudinal Additive and Multiplicative Effects) model, including parameter estimates, standard errors, credible intervals, and model diagnostics.
## S3 method for class 'lame' summary(object, ...)## S3 method for class 'lame' summary(object, ...)
object |
an object of class "lame", typically the result of fitting a
longitudinal AME model using the |
... |
additional parameters (currently not used) |
The summary includes:
Posterior means, posterior standard deviations, z-values, approximate p-values, and 95% credible intervals for dyadic, sender, and receiver covariates. Note: the z-values are computed as posterior mean / posterior SD, and the p-values are derived from a normal approximation. These are convenient screening statistics but are not formal frequentist test statistics. For rigorous inference, use the credible intervals or examine the full posterior via the BETA matrix directly.
Estimates and standard errors for:
Variance of additive sender/row effects
Covariance between sender and receiver effects
Variance of additive receiver/column effects
Dyadic correlation (reciprocity)
Residual variance
Only printed when the fit was
produced with dynamic_beta on at least one coefficient. The
table has one row per coefficient with columns:
average of the per-period posterior means across t
smallest and largest per-period posterior mean
Max - Min: the absolute range of the
per-period posterior means, in coefficient units
100 * Drift / |Mean|, the drift as a
percentage of the average level. Reported as NA when
the time-average is near zero (within 5\
range), because a trajectory that crosses zero makes the
percentage explode; read Drift in that case
"Y" if the coefficient was flagged as
dynamic, "N" if it was held static
The block also prints the per-block AR(1) hyperparameters
(rho_beta = ...). For per-period credible intervals use
confint.lame.
For dynamic fits the summary reports the posterior means of the
persistence parameters rho_uv (latent positions) and
rho_ab (additive effects). These are learned from period-to-period
transitions, so on short panels, and on sparse bipartite panels where each
period's positions are themselves uncertain, they lean on their priors
(default means 0.9 and 0.8; see the prior argument of
lame). Before reading a persistence value quantitatively,
refit with a different prior mean (for example
prior = list(rho_uv_mean = 0.5)) and check that the estimate
moves little; if it tracks the prior, describe the persistence
qualitatively rather than reporting the number.
A list of class "summary.lame" containing:
call |
The original function call |
beta |
Matrix of regression coefficient estimates and statistics |
variance |
Matrix of variance component estimates |
n.periods |
Number of time periods in the longitudinal data |
Cassy Dorff, Shahryar Minhas, Tosin Salau
Summary method for LAME simulations
## S3 method for class 'lame.sim' summary(object, ...)## S3 method for class 'lame.sim' summary(object, ...)
object |
simulation object of class "lame.sim" |
... |
additional arguments (not used) |
summary statistics
tidy
Light-weight fallback generic so that calls of the form
tidy(fit) dispatch through R's S3 system even when the
broom or generics packages are not loaded. When either
is loaded, its generic resolves first; this generic only fires for
bare-namespace use.
tidy(x, ...)tidy(x, ...)
x |
An object to tidy. |
... |
Passed to the relevant method. |
A data frame; method-specific schema.
ame / lame objectsReturns a data frame with one row per estimated coefficient,
compatible with the broom idiom. For dynamic_beta fits
(3-D BETA), returns one row per coefficient per period
with a period column. Standard errors are posterior standard
deviations; statistic is estimate / std.error.
## S3 method for class 'ame' tidy(x, conf.int = TRUE, conf.level = 0.95, ...) ## S3 method for class 'lame' tidy(x, conf.int = TRUE, conf.level = 0.95, ...)## S3 method for class 'ame' tidy(x, conf.int = TRUE, conf.level = 0.95, ...) ## S3 method for class 'lame' tidy(x, conf.int = TRUE, conf.level = 0.95, ...)
x |
A fitted |
conf.int |
Logical; include 95\
( |
conf.level |
Confidence level for the interval. Default
|
... |
Ignored. |
Note on p.value. This column is included for
broom compatibility but is not a classical test. It is a
two-sided Normal approximation based on the posterior mean and marginal
posterior standard deviation, matching the calculation in
summary(fit). Use it as a compact signal that the marginal posterior
is far from zero, and report it alongside the conf.low /
conf.high credible interval. When sign certainty matters, compute it
directly from x$BETA, for example
mean(sign(BETA) == sign(mean(BETA))).
Loaded as an S3 method against generics::tidy when the
generics package is available; works as
tidy(fit) either way once broom is loaded.
Data frame with columns term, estimate,
std.error, statistic, p.value,
conf.low, conf.high, and (for dynamic_beta fits)
period.
data(YX_bin_list) fit <- lame(YX_bin_list$Y, YX_bin_list$X, family = "binary", R = 0, nscan = 100, burn = 20, odens = 5, verbose = FALSE) tidy(fit)data(YX_bin_list) fit <- lame(YX_bin_list$Y, YX_bin_list$X, family = "binary", R = 0, nscan = 100, burn = 20, odens = 5, verbose = FALSE) tidy(fit)
ame_als / lame_als objectsReturns a data frame with one row per regression coefficient,
compatible with the broom idiom, so that ALS fits compose with
modelsummary / kableExtra pipelines next to MCMC fits.
Standard errors come from the sandwich covariance
(vcov.ame_als) by default, or from the bootstrap object
attached to x$bootstrap when present (preferred, fully
propagated). statistic is estimate / std.error;
p.value is the Normal-approximation two-sided tail
from the bootstrap or sandwich standard error. It is
a Wald-style summary for the point estimator, not a posterior probability.
## S3 method for class 'ame_als' tidy(x, conf.int = TRUE, conf.level = 0.95, ...) ## S3 method for class 'lame_als' tidy(x, conf.int = TRUE, conf.level = 0.95, ...)## S3 method for class 'ame_als' tidy(x, conf.int = TRUE, conf.level = 0.95, ...) ## S3 method for class 'lame_als' tidy(x, conf.int = TRUE, conf.level = 0.95, ...)
x |
A fitted |
conf.int |
Logical; include |
conf.level |
Confidence level. Default |
... |
Passed to |
Only the intercept and dyadic-covariate coefficients are returned,
matching coef(fit) on the sandwich-covered subset. Additive
(a, b), multiplicative (U, V), and
node-covariate parameters are not included; use
ame_als_bootstrap and inspect the bootstrap object
directly if you need them.
Data frame with columns term, estimate,
std.error, statistic, p.value,
conf.low, conf.high, plus a se_source column
recording "bootstrap" or "sandwich".
data(YX_bin_list) Y1 <- 1 * (YX_bin_list$Y[[1]] > 0); diag(Y1) <- NA fit <- ame_als(Y = Y1, Xdyad = YX_bin_list$X[[1]], family = "binary", R = 1, verbose = FALSE) tidy(fit)data(YX_bin_list) Y1 <- 1 * (YX_bin_list$Y[[1]] > 0); diag(Y1) <- NA fit <- ame_als(Y = Y1, Xdyad = YX_bin_list$X[[1]], family = "binary", R = 1, verbose = FALSE) tidy(fit)
boot_ame)ame_als_bootstrap() returns an object of class "boot_ame"
(not "ame_als"); this tidy method exposes the bootstrap
estimates as a broom-style data frame so the standalone object
composes with modelsummary the same way an embedded
ame_als(..., bootstrap = N) fit does.
## S3 method for class 'boot_ame' tidy(x, conf.level = 0.95, ...)## S3 method for class 'boot_ame' tidy(x, conf.level = 0.95, ...)
x |
A |
conf.level |
Confidence level. Default |
... |
Ignored. |
Data frame with columns term, estimate, std.error,
statistic, p.value, conf.low, conf.high, se_source.
Creates diagnostic plots for Markov Chain Monte Carlo (MCMC) samples from AME or LAME models. Displays trace plots to assess convergence and mixing, alongside density plots to visualize posterior distributions.
trace_plot( fit, params = c("all", "beta", "variance"), include = NULL, exclude = NULL, ncol = 3, nrow = NULL, burn.in = 0, thin = 1, title = NULL )trace_plot( fit, params = c("all", "beta", "variance"), include = NULL, exclude = NULL, ncol = 3, nrow = NULL, burn.in = 0, thin = 1, title = NULL )
fit |
An object of class "ame" or "lame" containing MCMC samples |
params |
Character vector specifying which parameters to plot: "beta" for regression coefficients, "variance" for variance components, or "all" (default) for both |
include |
Character vector of specific parameter names to include.
Raw variance-component names ("va", "ve", "rho", ...) and their
display labels ("Error Variance", ...) are both accepted.
For dynamic_beta fits, per-period traces are named like
|
exclude |
Character vector of specific parameter names to exclude.
Base names match all per-period traces, as with |
ncol |
Number of columns for plot layout (default 3) |
nrow |
Number of rows for plot layout (default NULL, determined automatically) |
burn.in |
Number of initial iterations to exclude as burn-in when calculating statistics (default 0, assumes burn-in already removed) |
thin |
Thinning interval for display (default 1, no thinning) |
title |
Optional title for the plot |
This function produces two types of diagnostic plots:
Show the evolution of parameter values across MCMC iterations. Good mixing is indicated by rapid exploration of the parameter space with no trends or stuck periods.
Show the posterior distribution of parameters. Multiple modes may indicate identification issues or convergence problems.
The plots help diagnose:
Convergence: Has the chain reached the stationary distribution?
Mixing: Is the chain exploring the parameter space efficiently?
Autocorrelation: Are successive samples highly correlated?
Parameters displayed include:
Regression coefficients (beta)
Variance components (va, vb, cab, rho, ve)
A ggplot2 object that can be further customized
Cassy Dorff, Shahryar Minhas, Tosin Salau
# Fit an AME model data(YX_nrm) fit <- ame(YX_nrm$Y, Xdyad = YX_nrm$X, nscan = 100, burn = 10, odens = 1, verbose = FALSE) # Basic trace plots for all parameters trace_plot(fit) # Only regression coefficients trace_plot(fit, params = "beta") # Only variance components trace_plot(fit, params = "variance")# Fit an AME model data(YX_nrm) fit <- ame(YX_nrm$Y, Xdyad = YX_nrm$X, nscan = 100, burn = 10, odens = 1, verbose = FALSE) # Basic trace plots for all parameters trace_plot(fit) # Only regression coefficients trace_plot(fit, params = "beta") # Only variance components trace_plot(fit, params = "variance")
S3 method for update that re-fits the model with
modified arguments. Reuses the original call recorded in fit$call.
If the fit was produced with freeze_call = TRUE, the data snapshot
on fit$data_snapshot is used in place of looking up names in the
caller's environment.
## S3 method for class 'ame' update(object, ..., evaluate = TRUE) ## S3 method for class 'lame' update(object, ..., evaluate = TRUE)## S3 method for class 'ame' update(object, ..., evaluate = TRUE) ## S3 method for class 'lame' update(object, ..., evaluate = TRUE)
object |
A fitted |
... |
Named arguments to overwrite in the original call (e.g.
|
evaluate |
Logical: if |
A new fitted object, or (when evaluate = FALSE) the
modified call.
data(YX_bin_list) fit <- lame(YX_bin_list$Y, YX_bin_list$X, family = "binary", burn = 5, nscan = 20, odens = 1, verbose = FALSE) # toggle dynamic_beta on without rewriting the whole call fit_dyn <- update(fit, dynamic_beta = "dyad") dim(fit_dyn$BETA) # 3-D nowdata(YX_bin_list) fit <- lame(YX_bin_list$Y, YX_bin_list$X, family = "binary", burn = 5, nscan = 20, odens = 1, verbose = FALSE) # toggle dynamic_beta on without rewriting the whole call fit_dyn <- update(fit, dynamic_beta = "dyad") dim(fit_dyn$BETA) # 3-D now
ame_als / lame_als fitS3 method for update that re-fits an ALS fit
with modified arguments. Two routes:
if ... contains only the warm-start refit knobs
(Y_new, X_new, Z_new, max_iter,
tol, verbose), it delegates to
ame_als_refit for a fast warm-started refit;
otherwise (e.g. changing R, family,
lambda, bootstrap) it re-evaluates the original
object$call with the overrides, matching the
update.ame semantics on the MCMC side.
The split exists because ame_als_refit() is a genuinely
warm-started single-fit refit (faster, narrower argument set),
while changing R / family requires a cold-start
refit through ame_als.
## S3 method for class 'ame_als' update(object, ..., evaluate = TRUE) ## S3 method for class 'lame_als' update(object, ..., evaluate = TRUE)## S3 method for class 'ame_als' update(object, ..., evaluate = TRUE) ## S3 method for class 'lame_als' update(object, ..., evaluate = TRUE)
object |
A fitted |
... |
Named arguments. See |
evaluate |
Logical: if |
A new fitted ame_als object, or (when
evaluate = FALSE on the cold-start path) the modified
call.
Y <- matrix(rnorm(400), 20, 20); diag(Y) <- NA fit <- ame_als(Y, R = 1, family = "normal", verbose = FALSE) # warm-start refit with the same arguments (fast) fit_w <- update(fit, max_iter = 50) # cold-start refit with a different R (full restart) fit_R2 <- update(fit, R = 2)Y <- matrix(rnorm(400), 20, 20); diag(Y) <- NA fit <- ame_als(Y, R = 1, family = "normal", verbose = FALSE) # warm-start refit with the same arguments (fast) fit_w <- update(fit, max_iter = 50) # cold-start refit with a different R (full restart) fit_R2 <- update(fit, R = 2)
Creates a two-dimensional visualization of the multiplicative effects (U and V) from an AME or LAME model. These latent factors capture network structure beyond what is explained by covariates and additive effects, including clustering, transitivity, and other higher-order dependencies.
uv_plot( fit = NULL, Y = NULL, U = NULL, V = NULL, row.names = NULL, col.names = NULL, layout = c("circle", "biplot"), vscale = 0.8, show.edges = FALSE, edge.alpha = 0.3, node.size = "magnitude", label.nodes = TRUE, label.size = 3, show.usernames = NULL, sender.color = "darkred", receiver.color = "darkblue", colors = NULL, title = NULL, time_point = NULL, plot_type = c("snapshot", "trajectory", "faceted"), show_arrows = TRUE, highlight = NULL )uv_plot( fit = NULL, Y = NULL, U = NULL, V = NULL, row.names = NULL, col.names = NULL, layout = c("circle", "biplot"), vscale = 0.8, show.edges = FALSE, edge.alpha = 0.3, node.size = "magnitude", label.nodes = TRUE, label.size = 3, show.usernames = NULL, sender.color = "darkred", receiver.color = "darkblue", colors = NULL, title = NULL, time_point = NULL, plot_type = c("snapshot", "trajectory", "faceted"), show_arrows = TRUE, highlight = NULL )
fit |
An object of class "ame" or "lame" containing multiplicative effects, or a network matrix Y if U and V are provided separately |
Y |
Network matrix (only needed if fit is not provided) |
U |
Matrix of sender latent factors (extracted from fit if not provided) |
V |
Matrix of receiver latent factors (extracted from fit if not provided) |
row.names |
Names for row nodes (defaults to rownames of Y or U) |
col.names |
Names for column nodes (defaults to colnames of Y or V) |
layout |
Character string specifying layout: "circle" (default) or "biplot" |
vscale |
Scaling factor for V positions relative to U (default 0.8) |
show.edges |
Logical; if TRUE, show network edges (default FALSE) |
edge.alpha |
Transparency for edges (default 0.3) |
node.size |
Size of nodes, or "degree" to scale by degree (default 3) |
label.nodes |
Logical; if TRUE, show node labels (default TRUE) |
label.size |
Size of node labels (default 3) |
show.usernames |
Integer: number of top-degree nodes to label, or NULL for default behavior |
sender.color |
Color for sender/row nodes (default "darkred") |
receiver.color |
Color for receiver/column nodes (default "darkblue") |
colors |
Optional vector of colors for nodes (e.g., for communities) |
title |
Optional title for the plot |
time_point |
For dynamic UV, which time point to plot (default: last). Can be numeric index or "average" for time-averaged positions |
plot_type |
For dynamic UV: "snapshot" (single time), "trajectory" (evolution), "faceted" (grid of time points). For static UV, this is ignored. |
show_arrows |
For trajectory plots, whether to show directional arrows |
highlight |
Optional character vector of actor names to highlight on a
|
The multiplicative effects in AME models provide a low-rank representation of network structure through latent factors:
Sender-specific latent positions (row factors)
Receiver-specific latent positions (column factors)
Captures dyad-specific effects beyond additive terms
The visualization can show:
Default layout placing nodes on a circle with latent positions shown as deviations
Shows U and V positions directly in latent space
Optional display of actual network ties
Interpretation (this is an eigenmodel, not a latent-distance model):
The latent contribution to a tie i -> j is the inner product u_i' v_j: sender and receiver vectors that align (small angle, large magnitude) raise the tie propensity, opposed vectors lower it. Euclidean distance between plotted points is not the operative quantity.
Actors with similar sender (or receiver) vectors have similar connection patterns; clustering of vectors indicates community structure.
A ggplot2 object that can be further customized
Cassy Dorff, Shahryar Minhas, Tosin Salau
# Fit an AME model with multiplicative effects data(YX_nrm) fit <- ame(YX_nrm$Y, Xdyad = YX_nrm$X, R = 2, nscan = 100, burn = 10, odens = 1, verbose = FALSE) # Basic visualization uv_plot(fit) # Use biplot layout uv_plot(fit, layout = "biplot")# Fit an AME model with multiplicative effects data(YX_nrm) fit <- ame(YX_nrm$Y, Xdyad = YX_nrm$X, R = 2, nscan = 100, burn = 10, odens = 1, verbose = FALSE) # Basic visualization uv_plot(fit) # Use biplot layout uv_plot(fit, layout = "biplot")
Returns the posterior covariance matrix of regression coefficients.
## S3 method for class 'ame' vcov(object, ...) ## S3 method for class 'lame' vcov(object, ...)## S3 method for class 'ame' vcov(object, ...) ## S3 method for class 'lame' vcov(object, ...)
object |
fitted AME model (class "ame") |
... |
additional arguments (ignored) |
p x p covariance matrix of posterior BETA draws
Returns a heteroskedasticity-robust (optionally dyad-clustered) sandwich
covariance matrix for the intercept and dyadic-covariate coefficients
of an ame_als fit. This is a fast analytic alternative to
the bootstrap for those coefficients.
## S3 method for class 'ame_als' vcov(object, cluster = c("dyad", "none"), ...)## S3 method for class 'ame_als' vcov(object, cluster = c("dyad", "none"), ...)
object |
an |
cluster |
|
... |
ignored. |
The estimate is the conditional sandwich with bread
( the observed intercept + dyadic-covariate design,
the fit's observation weights) and meat the
heteroskedasticity-robust (cluster = "none", an HC0 meat) or
dyad-clustered (cluster = "dyad", the default) outer product of the
weighted score contributions . For a normal or
transform fit the weights are unit, so this reduces to the ordinary
sandwich; for an IRLS fit it uses the final IRLS weights, matching
the estimating equation the fit actually solved. Dyad clustering pools the
score across , and time, so it reflects dyadic
dependence (reciprocity, repeated observation).
It is conditional: the additive effects a, b and the
multiplicative term are held fixed, so it omits their estimation uncertainty
and is anti-conservative. Node-covariate, additive and multiplicative
standard errors are not returned – use ame_als_bootstrap
for those and for fully-propagated inference.
A covariance matrix with matching row/column names. When the fit
carries a $bootstrap, this is the bootstrap covariance over all
estimated coefficients, matching coef(). Otherwise it is the
conditional sandwich, covering c(intercept, dyadic coefficients)
only.
ame_als_bootstrap for bootstrap uncertainty
covering all parameters.
Returns the sample covariance matrix of the bootstrap replicate
intercept + regression coefficients of a boot_ame object – the
covariance underlying the reported standard errors and confidence intervals.
## S3 method for class 'boot_ame' vcov(object, ...)## S3 method for class 'boot_ame' vcov(object, ...)
object |
a |
... |
ignored. |
A covariance matrix over the intercept and regression coefficients.
Longitudinal directed binary network of international economic sanctions
among 35 countries across four years (1993, 1994, 1995, 2000), derived from
the Threat and Imposition of Sanctions (TIES) dataset (Morgan et al. 2014).
Entry means country imposed sanctions on country
in year . Network density is approximately 2\
data(vignette_data)data(vignette_data)
Four objects:
List of 4 binary adjacency matrices (35 x 35), one per year.
List of 4 arrays (35 x 35 x 2) of dyadic covariates:
distance (geographic) and shared_igos (shared IGO memberships).
List of 4 matrices (35 x 2) of sender covariates:
log_gdp and log_pop.
List of 4 matrices (35 x 2) of receiver covariates:
log_gdp and log_pop.
When loaded via data(vignette_data), the following objects are placed
in the calling environment: Y, Xdyad, Xrow, Xcol.
Morgan, T. Clifton, Bapat, N., & Kobayashi, Y. (2014). Threat and Imposition of Economic Sanctions 1945–2005. Conflict Management and Peace Science, 31(5), 541–558.
data(vignette_data) cat("Countries:", nrow(Y[[1]]), "\n") cat("Time periods:", length(Y), "\n")data(vignette_data) cat("Countries:", nrow(Y[[1]]), "\n") cat("Time periods:", length(Y), "\n")
S3 method for waic that uses the stored fit$log_lik.
## S3 method for class 'ame' waic(x, ...) ## S3 method for class 'lame' waic(x, ...) ## S3 method for class 'ame_als' waic(x, ...)## S3 method for class 'ame' waic(x, ...) ## S3 method for class 'lame' waic(x, ...) ## S3 method for class 'ame_als' waic(x, ...)
x |
A fitted |
... |
Additional arguments forwarded to |
A waic object.
Computes a matrix of expected values based on an array X of predictors and a vector beta of regression coefficients.
Xbeta(X, beta)Xbeta(X, beta)
X |
an n by n by p array |
beta |
a p by 1 vector |
An n by n matrix
Cassy Dorff, Shahryar Minhas, Tosin Salau
Computes sum_k beta_k * X_k for a single time slice
Xbeta_bip_cpp(X, beta)Xbeta_bip_cpp(X, beta)
X |
3D array (nA x nB x p) of covariates for one time period |
beta |
Coefficient vector of length p |
nA x nB matrix
Column covariates loaded by data(vignette_data).
See vignette_data for full details.
A list of matrices of column covariates
Dyadic covariates loaded by data(vignette_data).
See vignette_data for full details.
A list of arrays of dyadic covariates
Row covariates loaded by data(vignette_data).
See vignette_data for full details.
A list of matrices of row covariates
Relational matrix loaded by data(vignette_data).
See vignette_data for full details.
A list of square binary adjacency matrices
a synthetic dataset that includes binary relational data as well as information on eight covariates
data(YX_bin)data(YX_bin)
The format is: List of 2 $ Y: num [1:100, 1:100] NA 0 0 0 0 0 0 0 0 1 ... $ X: num [1:100, 1:100, 1:8] 1 1 1 1 1 1 1 1 1 1 ... ..- attr(*, "dimnames")=List of 3 .. ..$ : NULL .. ..$ : NULL .. ..$ : chr [1:8] "intercept" "rgpa" "rsmoke" "cgpa" ...
data(YX_bin) gof_stats(YX_bin$Y)data(YX_bin) gof_stats(YX_bin$Y)
The list-form sibling of YX_bin_long: same synthetic
4-period 50-actor panel reshaped from arrays to lists. The shipped
Y entries hold the latent probit-scale predictor
(range roughly -20 to 17), not 0/1 ties. To recover the binary tie
indicator the dataset name implies, threshold at zero, e.g.
Y_bin <- lapply(YX_bin_list$Y, function(Yt) 1 * (Yt > 0)).
If passed unthresholded to lame(..., family = "binary") the
fit will warn and silently apply the same Y > 0 threshold.
A list with two elements:
List of 4 numeric matrices, each [50, 50], with
NA on the diagonal. Latent probit-scale predictor;
threshold at 0 for the binary indicator.
List of 4 numeric arrays, each [50, 50, 3] of
dyadic covariates.
a synthetic 50-actor, 4-period dataset used by the vignettes. The
shipped Y array holds the latent probit-scale predictor
(range roughly -24 to 20), not 0/1 ties. To recover the binary tie
indicator the dataset name implies, threshold at zero:
Y_bin <- (YX_bin_long$Y > 0) * 1. If passed unthresholded to
lame(..., family = "binary") the fit will warn and silently
apply the same Y > 0 threshold.
data(YX_bin_long)data(YX_bin_long)
A list with two elements:
Numeric array [50, 50, 4]. Latent probit-scale
predictor; threshold at 0 to get the binary tie indicator.
Numeric array [50, 50, 3, 4] of dyadic covariates.
data(YX_bin_long) # threshold latent z to 0/1 before computing binary GOF stats Yt <- 1 * (YX_bin_long$Y[, , 1] > 0) diag(Yt) <- NA gof_stats(Yt)data(YX_bin_long) # threshold latent z to 0/1 before computing binary GOF stats Yt <- 1 * (YX_bin_long$Y[, , 1] > 0) diag(Yt) <- NA gof_stats(Yt)
a synthetic dataset that includes relational data where the number of nominations per row is censored at 10, along with information on eight covariates
data(YX_cbin)data(YX_cbin)
The format is: List of 2 $ Y: num [1:100, 1:100] NA 0 0 0 1 0 0 0 0 3 ... $ X: num [1:100, 1:100, 1:8] 1 1 1 1 1 1 1 1 1 1 ... ..- attr(*, "dimnames")=List of 3 .. ..$ : NULL .. ..$ : NULL .. ..$ : chr [1:8] "intercept" "rgpa" "rsmoke" "cgpa" ...
data(YX_cbin) gof_stats(YX_cbin$Y)data(YX_cbin) gof_stats(YX_cbin$Y)
a synthetic dataset that includes fixed rank nomination data as well as information on eight covariates
data(YX_frn)data(YX_frn)
The format is: List of 2 $ Y: num [1:100, 1:100] NA 0 0 0 1 0 0 0 0 3 ... $ X: num [1:100, 1:100, 1:8] 1 1 1 1 1 1 1 1 1 1 ... ..- attr(*, "dimnames")=List of 3 .. ..$ : NULL .. ..$ : NULL .. ..$ : chr [1:8] "intercept" "rgpa" "rsmoke" "cgpa" ...
data(YX_frn) gof_stats(YX_frn$Y)data(YX_frn) gof_stats(YX_frn$Y)
a synthetic dataset that includes continuous (normal) relational data as well as information on eight covariates
data(YX_nrm)data(YX_nrm)
The format is: List of 2 $ Y: num [1:100, 1:100] NA -4.05 -0.181 -3.053 -1.579 ... $ X: num [1:100, 1:100, 1:8] 1 1 1 1 1 1 1 1 1 1 ... ..- attr(*, "dimnames")=List of 3 .. ..$ : NULL .. ..$ : NULL .. ..$ : chr [1:8] "intercept" "rgpa" "rsmoke" "cgpa" ...
data(YX_nrm) gof_stats(YX_nrm$Y)data(YX_nrm) gof_stats(YX_nrm$Y)
a synthetic dataset that includes ordinal relational data as well as information on seven covariates
data(YX_ord)data(YX_ord)
The format is: List of 2 $ Y: num [1:100, 1:100] NA 0 3 0 3 1 0 1 1 0 ... $ X: num [1:100, 1:100, 1:7] 1 1 1 1 1 1 1 1 1 1 ... ..- attr(*, "dimnames")=List of 3 .. ..$ : NULL .. ..$ : NULL .. ..$ : chr [1:7] "rgpa" "rsmoke" "cgpa" "csmoke" ...
data(YX_ord) gof_stats(YX_ord$Y)data(YX_ord) gof_stats(YX_ord$Y)