This vignette shows the bivariate workflow implemented in
dyadicMarkov. In the bivariate setting, two categorical
variables are observed repeatedly for the two members of a dyad. The
bivariate method follows the global-and-local procedure described in
Böllenrücher et al. (in press).
The bivariate method uses matrix codes to identify the local dependence patterns. Partial bivariate patterns are denoted B1–B3, while complete bivariate patterns are denoted C, D1–D4, and E1–E4. When the global step identifies a univariate case, the A-family codes described in the univariate workflow apply. The pattern nomenclature is summarized in Table 2 of Böllenrücher et al. (in press).
The current bivariate functions support states = 2. With
two binary variables observed for two members, the previous state is
described by four binary components. The empirical bivariate count
matrix therefore has 16 rows and 2 columns.
Although the data are synthetic, the four columns can be read like
real repeated observations from a dyad. For example, V1
could represent one coded behavior or response, and V2
could represent a second coded behavior or response observed at the same
measurement occasions. The columns FM_V1 and
SM_V1 then describe the two members on the main variable,
while FM_V2 and SM_V2 describe the same two
members on the second variable.
The 16 rows arise because the previous state combines four binary
lagged components: first member on V1, second member on
V1, first member on V2, and second member on
V2. With two possible states for each component, this gives
\(2^4 = 16\) previous-state
combinations. The 2 columns represent the possible next states of the
first member on the current main variable.
The example data set dyadic_bivariate_example contains
two categorical variables for the first member and the second member of
a dyad. Each row corresponds to one measurement occasion.
utils::data("dyadic_bivariate_example", package = "dyadicMarkov")
head(dyadic_bivariate_example)
#> time FM_V1 SM_V1 FM_V2 SM_V2
#> 1 1 2 1 1 2
#> 2 2 2 1 2 1
#> 3 3 2 2 2 1
#> 4 4 2 2 2 2
#> 5 5 2 2 1 2
#> 6 6 2 2 1 1
dim(dyadic_bivariate_example)
#> [1] 90 5The four chains are first-member and second-member sequences for the
main variable (V1) and the second variable
(V2).
The first step is to construct the empirical bivariate transition
count matrix with countEmpBivariate(). Rows represent the
16 possible previous-state combinations of the two dyadic variables.
Columns represent the next state of the first member on the main
variable.
emp_bi <- dyadicMarkov::countEmpBivariate(
chainFM_V1 = dyadic_bivariate_example$FM_V1,
chainSM_V1 = dyadic_bivariate_example$SM_V1,
chainFM_V2 = dyadic_bivariate_example$FM_V2,
chainSM_V2 = dyadic_bivariate_example$SM_V2,
states = 2L
)
emp_bi
#> next_1 next_2
#> mainFM1_mainSM1_secondFM1_secondSM1 7 0
#> mainFM1_mainSM1_secondFM1_secondSM2 0 2
#> mainFM1_mainSM1_secondFM2_secondSM1 0 0
#> mainFM1_mainSM1_secondFM2_secondSM2 1 0
#> mainFM1_mainSM2_secondFM1_secondSM1 0 1
#> mainFM1_mainSM2_secondFM1_secondSM2 0 1
#> mainFM1_mainSM2_secondFM2_secondSM1 2 0
#> mainFM1_mainSM2_secondFM2_secondSM2 0 2
#> mainFM2_mainSM1_secondFM1_secondSM1 0 0
#> mainFM2_mainSM1_secondFM1_secondSM2 2 1
#> mainFM2_mainSM1_secondFM2_secondSM1 1 1
#> mainFM2_mainSM1_secondFM2_secondSM2 0 3
#> mainFM2_mainSM2_secondFM1_secondSM1 1 1
#> mainFM2_mainSM2_secondFM1_secondSM2 1 4
#> mainFM2_mainSM2_secondFM2_secondSM1 1 5
#> mainFM2_mainSM2_secondFM2_secondSM2 0 52
class(emp_bi)
#> [1] "dyadic_counts" "matrix" "array"
dim(emp_bi)
#> [1] 16 2The function bivariateCase() performs the global step of
the bivariate method. The global approach compares nested models within
the likelihood-ratio test (LRT) framework. bivariateCase()
implements the two chi-squared tests for the A1 and B1 comparisons used
to identify the dependence case. dyadicMarkov evaluates
these tests using Pearson’s chi-squared statistic, \(X^2 = \sum (O-E)^2/E\), to classify the
analyzed sequence as a trivial, univariate, partial bivariate, or
complete bivariate case.
case_bi <- dyadicMarkov::bivariateCase(emp_bi, alpha = 0.05)
case_bi
#> Bivariate dyadic case
#> Case: complete
#> Alpha: 0.05
case_bi$case
#> [1] "complete"
summary(case_bi)
#> $case
#> [1] "complete"
#>
#> $alpha
#> [1] 0.05
#>
#> $call
#> dyadicMarkov::bivariateCase(empirical = emp_bi, alpha = 0.05)
#>
#> attr(,"class")
#> [1] "summary_dyadic_case" "list"This example is identified as a complete bivariate case. The appropriate local step is therefore to compare complete bivariate candidate patterns.
For a complete bivariate case, completePattern() first
computes the G-squared deviance, \(G^2 = 2\sum
O\log(O/E)\), for each complete bivariate candidate structure. It
then calculates \(AIC = G^2 + 2k\) and
returns the candidate with the smallest AIC.
complete_bi <- dyadicMarkov::completePattern(emp_bi)
complete_bi
#> Dyadic interaction pattern
#> Pattern: actor only on the main, actor-partner on the second (D2)
complete_bi$pattern
#> [1] "actor only on the main, actor-partner on the second (D2)"
complete_bi$aic
#> pattern matrix aic
#> 1 complete actor-partner (C) C 32.00000
#> 2 partner only on the main, actor-partner on the second (D1) D1 30.03720
#> 3 actor only on the main, actor-partner on the second (D2) D2 28.42735
#> 4 actor-partner on the main, partner only on the second (D3) D3 33.33973
#> 5 actor-partner on the main, actor only on the second (D4) D4 38.60730
#> 6 complete partner only (E1) E1 30.55374
#> 7 partner only on the main, actor only on the second (E2) E2 42.91748
#> 8 actor only on the main, partner only on the second (E3) E3 36.47261
#> 9 complete actor only (E4) E4 40.57170In this example, the selected complete bivariate pattern is
D2, labelled by the package as actor only on the main,
actor-partner on the second.
Each bivariate analysis is defined from a specific perspective. The sequence supplied as the first member is the sequence being analyzed, while the second member provides the partner sequence. Likewise, one variable is treated as the main variable and the other as the second variable. Swapping the two members therefore changes the member perspective of the analysis, while swapping the two variables changes which variable is treated as the main variable. To describe the dyad more completely, the workflow can be repeated for each combination of analyzed member and main variable. These are distinct analyses and may therefore lead to different global cases and local interaction patterns.
For compactness, the following vignette-local helper applies the
exported functions in sequence; analyze_bivariate() is not
part of the package API.
analyze_bivariate <- function(label, fm_v1, sm_v1, fm_v2, sm_v2) {
emp <- dyadicMarkov::countEmpBivariate(
chainFM_V1 = fm_v1,
chainSM_V1 = sm_v1,
chainFM_V2 = fm_v2,
chainSM_V2 = sm_v2,
states = 2L
)
case <- dyadicMarkov::bivariateCase(emp, alpha = 0.05)
cat("\n", label, "\n", sep = "")
print(case)
if (identical(case$case, "complete")) {
print(dyadicMarkov::completePattern(emp))
}
if (identical(case$case, "partial")) {
print(dyadicMarkov::partialPattern(emp))
}
if (identical(case$case, "univariate")) {
print(dyadicMarkov::univariatePattern(fm_v1, sm_v1, states = 2L, alpha = 0.05))
}
}
d <- dyadic_bivariate_example
analyze_bivariate(
"FM_V1 as analyzed sequence, V1 as main variable",
d$FM_V1, d$SM_V1, d$FM_V2, d$SM_V2
)
#>
#> FM_V1 as analyzed sequence, V1 as main variable
#> Bivariate dyadic case
#> Case: complete
#> Alpha: 0.05
#> Dyadic interaction pattern
#> Pattern: actor only on the main, actor-partner on the second (D2)
analyze_bivariate(
"SM_V1 as analyzed sequence, V1 as main variable",
d$SM_V1, d$FM_V1, d$SM_V2, d$FM_V2
)
#>
#> SM_V1 as analyzed sequence, V1 as main variable
#> Bivariate dyadic case
#> Case: complete
#> Alpha: 0.05
#> Dyadic interaction pattern
#> Pattern: actor-partner on the main, partner only on the second (D3)
analyze_bivariate(
"FM_V2 as analyzed sequence, V2 as main variable",
d$FM_V2, d$SM_V2, d$FM_V1, d$SM_V1
)
#>
#> FM_V2 as analyzed sequence, V2 as main variable
#> Bivariate dyadic case
#> Case: partial
#> Alpha: 0.05
#> Dyadic interaction pattern
#> Pattern: partial actor only (B2)
analyze_bivariate(
"SM_V2 as analyzed sequence, V2 as main variable",
d$SM_V2, d$FM_V2, d$SM_V1, d$FM_V1
)
#>
#> SM_V2 as analyzed sequence, V2 as main variable
#> Bivariate dyadic case
#> Case: univariate
#> Alpha: 0.05
#> Dyadic interaction pattern
#> Pattern: APM (A1)
#> Alpha: 0.05
#> States: 2For this example, analyzing the four sequences in turn illustrates
three branches of the procedure: complete bivariate cases when
FM_V1 and SM_V1 are analyzed, a partial
bivariate case for FM_V2, and a univariate case for
SM_V2. The partial branch is therefore demonstrated with
the same bivariate example data rather than with an artificial seeded
example.
The global and local steps should be read together while keeping
their statistics distinct. The global step compares nested models within
the LRT framework through two chi-squared tests evaluated using
Pearson’s chi-squared statistic, \(X^2\). The local partial and complete steps
use the G-squared deviance, \(G^2\), to
calculate candidate AIC values. If bivariateCase() returns
trivial, no subsequent local pattern is selected. If it
returns univariate, the bivariate workflow returns to
univariatePattern() using the first- and second-member
sequences of the current main variable. If it returns
partial, the local step is partialPattern().
If it returns complete, the local step is
completePattern().