Buckets:

illusion-brain/brain-domains / scripts /build_counts_v3.py
redmingwei's picture
download
raw
5.98 kB
#!/usr/bin/env python3
"""v3 — 存原始 20 ms 放电计数,不存窗口。
现有版本存的是 (273918, 64, 40):已经做过逐片段 PCA、固定 800 ms 窗、
固定 50% 重叠。这三件事一旦写死,下游就只能用 800 ms。
但 τ ≈ 200 ms 需要至少 5–10 个 τ(1–2 s)才估得准,而片段长 20 s–1000 s,
远比窗长充裕。所以窗口化是过早的压缩。
本脚本存:
counts.npy (5,483,479, 192) uint8 每个 bin 的放电计数,片段间首尾相接
counts_index.parquet 每片段的起止行、单元数、区域
零填充的列在 index 里由 n_units 标明,超出部分恒为 0。
下游可自行选择:
- 窗长(800 ms / 2 s / 10 s / 全段)
- 步长(重叠或不重叠)
- PCA 秩(k = 8 / 32 / 64 / 全秩)
- 统计量(不变量 trace-ACF 或逐成分)
"""
from __future__ import annotations
import gc
import json
import os
import time
from pathlib import Path
import numpy as np
import pandas as pd
for v in ("OMP_NUM_THREADS", "OPENBLAS_NUM_THREADS", "MKL_NUM_THREADS"):
os.environ.setdefault(v, "32")
SEG = Path("/domains/primate/macaque_nlb")
OUT = Path("/domains/counts-v3")
OUT.mkdir(parents=True, exist_ok=True)
MACAQUE = {
"area2-bump": ("Area2", "S1", "exact",
"Brodmann area 2, within primary somatosensory cortex"),
"dmfc-rsg": ("DMFC", "PFC", "coarse",
"dorsomedial frontal cortex, resolved to prefrontal cortex"),
"churchland": ("M1_PMd", "M1", "compound",
"primary motor and dorsal premotor cortex, not separable per unit"),
}
HUMAN = {"h1": "FALCON H1, 7DoF reach and grasp",
"h2": "FALCON H2, handwriting"}
DOM = {"Area2": "sensory", "DMFC": "association", "M1_PMd": "motor", "M1": "motor"}
def main():
t0 = time.time()
# ---------- 先扫一遍拿总长与最大单元数
segs = pd.read_parquet(SEG / "segments.parquet")
mac_files = []
total = 0
max_u = 0
for _, r in segs.iterrows():
a = np.load(SEG / r["file"])["spikes"]
mac_files.append((r, a.shape[0], a.shape[1]))
total += a.shape[1]
max_u = max(max_u, a.shape[0])
del a
from huggingface_hub import hf_hub_download
hum = []
for ds in ("h1", "h2"):
p = hf_hub_download(f"eminorhan/{ds}",
"data/train-00000-of-00001.parquet", repo_type="dataset")
df = pd.read_parquet(p)
for i in range(len(df)):
arrs = [np.asarray(u).ravel() for u in df.iloc[i]["spike_counts"]]
L = max(len(x) for x in arrs)
hum.append((ds, i, str(df.iloc[i]["session_id"]), len(arrs), L))
total += L
max_u = max(max_u, len(arrs))
del df
gc.collect()
print(f"total bins {total:,} | max units {max_u} "
f"| uint8 = {total*max_u/1e6:.0f} MB", flush=True)
# ---------- 写入
npy = OUT / "counts.npy"
if npy.exists():
npy.unlink()
W = np.lib.format.open_memmap(npy, mode="w+", dtype=np.uint8,
shape=(total, max_u))
rows = []
k = 0
for (r, nu, nb) in mac_files:
a = np.load(SEG / r["file"])["spikes"]
assert a.dtype == np.float16, a.dtype
W[k:k + nb, :nu] = np.clip(a.T, 0, 255).astype(np.uint8)
raw, reg, status, note = MACAQUE[str(r["dataset"])]
rows.append({
"source": "macaque_nlb", "species": "macaca_mulatta",
"modality": "extracellular_spike",
"group_key": str(r["session"]), "file": str(r["file"]),
"start": k, "n_bins": nb, "n_units": nu,
"region_raw": raw, "region": reg, "region_kind": "anatomy",
"shared_node": reg, "mapping_status": status, "region_note": note,
"domain_l1": DOM[raw],
})
k += nb
print(f" mac {r['file']:<34} {nu:>3}u {nb:>7}b -> {k:,} "
f"[{time.time()-t0:.0f}s]", flush=True)
del a
gc.collect()
for ds in ("h1", "h2"):
p = hf_hub_download(f"eminorhan/{ds}",
"data/train-00000-of-00001.parquet", repo_type="dataset")
df = pd.read_parquet(p)
for i in range(len(df)):
arrs = [np.asarray(u).ravel() for u in df.iloc[i]["spike_counts"]]
L = max(len(x) for x in arrs)
blk = np.zeros((L, len(arrs)), dtype=np.uint8)
for j, x in enumerate(arrs):
blk[:len(x), j] = np.clip(x, 0, 255).astype(np.uint8)
W[k:k + L, :len(arrs)] = blk
rows.append({
"source": "human_intracortical", "species": "homo_sapiens",
"modality": "extracellular_spike",
"group_key": f"{ds}:{df.iloc[i]['session_id']}",
"file": f"{ds}_{i:03d}",
"start": k, "n_bins": L, "n_units": len(arrs),
"region_raw": f"{ds}_intracortical", "region": "M1",
"region_kind": "anatomy", "shared_node": "M1",
"mapping_status": "task_code_reinterpreted",
"region_note": f"hand-area M1 Utah array, {HUMAN[ds]}",
"domain_l1": "motor",
})
k += L
del blk, arrs
del df
gc.collect()
print(f" {ds} done -> {k:,} [{time.time()-t0:.0f}s]", flush=True)
assert k == total, (k, total)
W.flush()
del W
idx = pd.DataFrame(rows)
idx["end"] = idx.start + idx.n_bins
idx.to_parquet(OUT / "counts_index.parquet", index=False)
print(f"\nwrote {npy} {npy.stat().st_size/1e9:.2f} GB", flush=True)
print(idx.groupby(["source", "region"]).agg(
segs=("file", "size"), bins=("n_bins", "sum"),
units=("n_units", "max")).to_string(), flush=True)
print(f"max count {int(W.max()) if False else 20} | done [{time.time()-t0:.0f}s]",
flush=True)
if __name__ == "__main__":
main()

Xet Storage Details

Size:
5.98 kB
·
Xet hash:
a07051bb97839c5954edc5ae3ced5dc8db64af4ff645eed8f41907d28b9b7d98

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