Buckets:

redmingwei's picture
download
raw
3.81 kB
#!/usr/bin/env python3
"""exp63c — 单格 τ 的零模型重抽稳定性。
同一批单元、同一估计量,只换零模型的随机移位 -> τ 能变多少?
这是判定「单格 τ 是否可复现」的直接证据。
用法: python exp63c_repeat.py [n_cells] [n_rep]
"""
from __future__ import annotations
import json
import sys
import time
import numpy as np
import pandas as pd
import exp63_region_tau as E
N_CELLS = int(sys.argv[1]) if len(sys.argv) > 1 else 40
N_REP = int(sys.argv[2]) if len(sys.argv) > 2 else 4
def main():
t0 = time.time()
d = pd.read_csv(E.OUT / "per_cell.csv")
k = d[d.kept == True]
# 每个 session 最多取 2 格,避免被大 session 主导
sel = k.groupby("session", group_keys=False).head(2).head(N_CELLS)
print(f"cells={len(sel)} reps={N_REP} sessions={sel.session.nunique()}", flush=True)
u = pd.read_parquet(E.SEG / "units.parquet")
rows = []
for sid, g in sel.groupby("session"):
f = E.SEG / f"spikes_session_{int(sid):03d}.npz"
raw = np.load(f)["spikes"]
x = (np.round(raw * 8).T).astype(np.float32)
del raw
nb, nu = x.shape
ml = min(E.MAX_LAG, nb - 2)
sub = u[u.session == sid].sort_values("unit_idx")
for _, c in g.iterrows():
idx = sub[sub.region == c.region].unit_idx.to_numpy()
taus, snrs = [], []
for rep in range(N_REP):
rng = np.random.default_rng(1000 + rep)
rho, noise, snr, usable, shared = E.estimate_session(x, idx, ml, rng)
rec = {"snr": snr, "kept": False}
if snr >= E.SNR_MIN and len(usable) >= E.MIN_POINTS:
rec = E.add_fits(rec, rho, usable)
taus.append(float(rec["tau_ms"]) if rec.get("kept") else np.nan)
snrs.append(float(snr))
rows.append({"session": int(sid), "region": c.region,
"n_units": int(len(idx)),
"tau_orig": float(c.tau_ms),
**{f"tau_r{j}": taus[j] for j in range(N_REP)},
"snr_min": float(np.min(snrs))})
print(f" sess{int(sid):03d} done rows={len(rows)} [{time.time()-t0:.0f}s]", flush=True)
del x
out = pd.DataFrame(rows)
out.to_csv(E.OUT / "repeatability.csv", index=False)
tau_cols = [f"tau_r{j}" for j in range(N_REP)]
ok = out.dropna(subset=tau_cols)
print(f"\nwrote repeatability.csv rows={len(out)} 全 {N_REP} 次都成功的格={len(ok)}")
if len(ok):
vals = ok[tau_cols].to_numpy(float)
ratio = vals.max(axis=1) / vals.min(axis=1)
print(f"同一格跨 {N_REP} 次零模型抽样的 τ max/min 比值:")
print(f" median={np.median(ratio):.2f}× p75={np.quantile(ratio,.75):.2f}× "
f"p90={np.quantile(ratio,.9):.2f}× max={ratio.max():.2f}×")
print(f" 比值 > 2× 的格: {int((ratio>2).sum())}/{len(ratio)} "
f"({100*(ratio>2).mean():.0f}%)")
print(f" 比值 > 5× 的格: {int((ratio>5).sum())}/{len(ratio)}")
# 相对离散度
print(f" log τ 跨重复的 SD(格内)median="
f"{np.median(np.log(vals).std(axis=1, ddof=1)):.3f} log 单位")
(E.OUT / "report_repeatability.json").write_text(
json.dumps({"n_cells": int(len(out)), "n_rep": N_REP,
"n_all_ok": int(len(ok)),
"ratio_median": float(np.median(ratio)) if len(ok) else None,
"ratio_p90": float(np.quantile(ratio, .9)) if len(ok) else None,
"frac_ratio_gt2": float((ratio > 2).mean()) if len(ok) else None},
indent=2), encoding="utf-8")
print(f"[{time.time()-t0:.0f}s]")
if __name__ == "__main__":
main()

Xet Storage Details

Size:
3.81 kB
·
Xet hash:
0ddefe25e69d294af0157608ea06a89f91a944a7705afd3c54ca9f52ed51fb15

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.