File size: 7,985 Bytes
f28d994 | 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 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 | """Generate a submission for one systematic random-walk model."""
from __future__ import annotations
import argparse
import importlib.util
import sys
from pathlib import Path
import lightgbm as lgb
import numpy as np
import pandas as pd
from gensim.models import Word2Vec
def load_module(name: str, path: Path):
spec = importlib.util.spec_from_file_location(name, path)
module = importlib.util.module_from_spec(spec)
assert spec.loader is not None
sys.modules[name] = module
spec.loader.exec_module(module)
return module
def make_subs(root: Path, out_dir: Path, version: str, score: np.ndarray, ratios: list[float], thresholds: list[float]) -> None:
known = np.load(root / "cached_scores" / "test_known_mask.npy").astype(bool)
current_path = root / "validation_runs" / "dynamic_seed202" / "node2vec_deepwalk_submission" / "submission_content_mf_deepwalk_node2vec_lgb_th0.480000.csv"
current = pd.read_csv(current_path)["Predicted"].to_numpy(np.int8) if current_path.exists() else None
rows = []
for ratio in ratios:
pred = np.zeros(len(score), dtype=np.int8)
pred[np.argsort(score)[-int(round(len(score) * ratio)):]] = 1
pred[known] = 1
path = out_dir / f"submission_{version}_r{ratio:.3f}.csv"
pd.DataFrame({"Index": np.arange(len(pred), dtype=np.int64), "Predicted": pred}).to_csv(path, index=False)
changed = int((pred != current).sum()) if current is not None else -1
rows.append({"path": str(path), "rule": f"r{ratio:.3f}", "positive_ratio": float(pred.mean()), "changed_vs_current": changed})
print(path, int(pred.sum()), float(pred.mean()), "changed", changed)
for th in thresholds:
pred = (score >= th).astype(np.int8)
pred[known] = 1
path = out_dir / f"submission_{version}_th{th:.6f}.csv"
pd.DataFrame({"Index": np.arange(len(pred), dtype=np.int64), "Predicted": pred}).to_csv(path, index=False)
changed = int((pred != current).sum()) if current is not None else -1
rows.append({"path": str(path), "rule": f"th{th:.6f}", "positive_ratio": float(pred.mean()), "changed_vs_current": changed})
print(path, int(pred.sum()), float(pred.mean()), "changed", changed)
pd.DataFrame(rows).to_csv(out_dir / f"{version}_submission_summary.csv", index=False)
def main() -> None:
parser = argparse.ArgumentParser()
parser.add_argument("--package-root", type=Path, default=Path(__file__).resolve().parents[1])
parser.add_argument("--split-seed", type=int, default=202)
parser.add_argument("--main-val-score-file", type=Path, required=True)
parser.add_argument("--version-name", required=True)
parser.add_argument("--threshold", type=float, default=0.5134975910186768)
parser.add_argument("--ratios", nargs="*", type=float, default=[0.498, 0.499, 0.500, 0.501, 0.502])
args = parser.parse_args()
root = args.package_root
stack = load_module("stack", root / "code" / "stack_rank_calibration.py")
lgcn = load_module("lgcn", root / "code" / "train_val_lgcn_ensemble.py")
post = load_module("post", root / "code" / "post95_ablation.py")
gen = load_module("gen", root / "code" / "generate_post95_submission.py")
extra = load_module("extra", root / "code" / "extra_score_sources_ablation.py")
rw = load_module("rw", root / "code" / "randomwalk_systematic_ablation.py")
sys_dir = root / "validation_runs" / f"dynamic_seed{args.split_seed}" / "randomwalk_systematic"
out_dir = root / "validation_runs" / f"dynamic_seed{args.split_seed}" / "randomwalk_ensemble_submission"
out_dir.mkdir(parents=True, exist_ok=True)
train_refs, val_pairs = lgcn.make_notebook_style_split(root, args.split_seed, 0.9)
pairs = val_pairs[["source", "target"]].to_numpy(np.int64)
y = val_pairs["label"].to_numpy(np.int8)
main = np.load(args.main_val_score_file).astype(np.float32)
builder = stack.ExplicitGraphFeatures(root, train_refs)
Xh = builder.transform(pairs)
X_val = np.column_stack(
[
stack.add_rank_features(pairs, main),
Xh,
post.negative_evidence_features(Xh, main),
gen.topk_content_similarity_fast(root, pairs, builder),
]
).astype(np.float32)
selected = [Path(x.strip()) for x in (root / "validation_runs" / f"dynamic_seed{args.split_seed}" / "post95_submission" / "selected_variant_val_scores.txt").read_text().splitlines() if x.strip()]
X_val = np.column_stack([X_val, gen.variant_feature_matrix(post, [np.load(p).astype(np.float32) for p in selected])]).astype(np.float32)
content = extra.content_mean_score(root, pairs, builder)
mf = np.load(root / "validation_runs" / f"dynamic_seed{args.split_seed}" / "extra_score_sources" / "val_mf_bpr_s202_d256.npy").astype(np.float32)
Xc, _ = extra.score_to_features(content, "content_mean_cos", pairs)
Xm, _ = extra.score_to_features(mf, "mf_bpr", pairs)
X_val = np.column_stack([X_val, Xc, Xm]).astype(np.float32)
cfg = next(c for c in rw.small_configs() + rw.graph_configs() + rw.extra_configs() if c.version_name == args.version_name)
model = Word2Vec.load(str(sys_dir / "models" / f"{args.version_name}.model"))
block, _ = rw.pair_feature_block(model, pairs, cfg, root, args.split_seed, train_refs)
X_val = np.column_stack([X_val, block]).astype(np.float32)
clf = lgb.LGBMClassifier(
n_estimators=1200,
learning_rate=0.025,
num_leaves=31,
subsample=0.9,
colsample_bytree=0.9,
reg_lambda=5.0,
min_child_samples=80,
objective="binary",
n_jobs=8,
verbose=-1,
random_state=202,
)
print("fit", X_val.shape)
clf.fit(X_val, y)
test_pairs = np.array(gen.read_txt(root / "data_and_docs" / "bipartite_test_ann.txt"), dtype=np.int64)
main_test = np.load(root / "validation_runs" / f"dynamic_seed{args.split_seed}" / "post95_test_scores" / "dyn202_l2d512_bpr_bigbatch_more" / "scores" / "test_vanilla_ensemble_mean.npy").astype(np.float32)
full_refs = pd.DataFrame(gen.read_txt(root / "data_and_docs" / "bipartite_train_ann.txt"), columns=["source", "target"])
test_builder = stack.ExplicitGraphFeatures(root, full_refs)
Xht = test_builder.transform(test_pairs)
X_test = np.column_stack(
[
stack.add_rank_features(test_pairs, main_test),
Xht,
post.negative_evidence_features(Xht, main_test),
gen.topk_content_similarity_fast(root, test_pairs, test_builder),
]
).astype(np.float32)
test_scores = []
for p in selected:
rel = p.resolve().relative_to(root / "validation_runs" / f"dynamic_seed{args.split_seed}")
tp = root / "validation_runs" / f"dynamic_seed{args.split_seed}" / "post95_test_scores" / rel.parent / rel.name.replace("val_", "test_", 1)
test_scores.append(np.load(tp).astype(np.float32))
X_test = np.column_stack([X_test, gen.variant_feature_matrix(post, test_scores)]).astype(np.float32)
content_test = extra.content_mean_score(root, test_pairs, test_builder)
mf_test = np.load(root / "validation_runs" / f"dynamic_seed{args.split_seed}" / "extra_bprmf_submission" / "test_mf_bpr_dynamic_s202_d256_e220.npy").astype(np.float32)
Xct, _ = extra.score_to_features(content_test, "content_mean_cos", test_pairs)
Xmt, _ = extra.score_to_features(mf_test, "mf_bpr", test_pairs)
X_test = np.column_stack([X_test, Xct, Xmt]).astype(np.float32)
test_block, _ = rw.pair_feature_block(model, test_pairs, cfg, root, args.split_seed, full_refs)
X_test = np.column_stack([X_test, test_block]).astype(np.float32)
print("predict", X_test.shape)
score = clf.predict_proba(X_test)[:, 1].astype(np.float32)
np.save(out_dir / f"test_{args.version_name}_pred.npy", score)
make_subs(root, out_dir, args.version_name, score, args.ratios, [args.threshold, 0.48, 0.50])
if __name__ == "__main__":
main()
|