Latent Social Relations Model

Path Diagram

alt latent.srm.xxmModel

xxM Model Matrices

Level-1 A(B): Within matrices

Residual Covariance Matrix

The resudual covariance matrix \( (2 \times 2) \) at level-1, \( (\Theta_{1,1}) \) is .

\[ \Theta^{1,1}= \begin{bmatrix} \psi_{1,1}^{1,1} & \\ \psi_{2,1}^{1,1} & \psi_{2,2}^{1,1} \end{bmatrix} \]

Corresponding intercept vector is:

\[ \nu^1 = \begin{bmatrix} \nu^1_1 & \\ \nu^1_2 \end{bmatrix} \]

Level-2 B(A): Within matrices

A(B) and B(A) include reciprocal exchangable ratings of members of the same dyad. Hence, the within-level parameters are constrained to be equal.

Residual Covariance Matrix

Residual covariance matrix at level-2 \( (\Theta_{2,2}) \) is contrained to be equal to level-1 residual covariance.

\[ \Theta^{2,2}= \begin{bmatrix} \theta_{1,1}^{2,2} & \\ \theta_{2,1}^{2,2} & \theta_{2,2}^{2,2} \end{bmatrix} = \begin{bmatrix} \theta_{1,1}^{1,1} & \\ \theta_{2,1}^{1,1} & \theta_{2,2}^{1,1} \end{bmatrix} \]

Similarly, intercepts are also constrained across the two levels.

\[ \nu^2 = \begin{bmatrix} \nu^2_1 & \\ \nu^2_2 \end{bmatrix} = \begin{bmatrix} \nu^1_1 & \\ \nu^1_2 \end{bmatrix} \]

Level-3 (Target): Within Matrices

At level-3, we have a single latent variable influencing both \( y_1 \) and \( y_2 \). There is a single parameter matrix, latent factor covariance matrix at the target level.

Latent Factor Covariance Matrix

The latent covariance matrix for target has a single element matrix fixed to 1.0:

\[ \Psi^{3,3}= \begin{bmatrix} 1.0 \end{bmatrix} \]

Level-4 (Rater): Within Matrices

Similarly, at level-4, there is a single latent variable: Rater effect.

Latent Factor Covariance Matrix

The latent covariance matrix for target has a single element matrix fixed to 1.0:

\[ \Psi^{4,4}= \begin{bmatrix} 1.0 \end{bmatrix} \]

Across level matrices:

Across-level factor-loading matrices

There are four factor-loading matrices:

  1. Target to A(B)
  2. Target to B(A)
  3. Rater to A(B)
  4. Rater to B(A)

All four matrices are freely estiamted. However, the matrices for target and rater effects are constrained to be equal:

  1. Target effect on A(B) is constrained to be equal to Target effect on B(A): \( \Lambda^{1,3}=\Lambda^{2,3} \)
\[ \begin{bmatrix} \lambda_{1,1}^{1,3} \\ \lambda_{2,1}^{1,3} \end{bmatrix} = \begin{bmatrix} \lambda_{1,1}^{2,3} \\ \lambda_{2,1}^{2,3} \end{bmatrix} \]
  1. Rater effect on A(B) is constrained to be equal to Target effect on B(A): \( \Lambda^{1,4}=\Lambda^{1,4} \)
\[ \begin{bmatrix} \lambda_{1,1}^{1,4} \\ \lambda_{2,1}^{1,4} \end{bmatrix} = \begin{bmatrix} \lambda_{1,1}^{2,4} \\ \lambda_{2,1}^{2,4} \end{bmatrix} \]

Across-level dyadic-covariances

Residuals of levels A(B) and B(A) covary across levels:

\[ \Theta^{1,2}= \begin{bmatrix} \theta_{1,1}^{1,2} & \theta_{1,2}^{1,2}\\ \theta_{2,1}^{1,2} & \theta_{2,2}^{1,2} \end{bmatrix} \]

However, across-level, across-variable residual-covariances are constrained to equality, \( \theta_{1,2}^{1,2} = \theta_{2,1}^{1,2} \).

Across-level Target-rater covariances

Target and Rater level latent variables are allowed to covary:

\[ \Psi^{3,4}= \begin{bmatrix} \psi_{1,1}^{3,4} \end{bmatrix} \]

Code Listing

xxM

Load xxM

xxM library needs to be loaded first.

library(xxm)

Prepare R datasets

SRM model has four real levels:

  1. a(b)
  2. a(b)
  3. target
  4. rater

and two virtual levels:

  1. dyad
  2. person

xxM requires separate datasets for six levels:

  1. a(b)
  2. a(b)
  3. target
  4. rater
  5. dyad
  6. person

Structure of each of these datasets is described below. Note:

  1. Observations within levels A(B) and B(A) with a common ID represent reciprocal ratings within a dyad.
  2. Observations for levels Target and Rater with a common ID represent the same person playing two different roles.
attach("nlsem.srm.xxm.RData")
## The following objects are masked from file:C://Paras//Projects//WAF//xxm/all//srm.xxm.RData:
## 
##     A_B, B_A, dyad, person, rater, target

A(B) includes rater B's ratings of target A and includes following columns:

str(A_B)
## 'data.frame':    209 obs. of  5 variables:
##  $ a_b   : int  2030202 2040202 2040203 2060201 2060202 2070202 2070203 2070204 2080205 2110205 ...
##  $ target: int  202 202 203 201 202 202 203 204 205 205 ...
##  $ rater : int  203 204 204 206 206 207 207 207 208 211 ...
##  $ like  : num  7 9 4 9 2 9 9 9 7 7 ...
##  $ warm  : num  9 7 3 7 2 9 8 9 8 7 ...

B(A) includes rater A's ratings of target B and includes following columns:

str(B_A)
## 'data.frame':    256 obs. of  5 variables:
##  $ b_a   : int  2030202 2040202 2040203 2060202 2060204 2070202 2080205 2100203 2100206 2110205 ...
##  $ target: int  203 204 204 206 206 207 208 210 210 211 ...
##  $ rater : int  202 202 203 202 204 202 205 203 206 205 ...
##  $ like  : num  7 8 8 1 1 8 8 4 1 7 ...
##  $ warm  : num  8 9 4 3 1 8 4 2 1 3 ...

target dataset includes a single column:

str(target)
## 'data.frame':    164 obs. of  1 variable:
##  $ target: int  201 202 203 204 205 206 207 208 209 210 ...

rater dataset includes a single column:

str(rater)
## 'data.frame':    114 obs. of  1 variable:
##  $ rater: int  202 203 204 205 206 207 208 211 213 214 ...

dyad dataset includes a single column:

str(dyad)
## 'data.frame':    383 obs. of  1 variable:
##  $ dyad: int  2030202 2040202 2040203 2060201 2060202 2060204 2070202 2070203 2070204 2080205 ...

person dataset includes a single column:

str(person)
## 'data.frame':    172 obs. of  1 variable:
##  $ person: int  201 202 203 204 205 206 207 208 209 210 ...

Construct R-matrices

For each parameter matrix, construct three related matrices:

  1. pattern matrix: A matrix indicating free or fixed parameters.
  2. value matrix: with start or fixed values for corresponding parameters.
  3. label matrix: with user friendly label for each parameter. label matrix is optional and used for imposing equality constraints. In this case, equality constraints are imposed on residual-covariance and intercepts for A(B) and B(A). Parameters with the same label are constrained to be equal.
# A(B) and B(A) Within matrices: Observed residual-covariance
theta_wn_pat <- matrix(1, 2, 2)
theta_wn_val <- matrix(c(2, 0, 0, 2), 2, 2)
theta_wn_lab <- matrix(c("like_like", "like_warm", "like_warm", "warm_warm"), 
    2, 2)
# A(B) and B(A) Within matrices: Observed intercepts
nu_pat <- matrix(1, 2, 1)
nu_val <- matrix(6, 2, 1)
nu_lab <- matrix(c("like_mean", "warm_mean"), 2, 1)
# Note: The use of common labels for nu (nu_lab) and theta (theta_wn_lab)
# for A(B) and B(A) imposes equality constraints on corresponding parameter
# estimates.

# Note: Latent factor variances for Target is fixed to 1.0 to define the
# scale of Target-Agree Level 3: Target
target_psi_pat <- diag(0, 1)
target_psi_val <- diag(1, 1)
# Note: Latent factor variances for Rater is fixed to 1.0 to define the
# scale of Rater-Agree Level 4: Rater
rater_psi_pat <- diag(0, 1)
rater_psi_val <- diag(1, 1)
###### Across-level matrices ###### Dyadic correlation (A_B with B_A)
theta_bw_pat <- matrix(1, 2, 2)
theta_bw_val <- matrix(0, 2, 2)
theta_bw_lab <- matrix(c("like1_like2", "like1_warm2", "like1_warm2", "warm1_warm2"))
# Note: The use of common labels like1_warm2 imposes equality constraints on
# across-level [A(B) and B(A)] covariance between `like` and `warm`.
# Generalized rater-target correlation
rater_target_psi_pat <- matrix(1, 1, 1)
rater_target_psi_val <- matrix(0, 1, 1)
# Rater -> Rating link matrices
rater_ly_pat <- matrix(1, 2, 1)
rater_ly_val <- matrix(0.1, 2, 1)
rater_ly_lab <- c("like_rater-agree", "warm_rater-agree")
# Target -> Rating link matrices:
target_ly_pat <- matrix(1, 2, 1)
target_ly_val <- matrix(0.1, 2, 1)
target_ly_lab <- c("like_target-agree", "warm_target-agree")

Construct model

xxmModel() is used to declare level names. The function returns a model object that is passed as a parameter to subsequent statements. Variable name for the return value can be anything.

zz <- xxmModel(c("a_b", "b_a", "target", "rater"))
## A new model was created.

For SRM, only real levels have observed and/or latent variables. Only real levels need to be declared using the xxmModel command. Virtual levels are declared in a separate command.

In this case, we have four real levels:

  1. a_b
  2. b_a
  3. rater
  4. target

Note that the two levels with observed dependent variables come before the levels with latent independnet variables.

Define virtual levels and add virtual data

For each vitual level we need three pieces of information.

  1. Name of the virtual level
  2. List of real levels that are instances of the virtual level
  3. Dataset for the virtual level with a column of IDs.

There are two commands that together accomplish these goals:

Virtual levels and role models xxmVirtuals()

xxmVirtuals() informs our model that there are virtual levels and binds each virtual level with the corresponding set of real levels. The function has two parameters.

  1. model is the first parameter is the model for which we want to define virtual levels.
  2. alias is a named list with as many elements as the number of virtual levels. The name of each element is the name of the virtual level. For each virtual level, a list of corresponding real levels is provided. In this case, there are two virtual levels:

    1. person with corresponding real levels: rater and target
    2. dyad with corresponding real levels: b_a and a_b

Virtual data: xxmVirtualIds()

xxmVirtualIds() adds data for a virtual level with a single column of IDs to our model. In this case, person and dyad datasets are added to our model.

alias = list(person = c("target", "rater"), dyad = c("a_b", "b_a"))
zz <- xxmVirtuals(zz, alias)
## Creating virtual `person` with 2 aliases
## Creating virtual `dyad` with 2 aliases
## Aliases created
zz <- xxmVirtualids(zz, person)
## Virtual level `person` was created
zz <- xxmVirtualids(zz, dyad)
## Virtual level `dyad` was created

Add submodels

For each declared level xxmSubmodel() is invoked to add corresponding submodel to the model object. The function adds three types of information to the model object:

In this case, a submodel is declared for each of the four real levels. Note, virtual levels do not need a submodel! Their sole purpose is to bind real levels so that we can include across-level covariances.

# Level 1: A(B)
zz <- xxmSubmodel(model = zz, level = "a_b", parents = c("target", "rater"), 
    ys = c("like", "warm"), xs = , etas = , data = A_B, )
## Creating role model `a_b` for virtual `dyad`
## Submodel for level `a_b` was created.
# Level 1: B(A)
zz <- xxmSubmodel(model = zz, level = "b_a", parents = c("target", "rater"), 
    ys = c("like", "warm"), xs = , etas = , data = B_A, )
## Creating role model `b_a` for virtual `dyad`
## Submodel for level `b_a` was created.
# Level 3: Target
zz <- xxmSubmodel(model = zz, level = "target", parents = , ys = , xs = , etas = c("target_agree"), 
    data = target, )
## Creating role model `target` for virtual `person`
## Submodel for level `target` was created.
# Level 3: Rater
zz <- xxmSubmodel(model = zz, level = "rater", parents = , ys = , xs = , etas = c("rater_agree"), 
    data = rater, )
## Creating role model `rater` for virtual `person`
## Submodel for level `rater` was created.

## @ knitr xxmWithinMatrix Level 1: A_B: Intercepts
zz <- xxmWithinMatrix(model = zz, level = "a_b", type = "nu", pattern = nu_pat, 
    value = nu_val, label = nu_lab, name = )
## 
## 'nu' matrix does not exist and will be added.
##  Added `nu` matrix.
# Level 1: A_B: Residual-covariance
zz <- xxmWithinMatrix(model = zz, level = "a_b", "theta", pattern = theta_wn_pat, 
    value = theta_wn_val, label = theta_wn_lab, )
## 
## 'theta' matrix does not exist and will be added.
##  Added `theta` matrix.
# Level 2: B_A: Intercepts
zz <- xxmWithinMatrix(model = zz, level = "b_a", type = "nu", pattern = nu_pat, 
    value = nu_val, label = nu_lab, )
## 
## 'nu' matrix does not exist and will be added.
##  Added `nu` matrix.
# Level 2: B_A: Residual-covariance
zz <- xxmWithinMatrix(model = zz, level = "b_a", type = "theta", pattern = theta_wn_pat, 
    value = theta_wn_val, label = theta_wn_lab, )
## 
## 'theta' matrix does not exist and will be added.
##  Added `theta` matrix.
# Level 3: Target: Latent covariance
zz <- xxmWithinMatrix(model = zz, level = "target", type = "psi", pattern = target_psi_pat, 
    value = target_psi_val, , )
## 
## 'psi' matrix does not exist and will be added.
##  Added `psi` matrix.
# Level 4: Rater: Latent covariance
zz <- xxmWithinMatrix(model = zz, level = "rater", type = "psi", pattern = rater_psi_pat, 
    value = rater_psi_val, , )
## 
## 'psi' matrix does not exist and will be added.
##  Added `psi` matrix.

## @ knitr xxmBetweenMatrix A_B - B_A residual-covariance
zz <- xxmBetweenMatrix(model = zz, parent = "b_a", child = "a_b", type = "theta", 
    pattern = theta_bw_pat, value = theta_bw_val, label = theta_bw_lab, )
## 
## 'theta' matrix does not exist and will be added.
##  Added `theta` matrix.
## Target-Rater Latent covariance
zz <- xxmBetweenMatrix(model = zz, parent = "rater", child = "target", type = "psi", 
    pattern = rater_target_psi_pat, value = rater_target_psi_val, , )
## 
## 'psi' matrix does not exist and will be added.
##  Added `psi` matrix.
## Rater -> A_B factor-loading matrix
zz <- xxmBetweenMatrix(model = zz, parent = "rater", child = "a_b", type = "lambda", 
    pattern = rater_ly_pat, value = rater_ly_val, label = rater_ly_lab)
## 
## 'lambda' matrix does not exist and will be added.
##  Added `lambda` matrix.
## Rater -> B_A factor-loading matrix
zz <- xxmBetweenMatrix(model = zz, parent = "rater", child = "b_a", type = "lambda", 
    pattern = rater_ly_pat, value = rater_ly_val, label = rater_ly_lab)
## 
## 'lambda' matrix does not exist and will be added.
##  Added `lambda` matrix.
## Target -> A_B factor-loading matrix
zz <- xxmBetweenMatrix(model = zz, parent = "target", child = "a_b", type = "lambda", 
    pattern = target_ly_pat, value = target_ly_val, label = target_ly_lab)
## 
## 'lambda' matrix does not exist and will be added.
##  Added `lambda` matrix.
## Target -> B_A factor-loading matrix
zz <- xxmBetweenMatrix(model = zz, parent = "target", child = "b_a", type = "lambda", 
    pattern = target_ly_pat, value = target_ly_val, label = target_ly_lab)
## 
## 'lambda' matrix does not exist and will be added.
##  Added `lambda` matrix.

Add within-level matrices

For each declared level xxmWithinMatrix() is used to add within-level parameter matrices. For each parameter matrix, the function adds the three matrices constructed earlier:

Add across-level matrices

Pairs of levels that share parent-child relationship have regression relationships. xxmBetweenMatrix() is used to add corresponding rergession matrices connecting the two levels.

For each parameter matrix, the function adds the three matrices constructed earlier:

Estimate model parameters

Estimation process is initiated by xxmRun(). If all goes well, a q&d summary of the results is printed.

zz <- xxmRun(zz)
## ------------------------------------------------------------------------------
## Estimating model parameters
## ------------------------------------------------------------------------------
##                4019.3977989295 
##                3988.9023248341 
## 
## 1010
##                3970.2507786867 
##                3958.2185837204 
##                3955.4636492817 
##                3949.3531090161 
##                3941.3090383276 
##                3907.8485191342 
##                3837.3588108308 
##                3802.7970408310 
##                3778.6934137156 
##                3767.6160091283 
##                3761.6428729863 
##                3744.9196855910 
##                3738.1431586419 
##                3732.6366955489 
##                3728.3743011442 
##                3732.4303786983 
##                3729.2450818405 
##                3729.2728768440 
##                3728.5216127310 
##                3728.4995717709 
##                3728.4815946827 
##                3728.4771698432 
##                3728.4758427053 
##                3728.4759427372 
##                3728.4759200660 
##                3728.4759089697 
##                3728.4759104052 
##                3728.4759176314 
##                3728.4759176196 
## Model converged normally
## nParms: 13
## ------------------------------------------------------------------------------
## *
##  1:                                     like_like ::      2.716 [     0.000,      0.000]
## 
##  2:                                     like_warm ::      0.654 [     0.000,      0.000]
## 
##  3:                                     warm_warm ::      3.468 [     0.000,      0.000]
## 
##  4:                                     like_mean ::      6.692 [     0.000,      0.000]
## 
##  5:                                     warm_mean ::      5.684 [     0.000,      0.000]
## 
##  6:                                   like1_like2 ::      1.136 [     0.000,      0.000]
## 
##  7:                                   like1_warm2 ::      0.649 [     0.000,      0.000]
## 
##  8:                                   warm1_warm2 ::      0.672 [     0.000,      0.000]
## 
##  9:                             like_target-agree ::      0.641 [     0.000,      0.000]
## 
## 10:                             warm_target-agree ::      0.980 [     0.000,      0.000]
## 
## 11:                              like_rater-agree ::      0.863 [     0.000,      0.000]
## 
## 12:                              warm_rater-agree ::      0.498 [     0.000,      0.000]
## 
## 13:                          target_rater_psi_1_1 ::      0.750 [     0.000,      0.000]
## 
## ------------------------------------------------------------------------------

Estimate profile-likelihood confidence intervals

Once parameters are estimated, confidence intervals are estimated by invoking xxmCI(). Depending on the the number of observations and the complexity of the model, xxmCI() may take a long time to compute. xxmCI() also prints a summary of parameter estimates and CIS.

zz <- xxmCI(zz)

View results

A summary of results may be retrived as an R list by a call to xxmSummary(). The returned list has two elements:

  1. fit is a list with five elements:
  2. estimates is a single table of free parameter estimates All xxM parameters have superscripts {child, parent} and subscripts {to, from}. xxM adds a descriptive parameter label if one is not already provided by the user.
latent.srm.results <- xxmSummary(zz)
latent.srm.results
## $fit
## $fit$deviance
## [1] 3728
## 
## $fit$nParameters
## [1] 13
## 
## $fit$nObservations
## [1] 907
## 
## $fit$aic
## [1] 3754
## 
## $fit$bic
## [1] 3817
## 
## 
## $estimates
##     child parent           to         from                label estimate
## 1     a_b    a_b         like         like            like_like   2.7158
## 2     a_b    a_b         like         warm            like_warm   0.6543
## 3     a_b    a_b         warm         warm            warm_warm   3.4681
## 4     a_b    a_b         like          One            like_mean   6.6915
## 5     a_b    a_b         warm          One            warm_mean   5.6835
## 6     a_b    b_a         like         like          like1_like2   1.1358
## 7     a_b    b_a         warm         like          like1_warm2   0.6493
## 8     a_b    b_a         like         warm          like1_warm2   0.6493
## 9     a_b    b_a         warm         warm          warm1_warm2   0.6721
## 10    b_a    b_a         like         like            like_like   2.7158
## 11    b_a    b_a         like         warm            like_warm   0.6543
## 12    b_a    b_a         warm         warm            warm_warm   3.4681
## 13    b_a    b_a         like          One            like_mean   6.6915
## 14    b_a    b_a         warm          One            warm_mean   5.6835
## 15    a_b target         like target_agree    like_target-agree   0.6406
## 16    a_b target         warm target_agree    warm_target-agree   0.9800
## 17    b_a target         like target_agree    like_target-agree   0.6406
## 18    b_a target         warm target_agree    warm_target-agree   0.9800
## 20    a_b  rater         like  rater_agree     like_rater-agree   0.8635
## 21    a_b  rater         warm  rater_agree     warm_rater-agree   0.4982
## 22    b_a  rater         like  rater_agree     like_rater-agree   0.8635
## 23    b_a  rater         warm  rater_agree     warm_rater-agree   0.4982
## 24 target  rater target_agree  rater_agree target_rater_psi_1_1   0.7503
##         low   high
## 1   2.29002 3.2342
## 2   0.28152 1.0906
## 3   2.92579 4.1188
## 4   6.40223 6.9763
## 5   5.39336 5.9709
## 6   0.47440 1.7666
## 7   0.01461 1.2454
## 8   0.01461 1.2454
## 9  -0.44640 1.7076
## 10  2.29002 3.2342
## 11  0.28152 1.0906
## 12  2.92579 4.1188
## 13  6.40223 6.9763
## 14  5.39336 5.9709
## 15  0.41414 0.8688
## 16  0.71933 1.2462
## 17  0.41414 0.8688
## 18  0.71933 1.2462
## 20  0.63464 1.1055
## 21  0.18171 0.7970
## 22  0.63464 1.1055
## 23  0.18171 0.7970
## 24  0.37691 1.0000

Free model object

xxM model object may hog a significant amount of RAM outside of R's workspace. This memory will automatically be released, when the workspace is cleared by a call to rm(list=ls()) or at the end of the R session. Alternatively, it is recommended that xxmFree() may be called to release the memory.

zz <- xxmFree(zz)
rm(list = ls())

alt latent.srm.results