Sound / add_estimated_position.py
Wendy-Fly's picture
default output to AIPF csv path (in-place overwrite, no cp needed)
2c780f9 verified
Raw History Blame Contribute Delete
4.88 kB
#!/usr/bin/env python3
"""把 embedding top-K match 估出来的整数 position 写回 golden_set.csv。
默认列名固定为 estimated_position(下游 AIPF warm-start 代码读这个名)。
默认输入/输出都指向 AIPF 流水线实际读取的那个 csv,**直接原地覆盖**,
省掉 `cp` 到 example/yss_ruler_eval/data/ 这一步。
每次跑都覆盖 estimated_position 列;用 --k 切换不同邻居数即可,
其它列保持不变。
用法:
python3 add_estimated_position.py --k 100 # 默认 K
python3 add_estimated_position.py --k 5
python3 add_estimated_position.py --k 1
⚠️ 第一次跑前建议备份原 csv:
cp /mnt/.../aipf_golden_set.csv /mnt/.../aipf_golden_set.csv.bak
可选:想同时存多列对比(不覆盖默认列),手动指定列名:
python3 add_estimated_position.py --k 5 --new-col estimated_position_top5
"""
import argparse
import json
from pathlib import Path
import numpy as np
import pandas as pd
DEFAULTS = dict(
csv = "/mnt/bn/tns-algo-ue-my/biaowu/aipf_dm_metric/example/yss_ruler_eval/data/aipf_golden_set.csv",
jsonl = "golden_top100.jsonl",
# 输出直接覆盖 AIPF 流水线实际读取的那个 csv,省掉 cp 那一步
output = "/mnt/bn/tns-algo-ue-my/biaowu/aipf_dm_metric/example/yss_ruler_eval/data/aipf_golden_set.csv",
id_col = "task_id",
)
def parse_args():
p = argparse.ArgumentParser()
p.add_argument("--csv", default=DEFAULTS["csv"])
p.add_argument("--jsonl", default=DEFAULTS["jsonl"])
p.add_argument("--output", default=DEFAULTS["output"])
p.add_argument("--id-col", default=DEFAULTS["id_col"])
p.add_argument("--k", type=int, default=100,
help="用前 K 个邻居算均值(K=1 即 top1 rank)")
p.add_argument("--new-col", default=None,
help="新列名;不传则自动用 estimated_position_top{K}")
p.add_argument("--k-suffix", default=None,
help="(已弃用,等价于 --new-col estimated_position_{suffix})")
return p.parse_args()
def main():
args = parse_args()
K = args.k
# 默认列名固定为 estimated_position(让下游代码不用改)
# 想要带 K 后缀(同时存多列对比)就显式传 --new-col 或 --k-suffix
if args.new_col:
col_name = args.new_col
elif args.k_suffix:
col_name = f"estimated_position_{args.k_suffix}"
else:
col_name = "estimated_position"
# 1) 读 jsonl,每条样本算 top-K rank 均值(K=1 时等价于最近邻 rank)
print(f"[1] read jsonl: {args.jsonl}")
estimated = {}
skipped = 0
with open(args.jsonl, "r", encoding="utf-8") as f:
for line in f:
line = line.strip()
if not line:
continue
r = json.loads(line)
topk = r.get("topk") or []
if len(topk) < K:
skipped += 1
continue
ranks = np.array([t["rank"] for t in topk[:K]], dtype=float)
estimated[str(r["task_id"])] = int(round(ranks.mean()))
print(f" -> {len(estimated)} cases estimated (K={K})")
if skipped:
print(f" ⚠️ {skipped} 条 jsonl 邻居数 < K,跳过")
# 2) 读 csv
print(f"[2] read csv: {args.csv}")
df = pd.read_csv(args.csv, keep_default_na=False)
print(f" -> {len(df)} rows, {len(df.columns)} cols")
if args.id_col not in df.columns:
raise ValueError(f"'{args.id_col}' not in csv. cols: {list(df.columns)}")
# 3) 给每条 case 加新列
print(f"[3] add column: {col_name}")
df[col_name] = df[args.id_col].astype(str).map(estimated)
n_total = len(df)
n_matched = df[col_name].notna().sum()
print(f" matched: {n_matched}/{n_total}")
if n_matched == n_total:
df[col_name] = df[col_name].astype("Int64")
# 4) 写
print(f"[4] write: {args.output}")
df.to_csv(args.output, index=False)
print(f" done. csv 现在有 {len(df.columns)} 列(含新列:{col_name})")
# 5) 预览 + stats
print(f"\n[preview] 前 5 行(task_id / label / {col_name}):")
cols = [args.id_col, "label", col_name]
cols = [c for c in cols if c in df.columns]
print(df[cols].head(5).to_string(index=False))
s = pd.to_numeric(df[col_name], errors="coerce")
print(f"\n[stats] {col_name}:")
print(f" min={int(s.min())} max={int(s.max())} mean={s.mean():.2f} median={int(s.median())} std={s.std():.2f}")
if "label" in df.columns:
print("\n按 label 分组:")
for lab, sub in df.groupby("label"):
ss = pd.to_numeric(sub[col_name], errors="coerce")
print(f" label={lab!r:>4} n={len(sub):>4} mean={ss.mean():.2f} median={int(ss.median())} std={ss.std():.2f}")
if __name__ == "__main__":
main()