生物医学网络科学Biomedical Network Science
Example08 / 10

个体内与个体间网络可以方向相反——多被试 VAR(1) 与 GVAR 的三种网络

所属专题
症状网络与网络精神病学
下载
Notebook · .py

模拟 100 名被试,每人 100 个时间点(模拟数据,仅用于演示方法)。个体内:上一时刻”压力”升高 使下一时刻”情绪低落”升高(时间效应 +0.3);同一时刻两者残差正相关(同期效应)。 个体间:平均压力高的人平均情绪低落反而低(例如这些人有更多社会支持;人为设定的负相关)。 依次估计:时间网络(对个体中心化的滞后值做回归)、同期网络(残差相关)、个体间网络(个人均值相关), 再看把所有观测直接合并算出的相关。 输出解读:三种网络回答不同的问题;直接合并的相关混合了个体内(正)与个体间(负)两种来源, 可能接近 0 甚至符号错误。这是 mlVAR/GVAR 要把三者分开估计的原因。

Output输出图

个体内与个体间网络可以方向相反——多被试 VAR(1) 与 GVAR 的三种网络:输出图 1

Output文字输出

时间网络(个体内,有向):
  压力(t−1) → 情绪低落(t):+0.32(真值 +0.30)
  情绪低落(t−1) → 压力(t):-0.00(真值 0)
同期网络(残差相关,两个变量时等于偏相关):+0.42(真值 +0.40)
个体间网络(个人均值相关):-0.69(设定 −0.70)
所有观测直接合并的相关:-0.04
注:真实 mlVAR 用多层模型给每人估计随机效应;此处共享同一时间效应,仅演示三种网络的区分。

Code代码

# 模拟 100 名被试,每人 100 个时间点(模拟数据,仅用于演示方法)。个体内:上一时刻"压力"升高
# 使下一时刻"情绪低落"升高(时间效应 +0.3);同一时刻两者残差正相关(同期效应)。
# 个体间:平均压力高的人平均情绪低落反而低(例如这些人有更多社会支持;人为设定的负相关)。
# 依次估计:时间网络(对个体中心化的滞后值做回归)、同期网络(残差相关)、个体间网络(个人均值相关),
# 再看把所有观测直接合并算出的相关。
# 输出解读:三种网络回答不同的问题;直接合并的相关混合了个体内(正)与个体间(负)两种来源,
# 可能接近 0 甚至符号错误。这是 mlVAR/GVAR 要把三者分开估计的原因。
import numpy as np

rng = np.random.default_rng(11)
N, T = 100, 100
A = np.array([[0.3, 0.0],        # 变量 0 = 压力,1 = 情绪低落;A[j, i] 为 i(t−1) → j(t)
              [0.3, 0.3]])
Sig_e = np.array([[1.0, 0.4], [0.4, 1.0]])
L = np.linalg.cholesky(Sig_e)
mu = rng.multivariate_normal([0, 0], [[1.0, -0.7], [-0.7, 1.0]], size=N)   # 个体均值:个体间负相关

data = []
for k in range(N):
    y = np.zeros((T + 50, 2))
    for t in range(1, T + 50):
        y[t] = A @ y[t - 1] + L @ rng.standard_normal(2)
    data.append(y[50:] + mu[k])
data = np.array(data)                       # N × T × 2

means = data.mean(axis=1)
Yc = data - means[:, None, :]               # 个体中心化(within-person centering)
Xlag = Yc[:, :-1, :].reshape(-1, 2)
Ynow = Yc[:, 1:, :].reshape(-1, 2)
coef, *_ = np.linalg.lstsq(Xlag, Ynow, rcond=None)
A_hat = coef.T
resid = Ynow - Xlag @ coef
r_contemp = np.corrcoef(resid, rowvar=False)[0, 1]
r_between = np.corrcoef(means, rowvar=False)[0, 1]
r_pooled = np.corrcoef(data.reshape(-1, 2), rowvar=False)[0, 1]

print("时间网络(个体内,有向):")
print(f"  压力(t−1) → 情绪低落(t):{A_hat[1, 0]:+.2f}(真值 +0.30)")
print(f"  情绪低落(t−1) → 压力(t):{A_hat[0, 1]:+.2f}(真值 0)")
print(f"同期网络(残差相关,两个变量时等于偏相关):{r_contemp:+.2f}(真值 +0.40)")
print(f"个体间网络(个人均值相关):{r_between:+.2f}(设定 −0.70)")
print(f"所有观测直接合并的相关:{r_pooled:+.2f}")
print("注:真实 mlVAR 用多层模型给每人估计随机效应;此处共享同一时间效应,仅演示三种网络的区分。")

import matplotlib.pyplot as plt
fig, axes = plt.subplots(1, 2, figsize=(10, 4))
x = np.arange(4)
axes[0].bar(x, [A_hat[1, 0], r_contemp, r_between, r_pooled], color=["#4477AA", "#4477AA", "#CC6677", "#BBBBBB"])
axes[0].scatter(x[:3], [0.3, 0.4, -0.7], marker="D", color="k", zorder=3, label="true / set value")
axes[0].axhline(0, color="k", lw=0.6)
axes[0].set_xticks(x, ["Temporal\nstress->mood", "Contemporaneous", "Between-\nperson", "Pooled r"], fontsize=8)
axes[0].set(ylabel="Estimate", title="Three networks answer different questions")
axes[0].legend(fontsize=8)
for k in range(0, N, 5):                    # 每 5 人取 1 人,画其个体内回归线(±1 SD 范围)
    xs, ys = data[k, :, 0], data[k, :, 1]
    xx = xs.mean() + np.array([-1, 1]) * xs.std()
    axes[1].plot(xx, ys.mean() + np.polyfit(xs, ys, 1)[0] * (xx - xs.mean()), color="#4477AA", lw=1.2)
axes[1].plot([], [], color="#4477AA", label="within-person fits (20 people)")
axes[1].scatter(means[:, 0], means[:, 1], s=20, color="k", marker="x", label="person means (all 100)")
xx = np.linspace(means[:, 0].min(), means[:, 0].max(), 2)
axes[1].plot(xx, np.polyval(np.polyfit(means[:, 0], means[:, 1], 1), xx), "--", color="#CC6677", lw=2,
             label="between-person fit")
axes[1].set(xlabel="Stress", ylabel="Low mood", title="Within-person slopes up; between-person slope down")
axes[1].legend(fontsize=8)
plt.tight_layout(); plt.show()

Run在浏览器中运行

首次加载 Python 环境约需 20–40 秒;可以修改参数后重新运行。

个体内与个体间网络可以方向相反——多被试 VAR(1) 与 GVAR 的三种网络