Skip to content

Commit a69f76d

Browse files
committed
update with draft conclusion
Signed-off-by: Nathaniel <[email protected]>
1 parent 64799e9 commit a69f76d

File tree

3 files changed

+2142
-1117
lines changed

3 files changed

+2142
-1117
lines changed

examples/case_studies/CFA_SEM.ipynb

Lines changed: 2055 additions & 1109 deletions
Large diffs are not rendered by default.

examples/case_studies/CFA_SEM.myst.md

Lines changed: 81 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,7 @@ del idata
262262

263263
### Intermediate Cross-Loading Model
264264

265-
The idea of a measurment is maybe a little opaque when we only see models that fit well. Instead we want to briefly show how an in-apt measurement model gets reflected in the estimated parameters for the factor loadings. Here we specify a measurement model which attempts to couple the `se_social` and `sup_parents` indicators and bundle them into the same factor.
265+
The idea of a measurment model is maybe a little opaque when we only see models that fit well. Instead we want to briefly show how an in-apt measurement model gets reflected in the estimated parameters for the factor loadings. Here we specify a measurement model which attempts to couple the `se_social` and `sup_parents` indicators and bundle them into the same factor.
266266

267267
```{code-cell} ipython3
268268
coords = {
@@ -542,7 +542,7 @@ ax.set_title("Residuals between Model Implied and Sample Covariances", fontsize=
542542
But we can also do more contemporary Bayesian posterior predictive checks as we pull out the predictive posterior distribution for each of the observed metrics.
543543

544544
```{code-cell} ipython3
545-
make_ppc(idata_mm, 100, drivers=residuals_posterior_cov.columns, dims=(3, 5));
545+
make_ppc(idata_mm, 100, drivers=residuals_posterior_cov.columns, dims=(5, 3));
546546
```
547547

548548
### Model Analysis
@@ -671,7 +671,7 @@ This model introduces the specific claims of dependence and the question then be
671671

672672
### Model Complexity and Bayesian Sensitivity Analysis
673673

674-
These models are complicated, we're adding a bunch of new parameters and structure to the model. Each of the parameters is equipped with a prior that shapes the implications of the model specification. This is hugely expressive framework where we can encode a huge variety of dependencies and correlations With this freedom to structure of inferential model we need to be careful to assess the robustness of our inferences. As such we will here perform a quick sensitivity analysis to show how the central implications of this model vary under prior settings.
674+
These models are already complicated and now we're adding a bunch of new parameters and structure to the model. Each of the parameters is equipped with a prior that shapes the implications of the model specification. This is hugely expressive framework where we can encode a huge variety of dependencies and correlations With this freedom to structure of inferential model we need to be careful to assess the robustness of our inferences. As such we will here perform a quick sensitivity analysis to show how the central implications of this model vary under prior settings.
675675

676676

677677
```{code-cell} ipython3
@@ -833,13 +833,30 @@ model_sem2, idata_sem2 = make_indirect_sem(
833833
)
834834
```
835835

836-
The main structural feature to observe is that we've now added a bunch of regressions to our model such that some of the constructs that we took as given in the measurement model are now derived as a linear combination of others. Because we removed the correlation effect between `SE_SOCIAL` AND `SE_ACAD` we re-introduce the possibility of their correlation by adding correlated error terms to their regression equations.
836+
The main structural feature to observe is that we've now added a bunch of regressions to our model such that some of the constructs that we took as given in the measurement model are now derived as a linear combination of others. Because we removed the correlation effect between `SE_SOCIAL` AND `SE_ACAD` we re-introduce the possibility of their correlation by adding correlated error terms to their regression equations. In the `lavaan` syntax we're aiming for something like
837+
838+
```
839+
Measurement model
840+
SUP_Parents =~ sup_parents_p1 + sup_parents_p2 + sup_parents_p3
841+
SUP_Friends =~ sup_friends_p1 + sup_friends_p2 + sup_friends_p3
842+
SE_Academic =~ se_acad_p1 + se_acad_p2 + se_acad_p3
843+
SE_Social =~ se_social_p1 + se_social_p2 + se_social_p3
844+
LS =~ ls_p1 + ls_p2 + ls_p3
845+
846+
Regressions
847+
SE_Academic ~ SUP_Parents + SUP_Friends
848+
SE_Social ~ SUP_Parents + SUP_Friends
849+
LS ~ SE_Academic + SE_Social + SUP_Parents + SUP_Friends
850+
851+
Residual covariances
852+
SE_Academic ~~ SE_Social
853+
```
837854

838855
```{code-cell} ipython3
839856
pm.model_to_graphviz(model_sem0)
840857
```
841858

842-
Next we'll see how the parameter estimates change across our prior specifications for the model
859+
It's worth pausing to examine the nature of the dependencies sketched in this diagram. We can see here how we've replaced the simpler measurement model structure and added three regression functions that replace the draws from the multivariate normal $Ksi$. In other words we've expressed a dependency as a series of regressions all within the one model. Next we'll see how the parameter estimates change across our prior specifications for the model. Notice the relative stability of the factor loadings compared to the regression coefficients.
843860

844861
```{code-cell} ipython3
845862
fig, ax = plt.subplots(figsize=(15, 15))
@@ -866,18 +883,58 @@ ax = sns.heatmap(residuals_posterior_corr, annot=True, cmap="bwr", center=0, mas
866883
ax.set_title("Residuals between Model Implied and Sample Correlations", fontsize=25);
867884
```
868885

869-
But the posterior predictive checks still look reasonable.
886+
But the posterior predictive checks still look reasonable. Our focal quantity of life-satisfaction seems to be recovered well.
887+
888+
```{code-cell} ipython3
889+
make_ppc(idata_sem0, 100, drivers=drivers, dims=(5, 3))
890+
```
891+
892+
Model diagnostics show generally healthy looking trace plots with some divergences, but the effective sample sizea and r-hat measures are fine so we should be generally pretty happy that the model has converged to the posterior distribution well.
893+
894+
```{code-cell} ipython3
895+
az.plot_trace(
896+
idata_sem0,
897+
var_names=["lambdas1", "lambdas2", "lambdas3", "lambdas4", "lambdas5", "beta_r", "beta_r2"],
898+
);
899+
```
870900

871901
```{code-cell} ipython3
872-
make_ppc(idata_sem0, 100, drivers=drivers, dims=(3, 5))
902+
az.summary(
903+
idata_sem0,
904+
var_names=[
905+
"lambdas1",
906+
"lambdas2",
907+
"lambdas3",
908+
"lambdas4",
909+
"lambdas5",
910+
"beta_r",
911+
"beta_r2",
912+
"Psi",
913+
"tau",
914+
],
915+
)
873916
```
874917

875-
We can also continue to assess questions of direct and indirect effects that were obscure in the simpler measurement model.
918+
Similar diagnostic results hold for the other models. We now continue to assess questions of direct and indirect effects that were obscure in the simpler measurement model. By which I mean we trace out the total paths that influence life-satisfaction and assess the relative strength of impact due to parental and peer support.
876919

877920
+++
878921

879922
### Indirect and Direct Effects
880923

924+
We now turn the additional regression structures that we've encoded into the model graph. First we pull out the regression coefficients
925+
926+
```{code-cell} ipython3
927+
fig, axs = plt.subplots(1, 2, figsize=(20, 8))
928+
929+
az.plot_energy(idata_sem0, ax=axs[0])
930+
931+
az.plot_forest(idata_sem0, var_names=["beta_r", "beta_r2"], combined=True, ax=axs[1])
932+
axs[1].axvline(0, color="red", label="zero-effect")
933+
axs[1].legend();
934+
```
935+
936+
The coefficients indicate a smaller relative weight accorded to the effects of peer support than we see with parental support. This is borne out as we trace out the cumulative causal effects (direct and indirect) through our DAG or chain of regression coefficients.
937+
881938
```{code-cell} ipython3
882939
def calculate_effects(idata, var="SUP_P"):
883940
summary_df = az.summary(idata, var_names=["beta_r", "beta_r2"])
@@ -911,6 +968,8 @@ def calculate_effects(idata, var="SUP_P"):
911968
)
912969
```
913970

971+
Importantly we see here the effect of priors on the implied relationships. As we pull our priors closer to 0 the total effects of parental support is pulled downwards away from .5, while the peer support remains relatively stable ~.10. However it remains clear that the impact of parental support dwarfs the effects due to peer support.
972+
914973
```{code-cell} ipython3
915974
summary_p = pd.concat(
916975
[calculate_effects(idata_sem0), calculate_effects(idata_sem1), calculate_effects(idata_sem2)]
@@ -920,6 +979,8 @@ summary_p.index = ["SEM0", "SEM1", "SEM2"]
920979
summary_p
921980
```
922981

982+
The sensitivity of the estimated impact due to parental support varies strongly as a function of our prior on the variances. Here is a substantive example of the role of theory choice in model design. How strongly should believe that parental and peer effects have 0 effect on life-satisfaction? I'm inclined to believe we're too conservative if we try and shrink the effect toward zero and should prefer a less conservative model. However, the example here is not to dispute the issue, but demonstrate the importance of sensitivity checks.
983+
923984
```{code-cell} ipython3
924985
summary_f = pd.concat(
925986
[
@@ -935,6 +996,18 @@ summary_f
935996

936997
# Conclusion
937998

999+
We've just seen how we can go from thinking about the measurment of abstract psychometric constructs, through the evaluation of complex patterns of correlation and covariances among these latent constructs to evaluating hypothetical causal structures amongst the latent factors. This is a bit of whirlwind tour of psychometric models and the expressive power of SEM and CFA models, which we're ending by linking them to the realm of causal inference! This is not an accident, but rather evidence that causal concerns sit at the heart of most modeling endeavours. When we're interested in any kind of complex joint-distribution of variables, we're likely interested in the causal structure of the system - how are the realised values of some observed metrics dependent on or related to others? Importantly, we need to understand how these observations are realised without confusing simple correlation for cause through naive or confounded inference.
1000+
1001+
Mislevy and Levy highlight this connection by focusing on the role of De Finetti's theorem in the recovery of exchangeable through Bayesian inference. By De Finetti’s theorem a distribution of exchangeable sequence of variables be expressed as mixture of conditional independent variables.
1002+
1003+
$$ p(x_{1}....x_{m}) = \dfrac{p(X | \theta)p(\theta)}{p_{i}(X)} = \dfrac{p(x_{i}.....x_{n} | \text{Ksi}, \Psi, \tau, \Lambda, \beta)p(\text{Ksi}, \Psi, \tau, \Lambda, \beta) }{p(x_{i}.....x_{n})} $$
1004+
1005+
So if we specify the conditional distribution correctly, we recover the conditions that warrant inference with a well designed model. The mixture distribution is just the vector of parameters upon which we condition our model. This plays out nicely in SEM and CFA models because we explicitly structure the interaction of the system to reflect remove biasing dependence structure and license clean inferences.
1006+
1007+
> [C]onditional independence is not a grace of nature for which we must wait passively, but rather a psychological necessity which we satisfy by organising our knowledge in a specific way. An important tool in such an organisation is the identification of intermediate variables that induce conditional independence among observables; if such variables are not in our vocabulary, we create them. In medical diagnosis, for instance, when some symptoms directly influence one another, the medical profession invents a name for that interaction (e.g. “syndrome”, “complication”, “pathological state”) and treats it as a new auxiliary variable that induces conditional independence.” - Pearl quoted in {cite:t}`levy2020bayesian` p61
1008+
1009+
It's this deliberate and careful focus on the structure of conditionalisation that unites the seemingly disparate disciplines of psychometrics and causal inference.
1010+
9381011
+++
9391012

9401013
## Authors

examples/references.bib

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -491,6 +491,12 @@ @incollection{leroux2000estimation
491491
year = {2000},
492492
publisher = {Springer}
493493
}
494+
@book{levy2020bayesian,
495+
title = {Bayesian Psychometric Modeling},
496+
author = {Levy, Roy and Mislevy, Robert J},
497+
year = {2020},
498+
publisher = {CRC Press}
499+
}
494500
@article{lewandowski2009generating,
495501
title = {Generating random correlation matrices based on vines and extended onion method},
496502
author = {Lewandowski, Daniel and Kurowicka, Dorota and Joe, Harry},

0 commit comments

Comments
 (0)