knitr::opts_chunk$set( collapse = TRUE, comment = "#>" )
library(dyadMLM)
Install the stable release from CRAN:
install.packages("dyadMLM")
To try the latest changes and help test upcoming features, install the development version from R-universe:
install.packages( "dyadMLM", repos = c( "https://pascal-kueng.r-universe.dev", "https://cloud.r-project.org" ) )
Development versions may change more frequently. Feedback is welcome through GitHub issues.
dyadMLM helps researchers prepare cross-sectional and intensive longitudinal
dyadic data for (generalized) multilevel models.
This vignette focuses on automatic data preparation for multilevel models (MLMs). For a comparison of MLM and structural equation modeling (SEM) approaches to dyadic data, see @ledermannAnalyzingDyadicData2017.
The model-fitting examples in the model-specific vignettes use the
glmmTMB package.
Post-estimation functions in dyadMLM, including model comparison and
back-transformation of exchangeable random-effect covariance structures, are
described in the Actor-Partner Interdependence Model vignette.
Other vignettes cover the Dyad-Individual Model and its equivalence to the exchangeable APIM, and the Dyadic Score Model and its equivalence to the distinguishable APIM. They also describe the corresponding coefficient and covariance transformations.
The online package overview provides the current online versions of these vignettes and the complete function reference.
The basic data structure needed for dyadMLM is a long data frame where dyads
are stacked on top of each other and both members of a dyad appear as separate
rows.
Roughly, the expected structure for dyadMLM is:
dyad x member| dyad | member | x | y | |---:|---:|---:|---:| | 1 | 1 | 4.2 | 7.1 | | 1 | 2 | 5.0 | 6.4 | | 2 | 1 | 3.8 | 5.9 | | 2 | 2 | 4.5 | 6.8 |
dyad x time x member| dyad | time | member | x | y | |---:|---:|---:|---:|---:| | 1 | 1 | 1 | 4.2 | 7.1 | | 1 | 1 | 2 | 5.0 | 6.4 | | 1 | 2 | 1 | 4.0 | 6.9 | | 1 | 2 | 2 | 5.3 | 6.6 |
Measured variables may contain missing values, but dyad, member, and
optional time must be complete; missing measurement occasions may instead be
represented by absent rows.
If your raw data are currently in wide format (for time or dyads or both),
reshape them to this long structure first. See the
tidyr pivoting vignette or
the pivot_longer() reference.
dyads_cross is a simulated cross-sectional dataset that contains three dyad
compositions.
Because these example data contain multiple compositions, keep_compositions
selects the composition modeled below. It can be omitted when the supplied data
already contain only the intended composition.
head(dyadMLM::dyads_cross)
We validate and prepare the data with the function dyadMLM::prepare_dyad_data().
cross_distinguishable_data <- dyadMLM::prepare_dyad_data( data = dyads_cross, dyad = coupleID, member = personID, role = gender, predictors = provided_support, model_types = "apim", add_apim_gmc_predictors = TRUE, # Optional grand-mean centering # 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" ) print(cross_distinguishable_data, n = 4)
The function retained 120 female-male dyads and created raw and grand-mean centered APIM variables [@kennyPartnerEffectsRelationship1999].
For fitted APIM examples using these columns, see the Actor-Partner Interdependence Model vignette.
For this example, we pretend that we have a dataset with no distinguishable
variable (e.g., same-sex friend dyads). Then, we simply omit the role argument:
cross_exchangeable_data <- dyadMLM::prepare_dyad_data( data = dyads_cross, dyad = coupleID, member = personID, predictors = provided_support, model_types = "apim", add_apim_gmc_predictors = TRUE, seed = 123 ) print(cross_exchangeable_data, n = 4)
The generated .member_contrast_arbitrary contrast assigns -1
and 1 to the two members of each exchangeable dyad
[@delrosarioPracticalGuideSpecifying2025]. Its direction is arbitrary, and
seed makes the assignment reproducible.
Refer to the APIM vignette's
exchangeable APIM section
for how to use these columns to specify an exchangeable dyadic APIM and recover
the constrained actor-partner variance-covariance structure with
dyadMLM::recover_exchangeable_covariance().
For exchangeable dyads, we can request DIM predictor columns.
DIM preparation requires exactly one exchangeable composition. This can be
achieved by omitting role. For more control over compositions, see
Working with multiple dyad compositions.
cross_dim_data <- dyadMLM::prepare_dyad_data( data = dyads_cross, dyad = coupleID, member = personID, predictors = provided_support, model_types = "dim", seed = 123 ) print(cross_dim_data, n = 4)
For distinguishable dyads, we can request DSM columns. DSM preparation currently requires exactly one distinguishable composition. To compute these columns, an explicit role order is required. The role order defines the direction of all DSM predictor differences and the DSM role contrast [@iidaModelsInterdependentIndividuals2018].
cross_dsm_data <- dyadMLM::prepare_dyad_data( data = dyads_cross, dyad = coupleID, member = personID, role = gender, predictors = provided_support, model_types = "dsm", dsm_role_order = c("female", "male"), keep_compositions = "female-male" ) print(cross_dsm_data, n = 4)
APIM GMC uses all retained non-missing values. DIM and DSM center complete-pair dyad means. The constants may differ with one-sided missingness.
In DIM and DSM, mean predictors are grand-mean centered by convention; thus, no additional argument is required to request them.
dyads_ild is a simulated intensive longitudinal dyadic dataset. Each dyad
has repeated observations over diaryday, with one row per person-day.
head(dyads_ild)
To prepare intensive longitudinal data, pass the time variable to
dyadMLM::prepare_dyad_data().
ild_apim_data <- dyadMLM::prepare_dyad_data( dyads_ild, dyad = coupleID, member = personID, role = gender, time = diaryday, predictors = provided_support, model_types = "apim", keep_compositions = "female-male", seed = 123 ) print(ild_apim_data, n = 6)
By default, numeric predictors in longitudinal APIM preparation are
decomposed into within-person and between-person components
[@bolgerIntensiveLongitudinalMethods2013]. This temporal predictor decomposition
is controlled by temporal_decomposition. The default "auto"
setting selects "2l" (2-level temporal decomposition).
add_apim_gmc_predictors = TRUE requires resolved
temporal_decomposition = "none", since the between-person component is
always already grand-mean centered by convention.
Note that observed person means used to construct the between-person (cbp)
predictors can be unreliable when each member contributes few occasions, which
can bias between-person estimates [@gottfredsonStraightforwardApproachCoping2019].
For fitted concurrent examples and AR(1) specifications for distinguishable and exchangeable dyads, refer to the intensive longitudinal APIM section.
Lagged versions of variables, including an outcome that is also passed to
predictors for dynamic models, can be obtained through the
lag1_predictors argument.
Lagging respects the dyad and member structure, matches observations at exactly
time - 1, and does not bridge missing occasions when rows are missing
in the dataset.
ild_apim_data_dynamic <- dyadMLM::prepare_dyad_data( dyads_ild, dyad = coupleID, member = personID, role = gender, time = diaryday, predictors = closeness, lag1_predictors = closeness, model_types = "apim", keep_compositions = "female-female", seed = 123 ) print(ild_apim_data_dynamic, n = 6)
Note: Whether to use the prepared raw or within-person-centered lagged outcome depends on the research question and the data. See the dynamic ILD APIM example for a more detailed discussion and guidance.
dyads_cross contains three dyad compositions:
distinguishable female-male dyads and exchangeable female-female and male-male
dyads [@Bolger2025Unified].
Let's have dyadMLM infer the compositions automatically:
mixed_cross_data <- dyadMLM::prepare_dyad_data( dyads_cross, dyad = coupleID, member = personID, role = gender, seed = 123 ) print(mixed_cross_data, n = 4)
Note that when role compositions are available, each exchangeable composition
receives its own difference contrast, such as
.member_contrast_female_x_female_arbitrary, which is 0 for all other
compositions.
We can use this data to model these dyad types as separate or in the same model.
Sometimes a mixed dataset contains dyad compositions that should not be part of
a given analysis. Use keep_compositions to keep only dyads whose observed
composition matches the requested labels. The filtering happens before
exchangeability constraints and pooling, so set_exchangeable_compositions
and pool_compositions (described later) can only refer to retained dyad
compositions.
mixed_cross_data_included <- dyadMLM::prepare_dyad_data( dyads_cross, dyad = coupleID, member = personID, role = gender, keep_compositions = c("female-female", "male-male"), seed = 123 ) print(mixed_cross_data_included, n = 4)
Note that whenever you need to refer to a dyad type, the order of members does
not matter (e.g., male-female and female-male will both work), and you can
use different separators like male_female, male_x_female, or male female.
set_exchangeable_compositions changes how selected role-defined compositions
are modeled while preserving their composition labels. By contrast, omitting
role indicates that no distinguishing variable is available, so all dyads are
treated as one exchangeable composition with a single global arbitrary-member
contrast.
mixed_cross_exchangeable_data <- dyadMLM::prepare_dyad_data( dyads_cross, dyad = coupleID, member = personID, role = gender, set_exchangeable_compositions = c("male-female"), seed = 123 ) print(mixed_cross_exchangeable_data, n = 4)
Sometimes, we may want to pool selected exchangeable dyad compositions and
analyze them as if they were one. Pooling can impose equality constraints among
compositions. After fitting nested pooled and unpooled models to the same
observations, these constraints can be tested with
dyadMLM::compare_nested_models(); see
testing distinguishability in the APIM vignette
for the model-comparison workflow.
For instance, let's pool male-male and female-female dyads
and name them same-sex dyads:
mixed_cross_data_pooled <- dyadMLM::prepare_dyad_data( dyads_cross, dyad = coupleID, member = personID, role = gender, pool_compositions = list( "same-sex" = c("male-male", "female_female") ), seed = 123 ) print(mixed_cross_data_pooled)
Note that you cannot pool distinguishable dyads. If we wanted to pool
female-male with male-male, we would first have to treat female-male as
exchangeable:
mixed_cross_data_pooled_constrained <- dyadMLM::prepare_dyad_data( dyads_cross, dyad = coupleID, member = personID, role = gender, set_exchangeable_compositions = "male female", pool_compositions = list( "pooled_exchangeable" = c("male-male", "male_female") ), seed = 123 ) print(mixed_cross_data_pooled_constrained)
If you use dyadMLM, please cite the version of the package you use. Obtain the
citation via:
citation("dyadMLM")
Continue with the Actor-Partner Interdependence Model (APIM) vignette.
Related model-specific vignettes:
or return to About this vignette.
::: {#refs} :::
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.