| import argparse |
| import glob |
| import os |
| import re |
|
|
| import numpy as np |
| import pandas as pd |
|
|
| KEY = 'TEST' |
|
|
| def parse_summary(path): |
| try: |
| txt = open(path).read() |
| mean = float(re.search(rf"{KEY}_MEAN=([0-9.]+)", txt).group(1)) |
| std = float(re.search(rf"{KEY}_STD=([0-9.]+)", txt).group(1)) |
| ckpt_line = re.search(r"Checkpoint:\s*(.*)", txt).group(1) |
| model = os.path.basename(ckpt_line).replace(".ckpt", "") |
| return model, f"{mean:.3f} ± {std:.3f}" |
| except: |
| return None |
|
|
| def parse_from_seeds(folder): |
| logs = sorted(glob.glob(os.path.join(folder, "seed_*.log"))) |
| expected_seeds = 5 |
|
|
| if not logs: |
| print(f"WARNING: No seed logs found in {folder}") |
| return None |
|
|
| auc_pattern = r"TEST AUC:\s*([0-9.]+)" if KEY == "TEST" else \ |
| r"LAST TEST AUC:\s*([0-9.]+)" if KEY == "LAST_TEST" else None |
| if auc_pattern is None: |
| return None |
|
|
| ckpt_pattern = r"'checkpoint_path':\s*'([^']*)'" |
|
|
| vals, model_name, valid_logs = [], None, 0 |
|
|
| for log in logs: |
| try: |
| txt = open(log).read() |
| m = re.search(auc_pattern, txt) |
| if m: |
| vals.append(float(m.group(1))) |
| valid_logs += 1 |
|
|
| cm = re.search(ckpt_pattern, txt) |
| if cm: |
| ckpt_path = cm.group(1) |
| model_name = os.path.basename(ckpt_path).replace(".ckpt", "") |
| except: |
| pass |
|
|
| model_name = model_name or "unknown" |
| if model_name == '': |
| model_name = "random" |
|
|
| if valid_logs != expected_seeds and model_name != 'random': |
| print(f"WARNING: Incomplete seeds for {model_name} in {folder} " |
| f"(found {valid_logs}/{expected_seeds})") |
|
|
| if not vals: |
| return None |
|
|
| mean, std = float(np.mean(vals)), float(np.std(vals)) |
| return model_name, f"{mean:.3f} ± {std:.3f}" |
|
|
| def parse_summary_or_seeds(folder): |
| summary_path = os.path.join(folder, "summary.txt") |
| if os.path.exists(summary_path): |
| parsed = parse_summary(summary_path) |
| if parsed: |
| return parsed |
| return parse_from_seeds(folder) |
|
|
| def extract_mean(x): |
| if isinstance(x, str) and "±" in x: |
| return float(x.split("±")[0].strip()) |
| return np.nan |
|
|
| def main(): |
| parser = argparse.ArgumentParser() |
| parser.add_argument("--results_dir", type=str, default="results", help="Path to results folder") |
| args = parser.parse_args() |
| ROOT = args.results_dir |
|
|
| rows, subjects, tasks, models, folds = [], set(), set(), set(), set() |
|
|
| |
| for folder in os.listdir(ROOT): |
| fpath = os.path.join(ROOT, folder) |
| if not os.path.isdir(fpath): |
| continue |
|
|
| parts = folder.split("_") |
| if len(parts) < 6: |
| continue |
|
|
| subj = parts[1] |
| task = parts[4] |
| if len(parts) > 5 and parts[5] in ["onset", "vs", "nonspeech", "speech", "time"]: |
| task += f"_{parts[5]}" |
| if len(parts) > 6 and parts[6] == "nonspeech": |
| task += f"_{parts[6]}" |
|
|
| fold = None |
| for p in parts: |
| if p.startswith("fold"): |
| fold = int(p.replace("fold", "")) |
| folds.add(fold) |
| break |
|
|
| parsed = parse_summary_or_seeds(fpath) |
| if not parsed: |
| continue |
|
|
| model, value = parsed |
| subjects.add(subj) |
| tasks.add(task) |
| models.add(model) |
| rows.append((task, model, subj, fold, value)) |
|
|
| |
| subjects = sorted(subjects, key=lambda x: int(x)) |
| df = pd.DataFrame(columns=["task", "model", "fold"] + subjects) |
|
|
| for task in sorted(tasks): |
| for model in sorted(models): |
| all_folds = sorted(folds) + [None] |
| for fold in all_folds: |
| subset = [(s, v) for t, m, s, f, v in rows if t == task and m == model and f == fold] |
| if not subset: |
| continue |
| row = {"task": task, "model": model, "fold": fold if fold is not None else ""} |
| for subj, val in subset: |
| row[subj] = val |
| df.loc[len(df)] = row |
|
|
| |
| subj_cols = [c for c in df.columns if c not in ["task", "model", "fold"]] |
| df["avg"] = df[subj_cols].applymap(extract_mean).mean(axis=1) |
| df["avg"] = df["avg"].apply(lambda x: f"{x:.3f}" if pd.notnull(x) else "") |
|
|
| |
| avg_rows = [] |
| for (task, model), group in df.groupby(["task", "model"]): |
| subj_avgs = {} |
| for subj in subj_cols: |
| vals = [float(v.split("±")[0].strip()) for v in group[subj] if isinstance(v, str) and "±" in v] |
| subj_avgs[subj] = f"{np.mean(vals):.3f}" if vals else "" |
| overall_vals = [float(v) for v in subj_avgs.values() if v != ""] |
| overall_avg = f"{np.mean(overall_vals):.3f}" if overall_vals else "" |
| row = {"task": task, "model": model, "fold": "AVG", "avg": overall_avg} |
| row.update(subj_avgs) |
| avg_rows.append(row) |
|
|
| df = pd.concat([df, pd.DataFrame(avg_rows)], ignore_index=True) |
| print(df.to_markdown(index=False)) |
|
|
| if __name__ == "__main__": |
| main() |
|
|