You can install the development version with:
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 Ledermann and Kenny (2017).
The model-fitting examples in the model-specific vignettes use the
glmmTMB package.
Post-processing 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 and back-transformation to the exchangeable APIM, and the Dyadic Score Model with its equivalence and back-transformation to the distinguishable APIM.
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.
#> # A tibble: 6 × 5
#> personID coupleID gender closeness provided_support
#> <int> <int> <fct> <dbl> <dbl>
#> 1 1 1 female 4.71 4.49
#> 2 2 1 male 4.61 4.76
#> 3 3 2 female 6.69 4.09
#> 4 4 2 male 5.98 6.20
#> 5 5 3 female 5.27 4.22
#> 6 6 3 male 4.37 5.03
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)
#> # dyadMLM data
#> # Rows: 240 | Dyads: 120 | Intensive longitudinal: no
#> # Structure: dyad = coupleID, member = personID, role = gender
#> #
#> # Dyad compositions:
#> # female_x_male distinguishable 120 dyads
#> #
#> # Added columns:
#> # .composition inferred dyad composition
#> # .composition_role composition-specific member role
#> # .is_{role} composition-role indicator columns
#> # .{pred}_actor APIM actor predictor: actor's original predictor
#> # values
#> # .{pred}_partner APIM partner predictor: partner's original predictor
#> # values
#> # .{pred}_gmc APIM grand-mean-centered predictor source: original
#> # values minus the mean across all retained non-missing
#> # observations
#> # .{pred}_gmc_actor APIM grand-mean-centered actor predictor: actor's
#> # value relative to the mean across all retained
#> # non-missing observations
#> # .{pred}_gmc_partner APIM grand-mean-centered partner predictor: partner's
#> # value relative to the mean across all retained
#> # non-missing observations
#> #
#> # A tibble: 240 × 14
#> personID coupleID gender closeness provided_support .composition
#> <int> <int> <fct> <dbl> <dbl> <fct>
#> 1 1 1 female 4.71 4.49 female_x_male
#> 2 2 1 male 4.61 4.76 female_x_male
#> 3 3 2 female 6.69 4.09 female_x_male
#> 4 4 2 male 5.98 6.20 female_x_male
#> # ℹ 236 more rows
#> # ℹ 8 more variables: .composition_role <fct>, .is_female <dbl>,
#> # .is_male <dbl>, .provided_support_gmc <dbl>, .provided_support_actor <dbl>,
#> # .provided_support_partner <dbl>, .provided_support_gmc_actor <dbl>,
#> # .provided_support_gmc_partner <dbl>The function retained 120 female-male dyads and created raw and grand-mean centered APIM variables (Kenny and Cook 1999).
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)
#> # dyadMLM data
#> # Rows: 720 | Dyads: 360 | Intensive longitudinal: no
#> # Structure: dyad = coupleID, member = personID
#> #
#> # Dyad compositions:
#> # assumed_exchangeable exchangeable 360 dyads
#> #
#> # Added columns:
#> # .composition inferred dyad composition
#> # .composition_role composition-specific member role
#> # .is_exchangeable composition-role indicator columns
#> # .member_contrast_arbitrary composition-specific member contrasts coded
#> # -1/+1 in arbitrary direction for
#> # exchangeability-constrained random effects.
#> # Values are 0 for other compositions
#> # .{pred}_actor APIM actor predictor: actor's original
#> # predictor values
#> # .{pred}_partner APIM partner predictor: partner's original
#> # predictor values
#> # .{pred}_gmc APIM grand-mean-centered predictor source:
#> # original values minus the mean across all
#> # retained non-missing observations
#> # .{pred}_gmc_actor APIM grand-mean-centered actor predictor:
#> # actor's value relative to the mean across all
#> # retained non-missing observations
#> # .{pred}_gmc_partner APIM grand-mean-centered partner predictor:
#> # partner's value relative to the mean across all
#> # retained non-missing observations
#> #
#> # A tibble: 720 × 14
#> personID coupleID gender closeness provided_support .composition
#> <int> <int> <fct> <dbl> <dbl> <fct>
#> 1 1 1 female 4.71 4.49 assumed_exchangeable
#> 2 2 1 male 4.61 4.76 assumed_exchangeable
#> 3 3 2 female 6.69 4.09 assumed_exchangeable
#> 4 4 2 male 5.98 6.20 assumed_exchangeable
#> # ℹ 716 more rows
#> # ℹ 8 more variables: .composition_role <fct>, .is_exchangeable <dbl>,
#> # .member_contrast_arbitrary <dbl>, .provided_support_gmc <dbl>,
#> # .provided_support_actor <dbl>, .provided_support_partner <dbl>,
#> # .provided_support_gmc_actor <dbl>, .provided_support_gmc_partner <dbl>The generated .member_contrast_arbitrary contrast
assigns -1 and 1 to the two members of each
exchangeable dyad (del Rosario and West
2025). 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)
#> # dyadMLM data
#> # Rows: 720 | Dyads: 360 | Intensive longitudinal: no
#> # Structure: dyad = coupleID, member = personID
#> #
#> # Dyad compositions:
#> # assumed_exchangeable exchangeable 360 dyads
#> #
#> # Added columns:
#> # .composition inferred dyad composition
#> # .composition_role composition-specific member role
#> # .is_exchangeable composition-role indicator columns
#> # .member_contrast_arbitrary composition-specific member contrasts coded
#> # -1/+1 in arbitrary direction for
#> # exchangeability-constrained random effects.
#> # Values are 0 for other compositions
#> # .{pred}_dyad_mean_gmc dyad-mean predictor: dyad's average predictor
#> # level, grand-mean centered
#> # .{pred}_within_dyad_dev DIM within-dyad member-deviation predictor:
#> # member's difference from the dyad mean
#> #
#> # A tibble: 720 × 11
#> personID coupleID gender closeness provided_support .composition
#> <int> <int> <fct> <dbl> <dbl> <fct>
#> 1 1 1 female 4.71 4.49 assumed_exchangeable
#> 2 2 1 male 4.61 4.76 assumed_exchangeable
#> 3 3 2 female 6.69 4.09 assumed_exchangeable
#> 4 4 2 male 5.98 6.20 assumed_exchangeable
#> # ℹ 716 more rows
#> # ℹ 5 more variables: .composition_role <fct>, .is_exchangeable <dbl>,
#> # .member_contrast_arbitrary <dbl>, .provided_support_dyad_mean_gmc <dbl>,
#> # .provided_support_within_dyad_dev <dbl>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 (Iida, Seidman, and Shrout 2018).
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)
#> # dyadMLM data
#> # Rows: 240 | Dyads: 120 | Intensive longitudinal: no
#> # Structure: dyad = coupleID, member = personID, role = gender
#> # DSM direction: female - male
#> #
#> # Dyad compositions:
#> # female_x_male distinguishable 120 dyads
#> #
#> # Added columns:
#> # .composition inferred dyad composition
#> # .composition_role composition-specific member role
#> # .is_{role} composition-role indicator columns
#> # .dsm_role_contrast DSM role contrast: +0.5 for the first declared
#> # role and -0.5 for the second declared role
#> # .{pred}_dyad_mean_gmc dyad-mean predictor: dyad's average predictor
#> # level, grand-mean centered
#> # .{pred}_within_dyad_diff DSM signed predictor difference: first declared
#> # role minus second declared role
#> #
#> # A tibble: 240 × 12
#> personID coupleID gender closeness provided_support .composition
#> <int> <int> <fct> <dbl> <dbl> <fct>
#> 1 1 1 female 4.71 4.49 female_x_male
#> 2 2 1 male 4.61 4.76 female_x_male
#> 3 3 2 female 6.69 4.09 female_x_male
#> 4 4 2 male 5.98 6.20 female_x_male
#> # ℹ 236 more rows
#> # ℹ 6 more variables: .composition_role <fct>, .is_female <dbl>,
#> # .is_male <dbl>, .dsm_role_contrast <dbl>,
#> # .provided_support_dyad_mean_gmc <dbl>,
#> # .provided_support_within_dyad_diff <dbl>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.
#> # A tibble: 6 × 6
#> personID coupleID diaryday gender closeness provided_support
#> <int> <int> <int> <fct> <dbl> <dbl>
#> 1 1 1 0 female 3.74 4.93
#> 2 2 1 0 male 5.91 5.59
#> 3 1 1 1 female 3.72 4.89
#> 4 2 1 1 male 6.32 5.18
#> 5 1 1 2 female 2.45 4.38
#> 6 2 1 2 male 3.44 4.99
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)
#> # dyadMLM data
#> # Rows: 3360 | Dyads: 120 | Intensive longitudinal: yes
#> # Structure: dyad = coupleID, member = personID, role = gender, time = diaryday
#> #
#> # Dyad compositions:
#> # female_x_male distinguishable 120 dyads
#> #
#> # Added columns:
#> # .composition inferred dyad composition
#> # .composition_role composition-specific member role
#> # .is_{role} composition-role indicator columns
#> # .{pred}_cwp within-person predictor: momentary deviations from
#> # each person's usual level
#> # .{pred}_cbp between-person predictor: stable differences from the
#> # average person's usual level
#> # .{pred}_actor APIM actor predictor: actor's original predictor
#> # values
#> # .{pred}_partner APIM partner predictor: partner's original predictor
#> # values
#> # .{pred}_cwp_actor APIM within-person actor predictor: actor's momentary
#> # deviations from their usual level
#> # .{pred}_cwp_partner APIM within-person partner predictor: partner's
#> # momentary deviations from their usual level
#> # .{pred}_cbp_actor APIM between-person actor predictor: actor's stable
#> # difference from the average person's usual level
#> # .{pred}_cbp_partner APIM between-person partner predictor: partner's
#> # stable difference from the average person's usual
#> # level
#> #
#> # A tibble: 3,360 × 18
#> personID coupleID diaryday gender closeness provided_support .composition
#> <int> <int> <int> <fct> <dbl> <dbl> <fct>
#> 1 1 1 0 female 3.74 4.93 female_x_male
#> 2 2 1 0 male 5.91 5.59 female_x_male
#> 3 1 1 1 female 3.72 4.89 female_x_male
#> 4 2 1 1 male 6.32 5.18 female_x_male
#> 5 1 1 2 female 2.45 4.38 female_x_male
#> 6 2 1 2 male 3.44 4.99 female_x_male
#> # ℹ 3,354 more rows
#> # ℹ 11 more variables: .composition_role <fct>, .is_female <dbl>,
#> # .is_male <dbl>, .provided_support_cwp <dbl>, .provided_support_cbp <dbl>,
#> # .provided_support_actor <dbl>, .provided_support_partner <dbl>,
#> # .provided_support_cwp_actor <dbl>, .provided_support_cwp_partner <dbl>,
#> # .provided_support_cbp_actor <dbl>, .provided_support_cbp_partner <dbl>By default, numeric predictors in longitudinal APIM preparation are
decomposed into within-person and between-person components (Bolger and Laurenceau 2013). 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 (Gottfredson 2019).
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)
#> # dyadMLM data
#> # Rows: 3360 | Dyads: 120 | Intensive longitudinal: yes
#> # Structure: dyad = coupleID, member = personID, role = gender, time = diaryday
#> #
#> # Dyad compositions:
#> # female_x_female exchangeable 120 dyads
#> #
#> # Added columns:
#> # .composition inferred dyad composition
#> # .composition_role composition-specific member role
#> # .is_exchangeable composition-role indicator columns
#> # .member_contrast_arbitrary composition-specific member contrasts coded
#> # -1/+1 in arbitrary direction for
#> # exchangeability-constrained random effects.
#> # Values are 0 for other compositions
#> # .{pred}_lag1 lag-1 raw predictor values
#> # .{pred}_cwp within-person predictor: momentary deviations
#> # from each person's usual level
#> # .{pred}_cwp_lag1 lag-1 within-person predictor: momentary
#> # deviations from each person's usual level
#> # .{pred}_cbp between-person predictor: stable differences
#> # from the average person's usual level
#> # .{pred}_actor APIM actor predictor: actor's original
#> # predictor values
#> # .{pred}_actor_lag1 lag-1 APIM actor predictor: actor's original
#> # predictor values
#> # .{pred}_partner APIM partner predictor: partner's original
#> # predictor values
#> # .{pred}_partner_lag1 lag-1 APIM partner predictor: partner's
#> # original predictor values
#> # .{pred}_cwp_actor APIM within-person actor predictor: actor's
#> # momentary deviations from their usual level
#> # .{pred}_cwp_actor_lag1 lag-1 APIM within-person actor predictor:
#> # actor's momentary deviations from their usual
#> # level
#> # .{pred}_cwp_partner APIM within-person partner predictor: partner's
#> # momentary deviations from their usual level
#> # .{pred}_cwp_partner_lag1 lag-1 APIM within-person partner predictor:
#> # partner's momentary deviations from their usual
#> # level
#> # .{pred}_cbp_actor APIM between-person actor predictor: actor's
#> # stable difference from the average person's
#> # usual level
#> # .{pred}_cbp_partner APIM between-person partner predictor:
#> # partner's stable difference from the average
#> # person's usual level
#> #
#> # A tibble: 3,360 × 24
#> personID coupleID diaryday gender closeness provided_support .composition
#> <int> <int> <int> <fct> <dbl> <dbl> <fct>
#> 1 241 121 0 female 6.60 6.18 female_x_female
#> 2 242 121 0 female 5.22 5.70 female_x_female
#> 3 241 121 1 female 8.33 4.57 female_x_female
#> 4 242 121 1 female 5.24 5.30 female_x_female
#> 5 241 121 2 female 6.55 5.19 female_x_female
#> 6 242 121 2 female 6.85 3.89 female_x_female
#> # ℹ 3,354 more rows
#> # ℹ 17 more variables: .composition_role <fct>, .is_exchangeable <dbl>,
#> # .member_contrast_arbitrary <dbl>, .closeness_cwp <dbl>,
#> # .closeness_cbp <dbl>, .closeness_lag1 <dbl>, .closeness_cwp_lag1 <dbl>,
#> # .closeness_actor <dbl>, .closeness_partner <dbl>,
#> # .closeness_cwp_actor <dbl>, .closeness_cwp_partner <dbl>,
#> # .closeness_cbp_actor <dbl>, .closeness_cbp_partner <dbl>, …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 (Bolger, Laurenceau, and
DiGiovanni 2025).
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)
#> # dyadMLM data
#> # Rows: 720 | Dyads: 360 | Intensive longitudinal: no
#> # Structure: dyad = coupleID, member = personID, role = gender
#> #
#> # Dyad compositions:
#> # female_x_female exchangeable 120 dyads
#> # female_x_male distinguishable 120 dyads
#> # male_x_male exchangeable 120 dyads
#> #
#> # Added columns:
#> # .composition inferred dyad composition
#> # .composition_role composition-specific member role
#> # .is_{comp-role} composition-role indicator columns
#> # .member_contrast_{comp}_arbitrary composition-specific member contrasts
#> # coded -1/+1 in arbitrary direction for
#> # exchangeability-constrained random
#> # effects. Values are 0 for other
#> # compositions
#> #
#> # A tibble: 720 × 13
#> personID coupleID gender closeness provided_support .composition
#> <int> <int> <fct> <dbl> <dbl> <fct>
#> 1 1 1 female 4.71 4.49 female_x_male
#> 2 2 1 male 4.61 4.76 female_x_male
#> 3 3 2 female 6.69 4.09 female_x_male
#> 4 4 2 male 5.98 6.20 female_x_male
#> # ℹ 716 more rows
#> # ℹ 7 more variables: .composition_role <fct>, .is_female_x_female <dbl>,
#> # .is_female_x_male_female <dbl>, .is_female_x_male_male <dbl>,
#> # .is_male_x_male <dbl>, .member_contrast_female_x_female_arbitrary <dbl>,
#> # .member_contrast_male_x_male_arbitrary <dbl>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)
#> # dyadMLM data
#> # Rows: 480 | Dyads: 240 | Intensive longitudinal: no
#> # Structure: dyad = coupleID, member = personID, role = gender
#> #
#> # Dyad compositions:
#> # female_x_female exchangeable 120 dyads
#> # male_x_male exchangeable 120 dyads
#> #
#> # Added columns:
#> # .composition inferred dyad composition
#> # .composition_role composition-specific member role
#> # .is_{comp-role} composition-role indicator columns
#> # .member_contrast_{comp}_arbitrary composition-specific member contrasts
#> # coded -1/+1 in arbitrary direction for
#> # exchangeability-constrained random
#> # effects. Values are 0 for other
#> # compositions
#> #
#> # A tibble: 480 × 11
#> personID coupleID gender closeness provided_support .composition
#> <int> <int> <fct> <dbl> <dbl> <fct>
#> 1 241 121 female 7.34 5.41 female_x_female
#> 2 242 121 female 6.43 5.19 female_x_female
#> 3 243 122 female 8.18 5.89 female_x_female
#> 4 244 122 female 8.48 5.57 female_x_female
#> # ℹ 476 more rows
#> # ℹ 5 more variables: .composition_role <fct>, .is_female_x_female <dbl>,
#> # .is_male_x_male <dbl>, .member_contrast_female_x_female_arbitrary <dbl>,
#> # .member_contrast_male_x_male_arbitrary <dbl>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)
#> # dyadMLM data
#> # Rows: 720 | Dyads: 360 | Intensive longitudinal: no
#> # Structure: dyad = coupleID, member = personID, role = gender
#> #
#> # Dyad compositions:
#> # female_x_female exchangeable 120 dyads
#> # female_x_male exchangeable (set by user) 120 dyads
#> # male_x_male exchangeable 120 dyads
#> #
#> # Added columns:
#> # .composition inferred dyad composition
#> # .composition_role composition-specific member role
#> # .is_{comp-role} composition-role indicator columns
#> # .member_contrast_{comp}_arbitrary composition-specific member contrasts
#> # coded -1/+1 in arbitrary direction for
#> # exchangeability-constrained random
#> # effects. Values are 0 for other
#> # compositions
#> #
#> # A tibble: 720 × 13
#> personID coupleID gender closeness provided_support .composition
#> <int> <int> <fct> <dbl> <dbl> <fct>
#> 1 1 1 female 4.71 4.49 female_x_male
#> 2 2 1 male 4.61 4.76 female_x_male
#> 3 3 2 female 6.69 4.09 female_x_male
#> 4 4 2 male 5.98 6.20 female_x_male
#> # ℹ 716 more rows
#> # ℹ 7 more variables: .composition_role <fct>, .is_female_x_female <dbl>,
#> # .is_female_x_male <dbl>, .is_male_x_male <dbl>,
#> # .member_contrast_female_x_female_arbitrary <dbl>,
#> # .member_contrast_female_x_male_arbitrary <dbl>,
#> # .member_contrast_male_x_male_arbitrary <dbl>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)
#> # dyadMLM data
#> # Rows: 720 | Dyads: 360 | Intensive longitudinal: no
#> # Structure: dyad = coupleID, member = personID, role = gender
#> #
#> # Dyad compositions:
#> # female_x_male distinguishable 120 dyads
#> # same-sex (pooled) exchangeable 240 dyads
#> # female_x_female
#> # male_x_male
#> #
#> # Added columns:
#> # .composition inferred dyad composition
#> # .composition_role composition-specific member role
#> # .is_{comp-role} composition-role indicator columns
#> # .member_contrast_{comp}_arbitrary composition-specific member contrasts
#> # coded -1/+1 in arbitrary direction for
#> # exchangeability-constrained random
#> # effects. Values are 0 for other
#> # compositions
#> #
#> # A tibble: 720 × 11
#> personID coupleID gender closeness provided_support .composition
#> <int> <int> <fct> <dbl> <dbl> <fct>
#> 1 1 1 female 4.71 4.49 female_x_male
#> 2 2 1 male 4.61 4.76 female_x_male
#> 3 3 2 female 6.69 4.09 female_x_male
#> 4 4 2 male 5.98 6.20 female_x_male
#> 5 5 3 female 5.27 4.22 female_x_male
#> 6 6 3 male 4.37 5.03 female_x_male
#> 7 7 4 female 7.85 5.36 female_x_male
#> 8 8 4 male 5.42 5.25 female_x_male
#> 9 9 5 female 7.54 5.78 female_x_male
#> 10 10 5 male 5.19 4.98 female_x_male
#> # ℹ 710 more rows
#> # ℹ 5 more variables: .composition_role <fct>, .is_female_x_male_female <dbl>,
#> # .is_female_x_male_male <dbl>, .is_same_sex <dbl>,
#> # .member_contrast_same_sex_arbitrary <dbl>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)
#> # dyadMLM data
#> # Rows: 720 | Dyads: 360 | Intensive longitudinal: no
#> # Structure: dyad = coupleID, member = personID, role = gender
#> #
#> # Dyad compositions:
#> # female_x_female exchangeable 120 dyads
#> # pooled_exchangeable (pooled) exchangeable 240 dyads
#> # female_x_male
#> # male_x_male
#> #
#> # Added columns:
#> # .composition inferred dyad composition
#> # .composition_role composition-specific member role
#> # .is_{comp-role} composition-role indicator columns
#> # .member_contrast_{comp}_arbitrary composition-specific member contrasts
#> # coded -1/+1 in arbitrary direction for
#> # exchangeability-constrained random
#> # effects. Values are 0 for other
#> # compositions
#> #
#> # A tibble: 720 × 11
#> personID coupleID gender closeness provided_support .composition
#> <int> <int> <fct> <dbl> <dbl> <fct>
#> 1 1 1 female 4.71 4.49 pooled_exchangeable
#> 2 2 1 male 4.61 4.76 pooled_exchangeable
#> 3 3 2 female 6.69 4.09 pooled_exchangeable
#> 4 4 2 male 5.98 6.20 pooled_exchangeable
#> 5 5 3 female 5.27 4.22 pooled_exchangeable
#> 6 6 3 male 4.37 5.03 pooled_exchangeable
#> 7 7 4 female 7.85 5.36 pooled_exchangeable
#> 8 8 4 male 5.42 5.25 pooled_exchangeable
#> 9 9 5 female 7.54 5.78 pooled_exchangeable
#> 10 10 5 male 5.19 4.98 pooled_exchangeable
#> # ℹ 710 more rows
#> # ℹ 5 more variables: .composition_role <fct>, .is_female_x_female <dbl>,
#> # .is_pooled_exchangeable <dbl>,
#> # .member_contrast_female_x_female_arbitrary <dbl>,
#> # .member_contrast_pooled_exchangeable_arbitrary <dbl>If you use dyadMLM, please cite the version of the
package you use. Obtain the citation via:
citation("dyadMLM")
#> To cite package 'dyadMLM' in publications use:
#>
#> Küng P (2026). _dyadMLM: Tools for Dyadic Multilevel Models_.
#> doi:10.5281/zenodo.21481720
#> <https://doi.org/10.5281/zenodo.21481720>. R package version 0.2.0,
#> <https://pascal-kueng.github.io/dyadMLM/>.
#>
#> A BibTeX entry for LaTeX users is
#>
#> @Manual{,
#> title = {dyadMLM: Tools for Dyadic Multilevel Models},
#> author = {Pascal Küng},
#> year = {2026},
#> note = {R package version 0.2.0},
#> url = {https://pascal-kueng.github.io/dyadMLM/},
#> doi = {10.5281/zenodo.21481720},
#> }Continue with the Actor-Partner Interdependence Model (APIM) vignette.
Related model-specific vignettes:
or return to About this vignette.