File size: 4,883 Bytes
2b769ad
de652ba
2b769ad
500dff7
2c780f9
 
2b769ad
2c780f9
 
de652ba
2c780f9
 
de652ba
 
 
2c780f9
 
 
 
de652ba
2b769ad
 
 
 
 
 
 
 
 
 
 
 
2c780f9
 
2b769ad
 
 
 
 
 
de652ba
 
 
 
 
 
 
 
 
 
2b769ad
 
 
 
 
de652ba
2b769ad
500dff7
 
de652ba
 
 
 
 
500dff7
de652ba
 
2b769ad
 
de652ba
2b769ad
 
 
 
 
 
de652ba
 
 
 
 
bf13d1c
de652ba
 
 
2b769ad
 
 
 
de652ba
2b769ad
 
bf13d1c
 
de652ba
 
 
bf13d1c
de652ba
 
bf13d1c
de652ba
 
bf13d1c
 
2b769ad
 
de652ba
2b769ad
de652ba
 
 
bf13d1c
 
2b769ad
de652ba
 
 
2b769ad
bf13d1c
2b769ad
de652ba
 
2b769ad
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
#!/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()