forked from chiki2bum2/SniperGold_ML
96 lines
No EOL
3.6 KiB
Python
96 lines
No EOL
3.6 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""P3-S.18 — TREE BASELINE (shallow decision tree + constrained boosting).
|
|
|
|
Intentionally small: DecisionTree(max_depth=3) and GradientBoosting
|
|
(n_estimators=40, max_depth=2, lr=0.03). No broad hyperparameter search.
|
|
Binary target: WIN vs LOSS (leads only). Same split/standardization policy;
|
|
trees are scale-invariant, scaler applied for consistency of the pipeline.
|
|
"""
|
|
import csv
|
|
import json
|
|
import os
|
|
import sys
|
|
|
|
import numpy as np
|
|
from sklearn.ensemble import GradientBoostingClassifier
|
|
from sklearn.preprocessing import StandardScaler
|
|
from sklearn.tree import DecisionTreeClassifier
|
|
|
|
HERE = os.path.dirname(os.path.abspath(__file__))
|
|
OUT = os.path.join(HERE, "output")
|
|
sys.path.insert(0, HERE)
|
|
sys.path.insert(0, os.path.normpath(os.path.join(HERE, "..", "setup_dataset")))
|
|
|
|
import prepare_dataset as PD # noqa: E402
|
|
|
|
SEED = 42
|
|
|
|
|
|
def _setup():
|
|
ctx = PD.load_verified_population()
|
|
rows = PD.build_rows(ctx)
|
|
bin_rows = [r for r in rows if r["lead"] and r["outcome"] in PD.BINARY_CLASSES]
|
|
bin_rows.sort(key=lambda r: (r["creation_bar"], r["setup_id"]))
|
|
tr, va, te, _ = PD.temporal_split(rows)
|
|
split_map = {}
|
|
for part, tag in ((tr, "train"), (va, "val"), (te, "test")):
|
|
for r in part:
|
|
split_map[r["setup_id"]] = tag
|
|
X = np.asarray([[r["feature_" + k] for k in PD.FEATURE_COLS]
|
|
for r in bin_rows], dtype=float)
|
|
y = np.asarray([1.0 if r["outcome"] == "WIN" else 0.0
|
|
for r in bin_rows], dtype=float)
|
|
splits = np.asarray([split_map[r["setup_id"]] for r in bin_rows])
|
|
scaler = StandardScaler().fit(X[splits == "train"])
|
|
Xs = scaler.transform(X)
|
|
return Xs, y, splits, bin_rows, tr, va, te, rows
|
|
|
|
|
|
def main():
|
|
os.makedirs(OUT, exist_ok=True)
|
|
Xs, y, splits, bin_rows, tr, va, te, rows = _setup()
|
|
models = {
|
|
"tree_depth3": DecisionTreeClassifier(max_depth=3, random_state=SEED,
|
|
min_samples_leaf=5),
|
|
"boost_small": GradientBoostingClassifier(
|
|
n_estimators=40, max_depth=2, learning_rate=0.03,
|
|
random_state=SEED),
|
|
}
|
|
preds = {}
|
|
for name, clf in models.items():
|
|
clf.fit(Xs[splits == "train"], y[splits == "train"])
|
|
preds[name] = clf.predict_proba(Xs)[:, 1]
|
|
|
|
rows_out = []
|
|
for i, r in enumerate(bin_rows):
|
|
d = {"setup_id": r["setup_id"], "split": splits[i],
|
|
"outcome": r["outcome"], "y": int(y[i])}
|
|
for name in models:
|
|
d["pred_" + name] = float(preds[name][i])
|
|
rows_out.append(d)
|
|
with open(os.path.join(OUT, "p3_s18_predictions_tree.csv"), "w",
|
|
newline="", encoding="utf-8") as f:
|
|
w = csv.DictWriter(f, fieldnames=list(rows_out[0].keys()))
|
|
w.writeheader()
|
|
for r in rows_out:
|
|
w.writerow(r)
|
|
|
|
with open(os.path.join(OUT, "p3_s18_tree_model.json"), "w",
|
|
encoding="utf-8") as f:
|
|
json.dump({
|
|
"models": list(models.keys()),
|
|
"config": {"tree": "max_depth=3,min_samples_leaf=5",
|
|
"boost": "n_estimators=40,max_depth=2,lr=0.03"},
|
|
"feature_sha16": PD.make_manifest(rows, tr, va, te,
|
|
True)["feature_sha16"],
|
|
"seed": SEED,
|
|
"feature_importance": {
|
|
"tree_depth3": dict(zip(PD.FEATURE_COLS, models[
|
|
"tree_depth3"].feature_importances_.tolist()))},
|
|
}, f, indent=2)
|
|
print("[saved] p3_s18_predictions_tree.csv / tree_model.json")
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main()) |