Buckets:

illusion-brain/brain-domains / scripts /build_duplicate_map.py
redmingwei's picture
download
raw
6.31 kB
#!/usr/bin/env python3
"""build_duplicate_map — L1 系统去重。
三条线索,逐条给出证据:
A. counts_v4 的 175 段 → 源 npz(索引里有 file 字段),并用数值核对:
uint8 计数与源 npz(1/8 缩放)应满足 sum(uint8) == sum(npz)*8。
B. omnibrain_multi 的窗 → omnibrain_spike_view 系列(各来源窗口数应一致),
抽样比对窗口内容。
C. omnibrain4d 的 band → eeg(同源,band 是派生),标 derived 而非 same_record。
输出 framework/duplicate_map.parquet / .csv
"""
from __future__ import annotations
import glob
from pathlib import Path
import numpy as np
import pandas as pd
ROOT = Path("/domains")
OUT = ROOT / "framework"
rows = []
def add(src_m, src_s, dst_m, dst_s, relation, evidence, verified):
rows.append(dict(src_member=src_m, src_slice=src_s, dst_member=dst_m,
dst_slice=dst_s, relation=relation, evidence=evidence,
verified=bool(verified)))
# ---------------- A. counts_v4 → 源 npz
print("[A] counts_v4 → 源 npz", flush=True)
ci = pd.read_parquet(ROOT / "counts-v4/counts_index.parquet")
flat = np.load(ROOT / "counts-v4/counts_ragged.npy", mmap_mode="r")
ok_n = 0
for _, r in ci.iterrows():
src = Path(str(r.file)).stem
src_l = str(r.source).lower()
is_mouse = ("steinmetz" in src_l) or ("mouse" in src_l)
member = "steinmetz" if is_mouse else "primate_macaque_nlb"
off, nel = int(r.offset), int(r.n_elements)
nb, nu = int(r.n_bins_20ms), int(r.n_units)
seg = np.asarray(flat[off:off + nel], dtype=np.float64).reshape(nb, nu)
f = ROOT / ("steinmetz" if member == "steinmetz" else "primate/macaque_nlb") / f"{src}.npz"
verified = False
ev = f"missing {f.name}"
if f.exists():
z = np.load(f, mmap_mode="r")
k = "spikes" if "spikes" in z.keys() else list(z.keys())[0]
a = np.asarray(z[k], dtype=np.float64)
x = a.T if a.shape[0] < a.shape[1] else a
if x.shape == seg.shape:
s1, s2 = float(seg.sum()), float(x.sum())
# npz 可能是整数计数,也可能是 1/8 缩放;两种假设都试,取吻合的那个
rel1 = abs(s1 - s2) / max(s1, 1.0)
rel2 = abs(s1 - s2 * 8) / max(s1, 1.0)
if min(rel1, rel2) < 0.02:
verified = True
scale = "1" if rel1 <= rel2 else "8"
ev = f"scale={scale} sum_uint8={s1:.0f} sum_npz={s2:.0f} rel={min(rel1, rel2):.5f}"
else:
ev = f"sum_uint8={s1:.0f} sum_npz={s2:.0f} rel1={rel1:.3f} rel8={rel2:.3f}"
else:
ev = f"shape seg={seg.shape} npz={x.shape} bin_ms={r.bin_ms}"
add("counts_v4_ragged", f"seg{int(r.segment_idx):03d}", member, src,
"same_record", ev, verified)
ok_n += int(verified)
print(f" {len(ci)} 段,数值核对通过 {ok_n}", flush=True)
# ---------------- B. multi 窗 vs spike_view
print("\n[B] omnibrain_multi → spike_view", flush=True)
mi = pd.read_parquet(ROOT / "omnibrain-multi/index_timeseries.parquet")
ts = np.load(ROOT / "omnibrain-multi/timeseries.npy", mmap_mode="r")
VIEWS = {"mouse_steinmetz": "omnibrain_spike_view",
"macaque_nlb": "omnibrain_spike_view_macaque",
"human_intracortical": "omnibrain_spike_view_human",
"human_eeg": "omnibrain_eeg_view"}
NP = 300
for src, view in VIEWS.items():
pos = np.flatnonzero((mi.source == src).to_numpy())
if not len(pos):
continue
a = np.asarray(ts[pos[:NP]], dtype=np.float32)
# 取同源 view 的前若干窗口
files = sorted(glob.glob(str(ROOT / "omnibrain" / view.replace("omnibrain_", "") / "**" / "*.npz"),
recursive=True))
chunks, got = [], 0
for f in files:
z = np.load(f, mmap_mode="r")
if "windows" not in z.keys():
continue
w = np.asarray(z["windows"], dtype=np.float32)
take = min(len(w), NP - got)
chunks.append(w[:take])
got += take
if got >= NP:
break
if got < 10:
add("omnibrain_multi", src, view, "-", "unverified", "no windows found", False)
continue
b = np.concatenate(chunks, axis=0)
n = min(len(a), len(b))
same = bool(np.allclose(a[:n], b[:n], atol=1e-3))
ev = f"n_rows_multi={len(pos)} n_win_view={got}; first {n} rows equal={same}"
add("omnibrain_multi", src, view, "-",
"reencoded_identical" if same else "related_same_source", ev, same)
print(f" {src}: multi={len(pos)} view_sample={got} equal={same}", flush=True)
# ---------------- C. 4D band → eeg
print("\n[C] omnibrain4d band → eeg", flush=True)
files4 = sorted(glob.glob(str(ROOT / "omnibrain4d/**/*.npz"), recursive=True))
by_key = {}
for f in files4:
z = np.load(f, mmap_mode="r")
keys = list(z.keys())
stem = Path(f).stem
for suf in ("_band", "_eeg", "-band", "-eeg"):
if stem.endswith(suf):
stem = stem[: -len(suf)]
break
if "eeg" in keys:
by_key.setdefault(stem, {})["eeg"] = tuple(z["eeg"].shape)
if "band" in keys:
by_key.setdefault(stem, {})["band"] = tuple(z["band"].shape)
for stem, v in list(by_key.items())[:6]:
if "eeg" in v and "band" in v:
add("omnibrain4d", stem, "omnibrain4d", stem, "derived",
f"eeg{v['eeg']} -> band{v['band']}(带通功率,非切片)", True)
print(f" {stem}: eeg{v['eeg']} band{v['band']}", flush=True)
print(f" 4D 文件 {len(files4)} 个,配对 {len(by_key)} 组", flush=True)
# 依据证据给失败项重新归类,避免一律读成"不是同一记录"
def relabel(r):
if r.relation != "same_record":
return r.relation
if r.verified:
return "same_record"
if str(r.evidence).startswith("missing"):
return "external_source" # 源只在 DANDI,桶内无镜像
if str(r.evidence).startswith("shape"):
return "resampled_or_reshaped" # 形状不同(如 50→20 ms)
return "unverified"
d = pd.DataFrame(rows)
d["relation"] = d.apply(relabel, axis=1)
d.to_parquet(OUT / "duplicate_map.parquet", index=False)
d.to_csv(OUT / "duplicate_map.csv", index=False)
print(f"\nrows={len(d)}")
print(d.groupby(["relation", "verified"]).size().to_string())

Xet Storage Details

Size:
6.31 kB
·
Xet hash:
23a61b1d1f5f5afeba37a698b5759d041ad3528dadfeb0776afa3ddc6d3b7544

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