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:
@@ -31,6 +31,7 @@ FAKE_MATCH = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
STATIC = {
|
STATIC = {
|
||||||
|
"meta": {"set": 17},
|
||||||
"units": {"TFT17_Rammus": {}},
|
"units": {"TFT17_Rammus": {}},
|
||||||
"traits": {"TFT17_ResistTank": {}},
|
"traits": {"TFT17_ResistTank": {}},
|
||||||
"items": {"TFT_Item_InfinityEdge": {}},
|
"items": {"TFT_Item_InfinityEdge": {}},
|
||||||
@@ -61,7 +62,7 @@ def test_validate_ids_clean():
|
|||||||
|
|
||||||
def test_validate_ids_flags_unknown():
|
def test_validate_ids_flags_unknown():
|
||||||
rows = extract_match(FAKE_MATCH)
|
rows = extract_match(FAKE_MATCH)
|
||||||
static = {"units": {}, "traits": {}, "items": {}, "augments": {}}
|
static = {"meta": {"set": 17}, "units": {}, "traits": {}, "items": {}, "augments": {}}
|
||||||
unknown = validate_ids(rows, static)
|
unknown = validate_ids(rows, static)
|
||||||
assert unknown["unit:TFT17_Rammus"] == 8
|
assert unknown["unit:TFT17_Rammus"] == 8
|
||||||
assert unknown["item:TFT_Item_InfinityEdge"] == 8
|
assert unknown["item:TFT_Item_InfinityEdge"] == 8
|
||||||
|
|||||||
@@ -82,13 +82,17 @@ def main() -> None:
|
|||||||
from tft import db
|
from tft import db
|
||||||
from tft.model import artifact as artifact_mod
|
from tft.model import artifact as artifact_mod
|
||||||
from tft.model.calibrate import calibrate
|
from tft.model.calibrate import calibrate
|
||||||
|
from tft.staticdata.fetch import load_static
|
||||||
|
|
||||||
conn = db.connect()
|
conn = db.connect()
|
||||||
art = artifact_mod.load(current_set())
|
learned_art = artifact_mod.load(current_set())
|
||||||
result = calibrate(conn, art, holdout_only=True)
|
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()
|
conn.close()
|
||||||
print(f"holdout matches: {result['matches']}")
|
print(f"holdout matches: {r_learned['matches']}")
|
||||||
print(f"mean spearman (score vs placement): {result['mean_spearman']:.3f}")
|
print(f"spearman baseline: {r_base['mean_spearman']:.3f}")
|
||||||
|
print(f"spearman learned: {r_learned['mean_spearman']:.3f}")
|
||||||
|
|
||||||
elif args.command == "autoplay":
|
elif args.command == "autoplay":
|
||||||
from tft.constants.loader import load_constants
|
from tft.constants.loader import load_constants
|
||||||
|
|||||||
@@ -39,16 +39,29 @@ def extract_match(match: dict) -> list[tuple]:
|
|||||||
return rows
|
return rows
|
||||||
|
|
||||||
|
|
||||||
|
BENIGN_UNIT_HINTS = ("minion", "summon", "pve", "follower")
|
||||||
|
|
||||||
|
|
||||||
def validate_ids(rows: list[tuple], static: dict) -> Counter:
|
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()
|
unknown: Counter = Counter()
|
||||||
known_items = set(static["items"]) | set(static["augments"])
|
known_items = set(static["items"]) | set(static["augments"])
|
||||||
|
set_prefix = f"TFT{static['meta']['set']}_"
|
||||||
for row in rows:
|
for row in rows:
|
||||||
for u in json.loads(row[8]):
|
for u in json.loads(row[8]):
|
||||||
if u["character_id"] not in static["units"]:
|
api = u["character_id"]
|
||||||
unknown[f"unit:{u['character_id']}"] += 1
|
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", []):
|
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
|
unknown[f"item:{item}"] += 1
|
||||||
for t in json.loads(row[9]):
|
for t in json.loads(row[9]):
|
||||||
if t["name"] not in static["traits"]:
|
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"]
|
set_number = artifact["meta"]["set"]
|
||||||
where = "WHERE set_number = ?"
|
where = "WHERE set_number = ?"
|
||||||
if holdout_only:
|
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(
|
rows = conn.execute(
|
||||||
f"SELECT match_id, placement, units, augments FROM endboards {where}",
|
f"SELECT match_id, placement, units, augments FROM endboards {where}",
|
||||||
(set_number,),
|
(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:
|
def learn_from_db(conn, set_number: int, exclude_holdout: bool = True) -> dict:
|
||||||
where = "WHERE set_number = ?"
|
where = "WHERE set_number = ?"
|
||||||
if exclude_holdout:
|
if exclude_holdout:
|
||||||
where += " AND rowid % 5 != 0"
|
where += " AND substr(match_id, -1) NOT IN ('0', '5')"
|
||||||
rows = conn.execute(
|
rows = conn.execute(
|
||||||
f"SELECT placement, units, traits, augments FROM endboards {where}",
|
f"SELECT placement, units, traits, augments FROM endboards {where}",
|
||||||
(set_number,),
|
(set_number,),
|
||||||
|
|||||||
Reference in New Issue
Block a user