Introduction
In our previous module, we delved deep into the logic of counterfactuals, culminating in sensitivity analysis—a powerful technique to quantify how robust our causal claims are to unmeasured confounding. We've established a rigorous theoretical foundation for making and scrutinizing causal arguments. Now, we begin a new module, "Simulation, Estimation, and Synthesis," where we pivot from theory to application. Our first task is a critical step in any modern, complex study: building a virtual laboratory for our experiment.
This lesson addresses the learning outcome: Simulate triadic satisfaction data based on the pre-specified structural causal model and experimental protocol. We will construct a data-generating process that mirrors the complex, interdependent dynamics of the vee-triad. Creating this synthetic dataset serves several vital purposes. It allows us to:
- Test our analysis pipeline: Before we ever collect real data, we can check if our planned statistical models can accurately recover the "true" causal effects that we build into the simulation.
- Understand model behavior: We can explore how different assumptions in our causal model translate into observable data patterns.
- Ensure reproducibility: By setting a "seed" for our simulation, we create a fixed, shareable dataset that guarantees anyone can reproduce our tests and developmental work.
Given your background in stochastic processes and simulation, we can move beyond basic methods and explore sophisticated frameworks designed specifically for interdependent social systems. We will examine two powerful approaches for generating this data.
The Challenge: Simulating Interdependent Actors
The core difficulty in simulating our triadic system is that the three individuals are not independent observations. Their satisfaction levels are likely correlated due to shared experiences (the treatment condition, household events) and direct interpersonal influence. A simple simulation that draws three independent random variables would fail to capture the essence of the system. We need a model that explicitly generates this codependence.
Let's begin by reviewing the fundamental R functions for generating random data and the crucial practice of ensuring reproducibility.
This video from Roger Peng's "Computing for Data Analysis" course offers a concise introduction to R's simulation tools and the importance of reproducibility.
Please watch the first two segments. Focus on the basic functions for generating random variables, such as rnorm, and the family of d/p/q/r functions (probability distribution functions). Pay close attention to the explanation of set.seed() (setting the seed). This is a non-negotiable first step in any simulation to ensure your results are reproducible.
With these fundamentals in place, we can now explore two advanced frameworks for generating our triadic data.
1. The Latent Variable Approach
One intuitive way to model the interconnectedness of the triad is to assume there is a shared, unobserved latent state—call it "triadic harmony" or "system mood"—that simultaneously influences each member's satisfaction. Individual satisfaction is then a combination of this shared state, their own personal factors, and random noise. This is the core idea behind many structural equation models (SEMs) and factor models.
A formal specification for this, adapted from research on triadic synchronization, can be expressed as a factor model for time-series data.
[PDF] a triadic synchronization measure: ampc - KU Leuven
This paper, while focused on measuring triadic dynamics, contains an excellent section on how to simulate them using a latent variable model.
Please read the section titled "Data Generation" (pp. 15-16). Focus on the set of equations that define the data-generating process.
Let's break down the model presented in the paper and adapt it for our experiment. For our three individuals (let's call them A, B, and C), their satisfaction scores at each time point of the crossover experiment can be modeled as:
Here's how each component works:
- : The vector of observed satisfaction scores for each person at time .
- : The latent triadic state at time . This is the unobserved "harmony" that drives shared variance in satisfaction. It can itself be an autoregressive process, e.g., , capturing the idea that a good day is more likely to follow another good day.
- : A vector of factor loadings. These parameters are key. They determine how strongly each person's satisfaction is influenced by the shared latent state. You can use these to encode hypotheses, for instance, by setting the pivot's loading higher than the others.
- : The treatment variable at time (e.g., 0 for control, 1 for living together). The coefficient represents the direct causal effect of the treatment on satisfaction, which we assume for simplicity here is the same for all members.
- : A vector of individual-specific errors. These represent personal mood, unique daily events, and measurement error. This term can also incorporate autocorrelation () to model individual mood inertia, a crucial feature in a crossover design.
To simulate data from this model, you would set values for all parameters (s, , variances, autocorrelation coefficients ) and then iterate through time, generating values for and and combining them to produce the observed satisfaction scores .
2. The Actor-Oriented Modeling Approach
A second, more mechanistic paradigm is the Stochastic Actor-Oriented Model (SAOM). This approach, rooted in your field of stochastic processes, models the micro-level decisions of individuals over time. Instead of assuming a top-down latent factor, it simulates from the bottom up.
The core idea is that time unfolds continuously. At random intervals, an "actor" gets an opportunity to change their "behavior" (here, their satisfaction level). Their choice of whether and how to change is governed by an objective function, which they myopically seek to maximize. This should resonate with your work in decision theory and econometrics.
[PDF] Statistical Methods for Social Network Dynamics
This document by Tom Snijders is the foundational text on SAOMs. We will focus on how these models handle the co-evolution of networks and individual behaviors, which is directly analogous to our problem of modeling satisfaction dynamics within a fixed triad structure.
To understand the logic, please read two sections: Start with "Dynamics of networks and behavior" (pp. 95-99). This will introduce the core concept of co-evolution. Then, read the section that details the modeling framework, starting from "Actor-driven models" up to the diagram on page 111. This explains how actors control their behavior via objective functions.
In our context, the "network" is our fixed triad. We are interested in the evolution of the "behavior"—satisfaction (). The SAOM simulation proceeds in micro-steps:
- Rate Function (): Determines the frequency at which actor gets to make a change. This can be a constant or depend on covariates (e.g., individuals might be more volatile during the treatment period).
- Objective Function (): When actor gets a chance to change, they consider moving their satisfaction up or down by one step. The probability of making a specific change is a function of how much it increases their objective function.
A simple objective function for an actor 's satisfaction, , could be a linear combination of effects reflecting your causal graph:
- : A shape effect. These terms model the general tendency for satisfaction to be high or low, or to gravitate towards a central point (if is negative).
- : A social influence effect (homophily). A negative would mean actors prefer their satisfaction to be similar to their partners', driving synchronization.
- : A covariate effect, representing the influence of the treatment on the actor's satisfaction.
While powerful, implementing a full SAOM from scratch is complex. Fortunately, specialized R packages like RSiena exist for this. For our purposes, the key takeaway is the conceptual framework: modeling dynamics as a sequence of individual, utility-maximizing choices.
3. A Practical Path: Simulation with dagitty
Both frameworks above are powerful but can be complex to implement. For the purpose of testing a pre-specified analysis plan, a more direct approach is often sufficient. The dagitty package, which we've used for graph-based reasoning, provides a convenient function, simulateData, to generate data directly from a Structural Causal Model (SCM).
This function assumes a simple data-generating process, typically a linear structural equation model, where each variable is a linear function of its parents in the DAG plus some random noise.
Johannes Textor: Causal Inference using the R package DAGitty
This segment from a presentation by Johannes Textor, the creator of dagitty, explains and demonstrates the simulateData function.
Please watch the segment from "ability to simulate data". This will show you exactly how to take a DAG and generate a corresponding dataset.
Let's translate our triadic SCM into dagitty syntax and simulate some data. Our model includes:
- An experimental treatment
T(living arrangement). - A shared confounder
Stress(household financial stress). - Individual baseline traits for each person (A, B, C), e.g.,
Neuroticism. - A potential mediator
Autonomyfor each person. - The final outcome
Satisfactionfor each person.
The dagitty model would look something like this:
library(dagitty)
library(tidyverse) # For data manipulation and plotting
# Define the Structural Causal Model for the triad
triad_scm <- dagitty(
'dag {
# Nodes for each person A, B, C
Satisfaction_A [outcome]
Satisfaction_B [outcome]
Satisfaction_C [outcome]
Autonomy_A [mediator]
Autonomy_B [mediator]
Autonomy_C [mediator]
Neuroticism_A [exogenous]
Neuroticism_B [exogenous]
Neuroticism_C [exogenous]
# Treatment and Shared Confounder
T [exposure]
Stress [exogenous]
# Causal Paths
T -> Autonomy_A -> Satisfaction_A
T -> Autonomy_B -> Satisfaction_B
T -> Autonomy_C -> Satisfaction_C
T -> Satisfaction_A
T -> Satisfaction_B
T -> Satisfaction_C
Neuroticism_A -> Satisfaction_A
Neuroticism_B -> Satisfaction_B
Neuroticism_C -> Satisfaction_C
Stress -> Satisfaction_A
Stress -> Satisfaction_B
Stress -> Satisfaction_C
# Interference pathways (correlation due to shared latent factors)
# We model this with correlated errors between satisfaction outcomes
Satisfaction_A <-> Satisfaction_B
Satisfaction_B <-> Satisfaction_C
Satisfaction_A <-> Satisfaction_C
}'
)
# Set path coefficients (the true causal effects)
# We can make the treatment effect positive
path(triad_scm, "T", "Satisfaction_A") <- 0.5
path(triad_scm, "T", "Satisfaction_B") <- 0.5
path(triad_scm, "T", "Satisfaction_C") <- 0.5
# Make stress have a negative effect
path(triad_scm, "Stress", "Satisfaction_A") <- -0.3
path(triad_scm, "Stress", "Satisfaction_B") <- -0.3
path(triad_scm, "Stress", "Satisfaction_C") <- -0.3
# Set the strength of the unobserved confounding (correlated errors)
path(triad_scm, "Satisfaction_A", "Satisfaction_B") <- 0.4
path(triad_scm, "Satisfaction_B", "Satisfaction_C") <- 0.4
path(triad_scm, "Satisfaction_A", "Satisfaction_C") <- 0.4
# --- Simulation ---
# Ensure reproducibility
set.seed(12345)
# Generate 500 observations (e.g., 500 days of data)
sim_data <- simulateData(triad_scm, n = 500)
# View the first few rows
head(sim_data)
# Let's verify our simulation.
# The effect of T on Satisfaction_A should be around 0.5
# We run a simple linear model on the SIMULATED data
# This is a sneak peek of what we'll do in the next lesson!
model_check <- lm(Satisfaction_A ~ T + Stress + Neuroticism_A, data = sim_data)
summary(model_check)
When you run this code, the summary(model_check) output will show a coefficient for T that is close to the 0.5 we specified. This confirms that the simulation is working as expected and that a correctly specified regression model can recover the true effect. The bi-directed edges A <-> B in the dagitty code are crucial; they represent unmeasured common causes or other dependencies, which simulateData implements as correlated error terms, thus generating the required codependence between the satisfaction scores.
Conclusion
In this lesson, we have laid the groundwork for the practical phase of our project. You have learned why simulation is an indispensable tool for complex study designs and have explored two sophisticated theoretical frameworks—Latent Variable Models and Actor-Oriented Models—for generating data from interdependent systems. Most importantly, you now have a practical method using dagitty to create a synthetic dataset that faithfully represents your pre-specified structural causal model.
Key Takeaways:
- Simulation is a "dress rehearsal" that allows you to test your analysis plan on data with known properties.
set.seed()is mandatory for ensuring the reproducibility of any simulation work.- Interdependent data, like in your triad, can be modeled using latent variables (an SEM approach) or through mechanistic micro-simulations (an SAOM approach).
- The
dagittypackage provides a pragmatic tool,simulateData, to generate data directly from a DAG, allowing you to specify true causal effects and correlation structures.
In our next lesson, we will take the dataset we've just learned to simulate and put it to use. We will apply the analysis plan you developed and pre-registered, attempting to recover the known causal parameters we built into the model. This will be the ultimate test of whether our analytical strategy is sound.