| Title: | Tools for Dyadic Multilevel Models |
| Version: | 0.1.0 |
| Description: | Provides tools for dyadic multilevel modeling with linear and generalized linear mixed-effects models. It validates and prepares long-format cross-sectional and intensive longitudinal data, including ecological momentary assessment designs, for distinguishable and exchangeable dyads. It also supports datasets containing multiple observed dyad compositions. It constructs composition-aware, model-ready variables for Actor-Partner Interdependence Models (APIMs), Dyadic Score Models (DSMs), and Dyad-Individual Models (DIMs). Prepared data can be used with model engines such as 'glmmTMB' and 'brms' for Gaussian and non-Gaussian outcomes, including counts, proportions, and skewed continuous responses. Post-estimation tools compare compatible fitted models and back-transform exchangeable sum-and-difference random-effect covariance structures into member-level quantities. The APIM and DSM specifications and their relationships follow Iida et al. (2018) <doi:10.1177/0265407517725407>; the multilevel sum-and-difference random-effects implementation for exchangeable dyads adapts del Rosario and West (2025) <doi:10.1177/25152459251351286>. |
| License: | MIT + file LICENSE |
| Encoding: | UTF-8 |
| RoxygenNote: | 8.0.0 |
| Suggests: | brms, glmmTMB, htmltools, knitr, lavaan, marginaleffects, rmarkdown, spelling, testthat (≥ 3.1.7) |
| Config/testthat/edition: | 3 |
| Imports: | dplyr (≥ 1.1.0), pillar, rlang (≥ 0.4.0), tidyselect, tibble (≥ 3.0.0) |
| VignetteBuilder: | knitr, rmarkdown |
| Depends: | R (≥ 4.1) |
| LazyData: | true |
| URL: | https://pascal-kueng.github.io/dyadMLM/, https://github.com/Pascal-Kueng/dyadMLM |
| BugReports: | https://github.com/Pascal-Kueng/dyadMLM/issues |
| Language: | en-US |
| NeedsCompilation: | no |
| Packaged: | 2026-07-22 01:10:11 UTC; pascalkueng |
| Author: | Pascal Küng |
| Maintainer: | Pascal Küng <kueng.pascal@gmail.com> |
| Repository: | CRAN |
| Date/Publication: | 2026-07-30 17:20:23 UTC |
Add actor and partner predictor columns
Description
Adds APIM-style actor and partner columns for the predictors recorded in an
dyadMLM_data object. For uncentered predictors, this will create actor and
partner versions of the raw predictor. For centered intensive longitudinal
predictors, this will create actor and partner versions of the raw predictor
and each recorded predictor component, such as the within-person and
between-person components created by center_predictors().
Selected lag predictors additionally create lag-1 raw and within-person
actor and partner columns.
Usage
add_actor_partner_columns(data)
Arguments
data |
A |
Details
The function will use the predictor decomposition metadata stored in
attr(data, "dyadMLM")$temporal_decompositions, so downstream code does
not need to infer generated predictor columns from their names. It stores the
constructed APIM columns in attr(data, "dyadMLM")$apim_predictors.
Value
A dyadMLM_data object with actor and partner predictor columns
added and APIM predictor metadata recorded.
Add dyad-individual predictor columns
Description
Adds Dyad-Individual Model (DIM) style dyad-mean and within-dyad
member-deviation columns for the predictors recorded in a dyadMLM_data
object. For
currently supported DIMs, the data must
contain one exchangeable dyad composition. This means distinguishable dyads
and multiple exchangeable compositions are not supported by DIM
construction until explicit role-contrast, composition-specific, or pooling
support is added. For
intensive longitudinal predictors decomposed by center_predictors(), raw
predictors and within-person components are decomposed within each dyad-time
occasion, while between-person components are decomposed once within each
dyad.
For raw predictors, the dyad-mean column is centered around the grand mean
of dyad means, or dyad-occasion means in longitudinal data, while the
within-dyad member-deviation column is the person's deviation from the
uncentered dyad mean.
Selected lag predictors additionally create lag-1 raw and within-person
dyad-mean and within-dyad member-deviation columns.
Usage
add_dyad_individual_columns(data)
Arguments
data |
A |
Details
The function reads attr(data, "dyadMLM")$temporal_decompositions and
stores the constructed DIM columns in
attr(data, "dyadMLM")$dim_predictors.
Value
A dyadMLM_data object with dyad-mean and within-dyad
member-deviation predictor columns added and DIM predictor metadata
recorded.
Add dyadic-score model predictor columns and contrast
Description
Adds Dyadic Score Model (DSM) dyad-mean and signed dyad-difference columns
for the predictors recorded in a dyadMLM_data object, together with a
DSM role contrast coded +0.5 and -0.5. DSM differences follow the role
order recorded in attr(data, "dyadMLM")$dsm_role_order. The supported DSM
structure contains one distinguishable dyad composition; exchangeable dyads
and multiple compositions are not supported.
Usage
add_dyadic_score_columns(data)
Arguments
data |
A |
Details
For ILD predictors, raw and within-person scores are computed within dyad-time and between-person scores within dyad. Raw dyad means are grand-mean centered. Both partners' predictor values are required for each score pair. Selected lag predictors additionally create lag-1 raw and within-person dyad-mean and signed-difference columns.
Constructed predictor columns are recorded in
attr(data, "dyadMLM")$dsm_predictors, and the contrast column name is
recorded in attr(data, "dyadMLM")$dsm_role_contrast_column.
Value
A dyadMLM_data object with dyad-mean and signed dyad-difference
predictor columns and a DSM role contrast added.
Add lagged temporal predictor columns
Description
Adds lag-1 raw and within-person columns for predictors selected through
lag1_predictors. Values are matched at exactly time - 1, so construction
does not depend on row order and does not bridge gaps in the measurement
index. Stable between-person components are not lagged.
Usage
add_temporal_lag_columns(data)
Arguments
data |
A |
Value
A dyadMLM_data object with lagged temporal predictor columns and
updated predictor metadata.
Assign arbitrary member roles within dyads
Description
Creates a member-level lookup with one arbitrary role per observed member.
The assignment is stable across longitudinal rows because it is made once per
group x member.
Usage
assign_arbitrary_member_roles(data, group_name, member_name, seed = NULL)
Arguments
data |
A data frame. |
group_name |
Name of the dyad/group column. |
member_name |
Name of the member/person column. |
seed |
Optional seed for random arbitrary partner-role assignment. If
|
Value
A data frame with group_name, member_name, and
.dy_arbitrary_role.
Create a canonical dyad composition label
Description
Sorts role labels before pasting them so composition labels do not depend on row order.
Usage
canonical_composition(roles, sep = dyad_composition_sep)
composition_role_label(composition, role, sep = dyad_composition_role_sep)
Arguments
roles |
A vector of role labels. |
sep |
Separator used between label components. |
composition |
A composition label. |
role |
A row-level role label. |
Value
A single composition label.
Center predictor variables for dyadic models
Description
Adds centered predictor columns to a dyadMLM_data object. It currently
supports two-level temporal centering for intensive longitudinal predictors:
a within-person component and a between-person component. The original
predictor remains available as a raw component for model-specific column
construction.
For two-level temporal centering, the between-person component is centered
around the grand mean of person means, not the grand mean of all observed rows.
This gives each person equal weight even when people have different numbers of
observed measurement occasions.
Usage
center_predictors(data)
Arguments
data |
A |
Details
The function uses the structural metadata stored by
prepare_dyad_data().
Value
A dyadMLM_data object with centered predictor columns added and
updated predictor metadata.
Compare nested glmmTMB models fitted to equivalent data
Description
Performs a likelihood-ratio test for two nested glmmTMB models. The models
may use ordinary data frames or dyadMLM_data
objects, and their calls do not need to refer to the same R object. Models may
be supplied in either order. The model with fewer estimated parameters is
shown first in the result.
Usage
compare_nested_glmmTMB_models(model1, model2)
Arguments
model1, model2 |
Two fitted |
Details
Both model calls must use named data-frame objects that remain available when
the models are compared. The checks assume these objects have not been
modified since fitting. All ordinary data columns must be identical,
including their types and attributes. For dyadMLM_data, generated .dy_
columns may differ, but the original columns must be identical. Ordinary and
prepared data may be compared with each other. Dyad metadata are checked when
both models use dyadMLM_data. The function also checks fitted rows,
outcomes, weights and offsets, model family and link, maximum-likelihood
estimation, and model convergence. Each model must use the same untransformed
response column.
These checks establish that the models use equivalent observations. They cannot establish that one model is mathematically nested within the other. The caller remains responsible for supplying genuinely nested models. The usual chi-squared reference distribution may also be inappropriate when tested variance parameters are on the boundary.
Value
An anova-style data frame containing model degrees of freedom,
information criteria, log-likelihoods, the likelihood-ratio statistic, and
its chi-squared p-value. When printed, a short conclusion interprets the
test at the 5% significance level.
Examples
if (requireNamespace("glmmTMB", quietly = TRUE)) {
restricted_data <- prepare_dyad_data(
dyads_cross,
dyad = coupleID,
member = personID,
role = gender,
# All three observed compositions in `dyads_cross` are detected and retained
# by default. This example focuses on `female-male` dyads, so we restrict the
# analysis here.
keep_compositions = "female-male"
)
full_data <- restricted_data
restricted_model <- glmmTMB::glmmTMB(
closeness ~ 1 + us(1 | coupleID),
data = restricted_data
)
full_model <- glmmTMB::glmmTMB(
closeness ~ gender + us(1 | coupleID),
data = full_data
)
compare_nested_glmmTMB_models(restricted_model, full_model)
}
Collect dyadMLM-generated columns
Description
Creates a normalized, one-row-per-column view over temporal predictor, APIM,
DIM, and DSM columns stored in a dyadMLM attribute. This is a
derived lookup table; the model-specific metadata tables remain the source
records.
Usage
dyad_generated_columns(meta)
Arguments
meta |
The |
Value
A tibble with one row per generated temporal predictor, APIM, DIM,
or DSM column. The lag column is 0 for contemporaneous columns and 1
for lag-1 columns.
Example Gaussian cross-sectional dyadic data
Description
A simulated long-format dataset containing distinguishable female-male
dyads and exchangeable female-female and male-male dyads. Each dyad has two
members and each member has one row. closeness and provided_support are
the member's averages across the 14 observations in dyads_ild.
Usage
dyads_cross
Format
A data frame with 720 rows and 6 variables:
- personID
Unique person identifier.
- coupleID
Dyad identifier.
- gender
Gender role, with levels
femaleandmale.- dyad_composition
Observed dyad composition, with levels
female_x_male,female_x_female, andmale_x_male.- closeness
Mean simulated Gaussian closeness score across 14 days.
- provided_support
Mean simulated provided-support score across 14 days.
Details
Prepare with dyad = coupleID, member = personID, and role = gender.
These data contain three compositions. Use keep_compositions in
prepare_dyad_data() when an analysis should retain only selected
compositions; omit it when all supplied compositions should remain.
Source
Simulated for dyadMLM; design adapted from
https://github.com/Pascal-Kueng/05DyadicDataAnalysis. See Küng,
P. M. (2026). Distinguishable and Exchangeable Dyads: Bayesian
Multilevel Modelling (v2.0.9). Zenodo.
doi:10.5281/zenodo.20720321.
Example Gaussian intensive longitudinal dyadic data
Description
A simulated long-format dataset containing distinguishable female-male dyads and exchangeable female-female and male-male dyads. Each dyad has two members observed on 14 diary days.
Usage
dyads_ild
Format
A data frame with 10,080 rows and 7 variables:
- personID
Unique person identifier.
- coupleID
Dyad identifier.
- diaryday
Measurement day, from 0 through 13.
- gender
Gender role, with levels
femaleandmale.- dyad_composition
Observed dyad composition, with levels
female_x_male,female_x_female, andmale_x_male.- closeness
Simulated Gaussian closeness outcome.
- provided_support
Simulated provided-support score.
Details
Prepare with dyad = coupleID, member = personID, role = gender, and
time = diaryday. These data contain three compositions. Use
keep_compositions in prepare_dyad_data() when an analysis should retain
only selected compositions; omit it when all supplied compositions should
remain.
Source
Simulated for dyadMLM; design adapted from
https://github.com/Pascal-Kueng/05DyadicDataAnalysis. See Küng,
P. M. (2026). Distinguishable and Exchangeable Dyads: Bayesian
Multilevel Modelling (v2.0.9). Zenodo.
doi:10.5281/zenodo.20720321.
Example negative-binomial cross-sectional dyadic data
Description
A simulated long-format dataset containing the same dyads, members, and
dyad compositions as dyads_cross. Each member has one row. stress is the
member's average across the 14 observations in dyads_nbinom_ild. The count
outcome is a separate negative-binomial draw using the NB2 variance function;
it is not an average or sum of the daily counts.
Usage
dyads_nbinom_cross
Format
A data frame with 720 rows and 6 variables:
- personID
Unique person identifier.
- coupleID
Dyad identifier.
- gender
Gender role, with levels
femaleandmale.- dyad_composition
Observed dyad composition, with levels
female_x_male,female_x_female, andmale_x_male.- conflict_count
Simulated number of conflictual interactions reported by a member.
- stress
Mean simulated stress score across 14 days.
Details
Prepare with dyad = coupleID, member = personID, and role = gender.
These data contain three compositions. Use keep_compositions in
prepare_dyad_data() when an analysis should retain only selected
compositions; omit it when all supplied compositions should remain.
Source
Simulated for dyadMLM; design adapted from
https://github.com/Pascal-Kueng/05DyadicDataAnalysis. See Küng,
P. M. (2026). Distinguishable and Exchangeable Dyads: Bayesian
Multilevel Modelling (v2.0.9). Zenodo.
doi:10.5281/zenodo.20720321.
Example negative-binomial intensive longitudinal dyadic data
Description
A simulated long-format dataset containing the same dyads, members, diary days, and dyad compositions as dyads_ild. The outcome is a count generated from a negative-binomial distribution using the NB2 variance function.
Usage
dyads_nbinom_ild
Format
A data frame with 10,080 rows and 7 variables:
- personID
Unique person identifier.
- coupleID
Dyad identifier.
- diaryday
Measurement day, from 0 through 13.
- gender
Gender role, with levels
femaleandmale.- dyad_composition
Observed dyad composition, with levels
female_x_male,female_x_female, andmale_x_male.- conflict_count
Simulated number of conflictual interactions reported by a member on that day.
- stress
Simulated stress score.
Details
Prepare with dyad = coupleID, member = personID, role = gender, and
time = diaryday. These data contain three compositions. Use
keep_compositions in prepare_dyad_data() when an analysis should retain
only selected compositions; omit it when all supplied compositions should
remain.
Source
Simulated for dyadMLM; design adapted from
https://github.com/Pascal-Kueng/05DyadicDataAnalysis. See Küng,
P. M. (2026). Distinguishable and Exchangeable Dyads: Bayesian
Multilevel Modelling (v2.0.9). Zenodo.
doi:10.5281/zenodo.20720321.
Extract exchangeable random-effect blocks from a fitted model
Description
Normalizes the random-effect coefficients and fitted covariance parameters
needed by recover_exchangeable_covariance() while keeping backend-specific work in two
small adapters.
Usage
extract_exchangeable_residual_blocks(model)
Arguments
model |
A fitted model. Supported classes are |
Value
A list containing the model backend, one normalized record per
random-effect block, and one grouping-factor ID per fitted row.
Every block record contains group, coefficients, correlated, term,
and an estimate/draw-by-coefficients covariance array.
Format counted group identifiers for validation messages
Description
Converts a vector of dyad or group identifiers into text that includes both the number of groups and a compact list of their identifiers.
Usage
format_group_count(groups, singular = "dyad", plural = "dyads", max = 10)
Arguments
groups |
A vector of group identifiers. |
singular |
Singular label for one group. |
plural |
Plural label for multiple groups. |
max |
Maximum number of identifiers to show before truncating the list. |
Value
A single character string.
Format group identifiers for validation messages
Description
Converts a vector of dyad or group identifiers into a compact comma-separated string for use in validation errors and warnings.
Usage
format_group_list(groups, max = 10)
Arguments
groups |
A vector of group identifiers. |
max |
Maximum number of identifiers to show before truncating the list. |
Value
A single character string.
Infer dyad compositions
Description
Builds a dyad-level summary of role compositions from a validated
dyadMLM_data object.
Usage
infer_dyad_compositions(
data,
seed = NULL,
keep_compositions = NULL,
set_exchangeable_compositions = NULL,
pool_compositions = NULL
)
Arguments
data |
A |
seed |
Optional seed for random |
keep_compositions |
Optional observed dyad compositions to keep before exchangeability overrides and pooling. |
set_exchangeable_compositions |
Optional dyad compositions to treat as exchangeable for analysis. |
pool_compositions |
Optional named list that pools exchangeable dyad compositions into user-named final composition labels. Each pool must resolve to at least two distinct observed compositions. |
Value
A dyadMLM_data object with added .dy_composition and
.dy_composition_role factor columns, .dy_is_* numeric indicator columns,
composition-specific numeric .dy_member_contrast_* columns coded -1 and
1 for the two members of matching exchangeable dyads and 0 otherwise,
and dyad composition metadata.
Create safe suffixes for generated dyadMLM columns
Description
Create safe suffixes for generated dyadMLM columns
Usage
make_dyad_suffixes(
labels,
label_type = "labels",
rename_hint = "role or composition labels"
)
Arguments
labels |
Labels that will be used to build generated column names. |
Value
A named character vector. Names are the original labels; values are sanitized column-name suffixes.
Prepare dyadic data for multilevel models
Description
Validates dyadic data, records the structural variables, and adds metadata and model-ready columns for dyadic multilevel model parameterizations.
Usage
prepare_dyad_data(
data,
dyad,
member,
role = NULL,
time = NULL,
predictors = NULL,
lag1_predictors = NULL,
model_types = "apim",
dsm_role_order = NULL,
temporal_decomposition = c("auto", "2l", "none"),
set_exchangeable_compositions = NULL,
keep_compositions = NULL,
pool_compositions = NULL,
incomplete_dyads = c("error", "drop"),
missing_role = c("error", "drop"),
seed = NULL
)
Arguments
data |
A data frame or tibble. Data must be in long format. For cross-sectional dyadic data, each observed member of each dyad has one row. For intensive longitudinal dyadic data, each observed member of each dyad has one row per observed time point. |
dyad |
Column identifying the dyad. |
member |
Column identifying a person or the member within dyad. |
role |
Optional column identifying a stable member role, such as gender.
Non-missing values must be consistent within each |
time |
Optional column identifying time or measurement order of repeated measures. |
predictors |
Optional variables to use for temporal predictor decomposition and model-ready predictor construction. |
lag1_predictors |
Optional subset of |
model_types |
Model-ready column families to construct. Can contain one
or more of |
dsm_role_order |
For |
temporal_decomposition |
Temporal decomposition strategy for
|
set_exchangeable_compositions |
Optionally specify dyad compositions
to treat as exchangeable, when their roles would otherwise imply distinguishability.
Requires |
keep_compositions |
Optional observed dyad compositions to keep
before exchangeability overrides and pooling. Requires |
pool_compositions |
Optionally pool exchangeable dyad compositions
into a shared final composition label. Must be a named list where each name
is the final composition label and each value is a character vector of
composition references, for example
|
incomplete_dyads |
How to handle dyads with fewer than two unique
members across all rows in |
missing_role |
How to handle dyads in which at least one member has no
non-missing |
seed |
Optional seed for random |
Details
Data must be in long format. Cross-sectional dyadic data may contain at most
one row per member within dyad. Intensive longitudinal dyadic data may
contain at most one row per member and observed measurement occasion within
dyad. Measured variables may contain missing values. Structural completeness
is assessed across all rows. incomplete_dyads controls dyads with fewer
than two members; dyads with more than two members always cause an error.
When role is supplied, stable member roles are resolved across repeated
rows before missing_role is applied.
Dyad composition labels are canonical: role labels are sorted alphabetically before being combined, so labels do not depend on row or member order.
Value
The original data as a tibble with class dyadMLM_data,
.dy_composition and .dy_composition_role factor columns,
.dy_is_* numeric indicator columns, composition-specific
numeric .dy_member_contrast_* columns coded -1 and 1 for the two
members of matching exchangeable dyads and 0 otherwise, and a dyadMLM
attribute containing structural metadata, dyad_compositions, and
predictor metadata such as temporal_decompositions, lag1_predictors,
apim_predictors, and dim_predictors, as well as dsm_predictors and
dsm_role_order when applicable.
Examples
data <- data.frame(
dyad_id = c(1, 1, 2, 2, 3, 3),
person_id = c(1, 2, 3, 4, 5, 6),
role = c("female", "male", "female", "female", "male", "male"),
x = c(4, 7, 5, 6, 3, 8)
)
prepared <- prepare_dyad_data(
data,
dyad = dyad_id,
member = person_id,
role = role,
predictors = x,
model_types = "apim"
)
print(prepared)
pooled <- prepare_dyad_data(
data,
dyad = dyad_id,
member = person_id,
role = role,
predictors = x,
model_types = "apim",
set_exchangeable_compositions = "female-male",
pool_compositions = list(
romantic_couples = c("female-female", "male-male", "female-male")
)
)
print(pooled)
ild_data <- data.frame(
dyad_id = rep(c(1, 2), each = 4),
person_id = rep(c(1, 2), times = 4),
time = rep(c(1, 1, 2, 2), times = 2),
x = c(4, 7, 5, 8, 3, 6, 4, 7)
)
ild_prepared <- prepare_dyad_data(
ild_data,
dyad = dyad_id,
member = person_id,
time = time,
predictors = x,
lag1_predictors = x,
model_types = "apim",
seed = 123
)
print(ild_prepared)
Print recovered exchangeable residual covariance
Description
Print recovered exchangeable residual covariance
Usage
## S3 method for class 'exchangeable_rescov'
print(x, representation = c("both", "varcov", "sdcor"), digits = 3L, ...)
Arguments
x |
An object returned by |
representation |
Which representation to print: |
digits |
Number of decimal places to print. |
... |
Additional arguments passed to |
Value
x, invisibly.
Recover member-level residual covariance from exchangeable random-effect blocks
Description
Back-transforms covariance matrices from paired shared and member-difference random-effect blocks to the covariance structure of two exchangeable members. The result is on the fitted random effects' linear-predictor scale. In non-Gaussian models, it therefore describes a Gaussian latent covariance, not response-scale residual covariance. For the model specification, derivation, and interpretation, see the exchangeable APIM vignette.
Usage
recover_exchangeable_covariance(model, block_pairings = NULL)
Arguments
model |
A fitted |
block_pairings |
|
Details
Automatic matching recognizes exact .dy_member_contrast_*_arbitrary and
legacy .dy_diff_*_arbitrary coefficient names
and first looks for the corresponding .dy_is_* shared block. It requires
the two blocks to use the same grouping factor and the same underlying
terms. Most models fitted with dyadMLM-generated columns therefore need
only:
result <- dyadMLM::recover_exchangeable_covariance(model) print(result)
Supply block_pairings when automatic matching is ambiguous or when a model uses
custom indicators, multiple covariance levels, or deliberately omitted
blocks or terms. To specify one pair with a custom difference indicator:
result <- dyadMLM::recover_exchangeable_covariance(
model,
block_pairings = list(
shared_block = "(1 + time | coupleID)",
difference_block = "(0 + my_diff + I(my_diff * time) | coupleID)",
difference_indicator = "my_diff"
)
)
For multiple covariance levels, wrap the pairings in an outer list. For example,
in a Gaussian glmmTMB model fitted with dispformula = ~ 0, this call
recovers both a stable dyad-level covariance with an omitted difference
time slope and the same-occasion partner residual covariance:
result <- dyadMLM::recover_exchangeable_covariance(
model,
block_pairings = list(
dyad = list(
shared_block = "(1 + diaryday | coupleID)",
difference_block = "(0 + .dy_member_contrast_assumed_exchangeable_arbitrary | coupleID)",
difference_indicator =
".dy_member_contrast_assumed_exchangeable_arbitrary"
),
same_occasion = list(
shared_block = "(1 | coupleID:diaryday)",
difference_block = "(0 + .dy_member_contrast_assumed_exchangeable_arbitrary | coupleID:diaryday)",
difference_indicator =
".dy_member_contrast_assumed_exchangeable_arbitrary"
)
)
)
At the dyad level, the fitted model includes a shared time slope but no
difference time slope. Thus, the two members' time random effects are
identical at this level, with correlation +1 whenever the shared slope
variance is non-zero; at zero variance, the correlation is undefined.
Covariances involving the diary-day slope are therefore supplied entirely by
the shared block.
The random-effect terms may be copied exactly from the model formula.
Equivalent backend syntax is also recognized, such as
(1 + time | group) and us(1 + time | group), or
(0 + x || group) and diag(0 + x | group). A custom difference-indicator
name is supplied literally. Difference slopes may be written in either
interaction order or as a simple product inside I().
When a difference block is supplied and the fitted model frame retains the
indicator columns, difference_indicator must assign -1 and +1 to the
two arbitrary member positions consistently within each dyad. For
composition-specific blocks, it must be zero where shared_indicator is
zero.
For custom difference indicators supplied through block_pairings, the function
checks whether both positions occur within each supported fitted grouping
unit. It rejects coding when no group contains both positions, and warns when
only some groups are one-sided, which can result from fitted-row filtering.
It also warns when stable member assignments cannot be verified across
repeated rows without a member identifier.
Value
An exchangeable_rescov object: a named list with one element per
matched block pairing. Each element contains shared_term and
difference_term (each a fitted term string or NULL), plus the member-level
variance-covariance matrix in varcov and its standard-deviation/correlation
representation in sdcor, with standard deviations on the diagonal and
correlations off the diagonal. Covariance dimension labels member_1 and
member_2 denote arbitrary exchangeable positions, not substantive roles
or encodings. Caller-supplied outer names are preserved; unnamed pairings
receive stable names pair_1, pair_2, and so on in resolved order.
For glmmTMB, varcov and sdcor are matrices. For brms, they
are posterior-draw by coefficient by coefficient arrays.
What omitted blocks and terms mean
recover_exchangeable_covariance() only describes constraints that were already imposed
when the model was fitted. It does not remove a block, set a variance to zero,
or otherwise constrain the supplied model. Describe only the structure that
was actually fitted.
If a term occurs in only one selected block, the function represents the missing coordinate as a structural zero:
A term present only in the shared block has no difference component, so the two members have identical random effects for that term.
A term present only in the difference block has no shared component, so the two members have equal-magnitude, opposite-sign random effects for that term.
Setting difference_block = NULL or shared_block = NULL applies the corresponding rule
to the entire omitted block. This is valid only when that block is truly
absent from the fitted model. Do not use NULL merely to ignore an existing
block; the resulting back-transformation would be incorrect.
See the constrained-block example in the exchangeable APIM vignette.
Backend note
For glmmTMB, random effects in non-conditional components are ignored with
a warning. See the vignette's
extension to exchangeable random slopes
section for the manual calculation.
In brms, cross-sectional and same-occasion partner dependence can be
represented directly with
unstr(time = member_position, gr = residual_group). With Gaussian
outcomes, sigma ~ 1 supplies the common residual scale. Non-Gaussian
families have no sigma parameter here; unstr() instead estimates a
common latent residual scale and correlation on the linear-predictor scale.
Here,
member_position identifies the same two arbitrary positions within every
group, and residual_group identifies dyads in cross-sectional data or
dyad-occasions in longitudinal data. This direct specification applies when
one covariance structure is sufficient. Separate composition-specific
unstr() structures for mixed dyad types are not currently supported in a
standard single-response brms model. For Gaussian mixed-dyad residual
covariance, use glmmTMB. Shared/difference blocks remain relevant for
higher-level random effects and can represent latent link-scale covariance
in non-Gaussian models.
See Also
The
exchangeable APIM vignette
for the model specification, covariance derivation, and constrained-block
example. Run vignette("apim", package = "dyadMLM") to open the installed
version.
Examples
if (requireNamespace("glmmTMB", quietly = TRUE)) {
example_data <- prepare_dyad_data(
dyads_cross,
dyad = coupleID,
member = personID,
role = gender,
model_types = "none",
# All three observed compositions in `dyads_cross` are detected and retained
# by default. This example focuses on `female-female` dyads, so we restrict
# the analysis here.
keep_compositions = "female-female",
seed = 123
)
model <- glmmTMB::glmmTMB(
closeness ~ 1 +
us(1 | coupleID) +
us(0 + .dy_member_contrast_female_x_female_arbitrary | coupleID),
dispformula = ~ 0,
data = example_data
)
recover_exchangeable_covariance(model)
}
Resolve user-supplied composition references
Description
Resolve user-supplied composition references
Usage
resolve_composition_references(references, observed_compositions, arg_name)
Arguments
references |
A character vector of composition references. |
observed_compositions |
Canonical composition labels observed in the data. |
arg_name |
Name of the user-facing argument for error messages. |
Value
Canonical observed composition labels.
Resolve the DSM role order
Description
Checks the relationship between model_types, role, and dsm_role_order,
validates the requested role order, and returns its stored representation.
Usage
resolve_dsm_role_order(dsm_role_order, model_types, has_role)
Arguments
dsm_role_order |
The requested DSM role order. |
model_types |
The normalized model types. |
has_role |
Whether a role column was supplied. |
Value
The validated, unnamed role order, or NULL.
Validate DIM compatibility
Description
Checks whether a dyadMLM_data object can be used for the currently
supported undirected DIM construction. These models
currently support only data with exactly one exchangeable dyad composition. Distinguishable or
multiple exchangeable compositions are rejected until explicit role-contrast,
composition-specific, or pooling support is added.
Usage
validate_dim_compatibility(data)
Arguments
data |
A |
Value
Invisibly returns data when compatible.
Validate DSM compatibility
Description
Checks whether prepared data contain the single distinguishable dyad composition required by the DSM and whether its observed roles match the declared directional role order.
Usage
validate_dsm_compatibility(data)
Arguments
data |
A |
Value
Invisibly returns data when compatible.
Validate dyadic input data
Description
Checks whether data has a valid long-format dyadic structure and returns it
as a tibble with an additional dyadMLM_data class. Cross-sectional data
may contain at most one row per member within each dyad. Intensive
longitudinal data may contain at most one row per member and measurement
occasion within each dyad.
Usage
validate_dyad_data(
data,
dyad,
member,
role = NULL,
time = NULL,
predictors = NULL,
lag1_predictors = NULL,
model_types = "apim",
dsm_role_order = NULL,
temporal_decomposition = c("auto", "2l", "none"),
incomplete_dyads = c("error", "drop"),
missing_role = c("error", "drop")
)
Arguments
data |
A long-format data frame or tibble. |
dyad |
Column identifying the dyad. |
member |
Column identifying the two people or members within each dyad, such as a person ID. |
role |
Optional column identifying a stable member role, such as gender.
Non-missing values must be consistent within each |
time |
Optional column identifying time or measurement order. |
predictors |
Optional variables to select and store as metadata for temporal predictor decomposition and model-helper functions. |
lag1_predictors |
Optional subset of |
model_types |
Requested model-ready column families. Can contain one or
more of |
dsm_role_order |
For |
temporal_decomposition |
Requested temporal predictor decomposition
strategy for predictors. |
incomplete_dyads |
How to handle dyads with fewer than two unique
members across all rows in |
missing_role |
How to handle dyads in which at least one member has no
non-missing |
Value
A tibble with class dyadMLM_data and metadata about the dyad,
member, optional role, and optional time columns.