Kalibrierung: Holdout pro Match, Kanarienvogel ignoriert Summons/Sonder-Items, Baseline-Vergleich
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -82,13 +82,17 @@ def main() -> None:
|
||||
from tft import db
|
||||
from tft.model import artifact as artifact_mod
|
||||
from tft.model.calibrate import calibrate
|
||||
from tft.staticdata.fetch import load_static
|
||||
|
||||
conn = db.connect()
|
||||
art = artifact_mod.load(current_set())
|
||||
result = calibrate(conn, art, holdout_only=True)
|
||||
learned_art = artifact_mod.load(current_set())
|
||||
baseline_art = artifact_mod.build(load_static(), {})
|
||||
r_base = calibrate(conn, baseline_art, holdout_only=True)
|
||||
r_learned = calibrate(conn, learned_art, holdout_only=True)
|
||||
conn.close()
|
||||
print(f"holdout matches: {result['matches']}")
|
||||
print(f"mean spearman (score vs placement): {result['mean_spearman']:.3f}")
|
||||
print(f"holdout matches: {r_learned['matches']}")
|
||||
print(f"spearman baseline: {r_base['mean_spearman']:.3f}")
|
||||
print(f"spearman learned: {r_learned['mean_spearman']:.3f}")
|
||||
|
||||
elif args.command == "autoplay":
|
||||
from tft.constants.loader import load_constants
|
||||
|
||||
@@ -39,16 +39,29 @@ def extract_match(match: dict) -> list[tuple]:
|
||||
return rows
|
||||
|
||||
|
||||
BENIGN_UNIT_HINTS = ("minion", "summon", "pve", "follower")
|
||||
|
||||
|
||||
def validate_ids(rows: list[tuple], static: dict) -> Counter:
|
||||
"""Count ids in endboards that are unknown to the static data (patch-drift canary)."""
|
||||
"""Count ids in endboards that are unknown to the static data (patch-drift canary).
|
||||
|
||||
Summons/PvE-Units und Sonder-Items (Radiant, Ornn, ...) sind erwartbar
|
||||
unbekannt und werden ignoriert.
|
||||
"""
|
||||
unknown: Counter = Counter()
|
||||
known_items = set(static["items"]) | set(static["augments"])
|
||||
set_prefix = f"TFT{static['meta']['set']}_"
|
||||
for row in rows:
|
||||
for u in json.loads(row[8]):
|
||||
if u["character_id"] not in static["units"]:
|
||||
unknown[f"unit:{u['character_id']}"] += 1
|
||||
api = u["character_id"]
|
||||
if api not in static["units"]:
|
||||
if not any(h in api.lower() for h in BENIGN_UNIT_HINTS):
|
||||
unknown[f"unit:{api}"] += 1
|
||||
for item in u.get("itemNames", []):
|
||||
if item not in known_items:
|
||||
if item in known_items:
|
||||
continue
|
||||
# Nur Items des aktuellen Sets oder generische zählen als Drift.
|
||||
if item.startswith("TFT_Item_") or item.startswith(set_prefix):
|
||||
unknown[f"item:{item}"] += 1
|
||||
for t in json.loads(row[9]):
|
||||
if t["name"] not in static["traits"]:
|
||||
|
||||
@@ -49,7 +49,8 @@ def calibrate(conn, artifact: dict, holdout_only: bool = False) -> dict:
|
||||
set_number = artifact["meta"]["set"]
|
||||
where = "WHERE set_number = ?"
|
||||
if holdout_only:
|
||||
where += " AND rowid % 5 = 0"
|
||||
# Holdout pro MATCH (nicht pro Board), sonst gibt es keine vollständigen 8er.
|
||||
where += " AND substr(match_id, -1) IN ('0', '5')"
|
||||
rows = conn.execute(
|
||||
f"SELECT match_id, placement, units, augments FROM endboards {where}",
|
||||
(set_number,),
|
||||
|
||||
@@ -80,7 +80,7 @@ def learn(rows: list[tuple]) -> dict:
|
||||
def learn_from_db(conn, set_number: int, exclude_holdout: bool = True) -> dict:
|
||||
where = "WHERE set_number = ?"
|
||||
if exclude_holdout:
|
||||
where += " AND rowid % 5 != 0"
|
||||
where += " AND substr(match_id, -1) NOT IN ('0', '5')"
|
||||
rows = conn.execute(
|
||||
f"SELECT placement, units, traits, augments FROM endboards {where}",
|
||||
(set_number,),
|
||||
|
||||
Reference in New Issue
Block a user