ScooBDoob / mb_stats.py
ynuozhang
Upload ScooBDoob code without binary caches
31d1d63
Raw History Blame Contribute Delete
4.54 kB
import numpy as np, json
from scoobdoob.validation import msm_build as mb, tpt, bridge
from scoobdoob.validation import mb_ground_truth as gt
from scoobdoob.validation import mb_data as V
import make_mb_panels as MP
LAG, N, TL, ALPHA = MP.LAG_OPT, MP.N_OPT, MP.TICA_LAG, 1.5
CLUST_SEEDS = list(range(20))
PATH_SEEDS = [0, 1, 2]
NPATH = 2000
sad = gt.saddle_points()
S1 = sad[np.argmin(sad[:, 0])]
trajs = V.load_trajs(str(V.DEFAULT_DATA))
raw_m, fk_m, within = [], [], []
for cs in CLUST_SEEDS:
model = mb.build_full_msm(
trajs, trajs, lag=LAG, tica_lag=TL, k=V.K, n_comp=2, seed=cs, use_tica=True
)
A, B, _ = mb.q2_sign_endpoints(model)
start, end = V.orient_endpoints(model, A, B)
xy = model.state_xy
_, q, _ = tpt.committor_agreement(model, start, end)
rf = tpt.reactive_flux(model, start, end)
thru = np.asarray(rf.gross_flux).sum(1)
share = thru / thru.sum()
on = share > 0.5 / model.n_active
on[list(start)] = True
on[list(end)] = True
Axy = model.active_to_xy(start).mean(0)
Bxy = model.active_to_xy(end).mean(0)
land = np.vstack([Axy, Bxy, sad])
lo = land.min(0) - 0.35
hi = land.max(0) + 0.35
on = on & (
(xy[:, 0] >= lo[0])
& (xy[:, 0] <= hi[0])
& (xy[:, 1] >= lo[1])
& (xy[:, 1] <= hi[1])
)
labels = np.concatenate(model.dtrajs)
counts = np.bincount(labels, minlength=model.n_active)[: model.n_active].astype(
float
)
rho = np.maximum(counts, 1) / counts.mean()
react = (q > 0.05) & (q < 0.95)
wfk = np.exp(-LAG * ALPHA * np.maximum(rho, np.percentile(rho[react], 25)))
wfk[~on] = 0.0
wraw = np.ones_like(wfk)
wraw[~on] = 0.0
n1 = np.linalg.norm(xy - S1, axis=1) < 0.25
Kraw = bridge.doob_kernels(model.P, end, N, w=wraw)
Kfk = bridge.doob_kernels(model.P, end, N, w=wfk)
r_ps, f_ps = [], []
for psd in PATH_SEEDS:
pr = bridge.sample_bridge_paths(Kraw, start, n_paths=NPATH, seed=psd)
pf = bridge.sample_bridge_paths(Kfk, start, n_paths=NPATH, seed=psd)
r_ps.append(np.mean([any(n1[s] for s in p) for p in pr]) * 100)
f_ps.append(np.mean([any(n1[s] for s in p) for p in pf]) * 100)
raw_m.append(np.mean(r_ps))
fk_m.append(np.mean(f_ps))
within.append((np.std(r_ps), np.std(f_ps)))
print(
f" [clust seed {cs:2d}] raw {raw_m[-1]:5.1f}% fk {fk_m[-1]:5.1f}% "
f"diff {fk_m[-1] - raw_m[-1]:+5.1f} (path-seed sd {within[-1][0]:.1f}/{within[-1][1]:.1f})"
)
raw = np.array(raw_m)
fk = np.array(fk_m)
d = fk - raw
n = len(d)
print(
f"\n--- variance decomposition (n={n} clustering seeds, {len(PATH_SEEDS)} path seeds, "
f"{NPATH} paths each) ---"
)
wr = np.mean([w[0] for w in within])
wf = np.mean([w[1] for w in within])
print(f"between-clustering sd : raw {raw.std(ddof=1):.1f} fk {fk.std(ddof=1):.1f}")
print(f"within (path-sampling) sd : raw {wr:.1f} fk {wf:.1f}")
print(
f"-> clustering dominates by {fk.std(ddof=1) / max(wf, 1e-9):.0f}x; Monte-Carlo error is negligible"
)
print(f"\n--- paired comparison, FK vs raw ---")
print(f"raw {raw.mean():.1f} +- {raw.std(ddof=1):.1f}")
print(f"fk {fk.mean():.1f} +- {fk.std(ddof=1):.1f}")
se = d.std(ddof=1) / np.sqrt(n)
print(f"paired diff {d.mean():+.1f} (sd {d.std(ddof=1):.1f}, se {se:.1f})")
print(
f" min diff over seeds {d.min():+.1f}, max {d.max():+.1f} "
f"(sign consistent: {'yes' if (d > 0).all() else 'NO'})"
)
print(f"Cohen's d_z = {d.mean() / d.std(ddof=1):.2f}")
try:
from scipy import stats
t, pt = stats.ttest_rel(fk, raw)
w, pw = stats.wilcoxon(fk, raw)
ci = stats.t.interval(0.95, n - 1, loc=d.mean(), scale=se)
print(f"paired t: t={t:.1f}, p={pt:.2e}")
print(
f"Wilcoxon signed-rank: W={w:.0f}, p={pw:.2e} "
f"(floor for n={n} is {2 / 2**n:.1e})"
)
print(f"95% CI of the mean difference: [{ci[0]:.1f}, {ci[1]:.1f}]")
except ImportError:
print("scipy unavailable; bootstrap only")
rng = np.random.default_rng(0)
bs = np.array([rng.choice(d, n, replace=True).mean() for _ in range(20000)])
print(
f"bootstrap 95% CI of mean diff: [{np.percentile(bs, 2.5):.1f}, {np.percentile(bs, 97.5):.1f}]"
)
json.dump(
{
"raw": raw.tolist(),
"fk": fk.tolist(),
"clust_seeds": CLUST_SEEDS,
"path_seeds": PATH_SEEDS,
"n_paths": NPATH,
"tica_lag": TL,
"lag": LAG,
"N": N,
"alpha": ALPHA,
},
open("data/mb_stats.json", "w"),
indent=2,
)
print("[done]")