124 lines
4.4 KiB
Python
124 lines
4.4 KiB
Python
|
|
from catboost import CatBoostClassifier
|
|||
|
|
import pandas as pd
|
|||
|
|
import numpy as np
|
|||
|
|
from typing import Dict, Any
|
|||
|
|
|
|||
|
|
# Загрузка модели с игроками
|
|||
|
|
modelWithPlayers = CatBoostClassifier()
|
|||
|
|
modelWithPlayers.load_model("artifacts/model_with_players.cbm")
|
|||
|
|
|
|||
|
|
# Загрузка порядка фич
|
|||
|
|
def load_feature_order(path: str) -> list:
|
|||
|
|
fo = pd.read_csv(path)
|
|||
|
|
first_col = fo.columns[0]
|
|||
|
|
return fo[first_col].tolist()
|
|||
|
|
|
|||
|
|
FEATURE_ORDER_WITH_PLAYERS = load_feature_order("artifacts/feature_order_with_players.csv")
|
|||
|
|
|
|||
|
|
def build_player_features(payload: Dict[str, Any]) -> pd.DataFrame:
|
|||
|
|
"""
|
|||
|
|
Создаёт бинарные признаки для модели с игроками.
|
|||
|
|
|
|||
|
|
Признаки:
|
|||
|
|
- radiant_p{player_id}_h{hero_id}_pos{position}
|
|||
|
|
- radiant_p{player_id}_h{hero_id}
|
|||
|
|
- radiant_p{player_id}_pos{position}
|
|||
|
|
(аналогично для dire)
|
|||
|
|
"""
|
|||
|
|
features = {}
|
|||
|
|
|
|||
|
|
# Инициализируем все признаки нулями
|
|||
|
|
for feat in FEATURE_ORDER_WITH_PLAYERS:
|
|||
|
|
features[feat] = 0
|
|||
|
|
|
|||
|
|
# Radiant: игроки + герои + позиции
|
|||
|
|
for i in range(1, 6):
|
|||
|
|
hero_id = int(payload.get(f"r_h{i}", -1))
|
|||
|
|
player_id = int(payload.get(f"r_p{i}", -1))
|
|||
|
|
position = int(payload.get(f"rp_h{i}", -1))
|
|||
|
|
|
|||
|
|
# Признак: игрок + герой + позиция
|
|||
|
|
if player_id > 0 and hero_id >= 0 and position >= 0:
|
|||
|
|
feature_name = f"radiant_p{player_id}_h{hero_id}_pos{position}"
|
|||
|
|
if feature_name in features:
|
|||
|
|
features[feature_name] = 1
|
|||
|
|
|
|||
|
|
# Признак: только игрок + герой
|
|||
|
|
if player_id > 0 and hero_id >= 0:
|
|||
|
|
feature_name = f"radiant_p{player_id}_h{hero_id}"
|
|||
|
|
if feature_name in features:
|
|||
|
|
features[feature_name] = 1
|
|||
|
|
|
|||
|
|
# Признак: только игрок + позиция
|
|||
|
|
if player_id > 0 and position >= 0:
|
|||
|
|
feature_name = f"radiant_p{player_id}_pos{position}"
|
|||
|
|
if feature_name in features:
|
|||
|
|
features[feature_name] = 1
|
|||
|
|
|
|||
|
|
# Dire: игроки + герои + позиции
|
|||
|
|
for i in range(1, 6):
|
|||
|
|
hero_id = int(payload.get(f"d_h{i}", -1))
|
|||
|
|
player_id = int(payload.get(f"d_p{i}", -1))
|
|||
|
|
position = int(payload.get(f"dp_h{i}", -1))
|
|||
|
|
|
|||
|
|
# Признак: игрок + герой + позиция
|
|||
|
|
if player_id > 0 and hero_id >= 0 and position >= 0:
|
|||
|
|
feature_name = f"dire_p{player_id}_h{hero_id}_pos{position}"
|
|||
|
|
if feature_name in features:
|
|||
|
|
features[feature_name] = 1
|
|||
|
|
|
|||
|
|
# Признак: только игрок + герой
|
|||
|
|
if player_id > 0 and hero_id >= 0:
|
|||
|
|
feature_name = f"dire_p{player_id}_h{hero_id}"
|
|||
|
|
if feature_name in features:
|
|||
|
|
features[feature_name] = 1
|
|||
|
|
|
|||
|
|
# Признак: только игрок + позиция
|
|||
|
|
if player_id > 0 and position >= 0:
|
|||
|
|
feature_name = f"dire_p{player_id}_pos{position}"
|
|||
|
|
if feature_name in features:
|
|||
|
|
features[feature_name] = 1
|
|||
|
|
|
|||
|
|
# Создаём DataFrame с одной строкой в правильном порядке
|
|||
|
|
df = pd.DataFrame([features], columns=FEATURE_ORDER_WITH_PLAYERS)
|
|||
|
|
|
|||
|
|
return df
|
|||
|
|
|
|||
|
|
def predict_with_players(payload: Dict[str, Any]) -> Dict[str, float]:
|
|||
|
|
"""
|
|||
|
|
Делает предсказание с использованием модели с игроками.
|
|||
|
|
|
|||
|
|
Возвращает:
|
|||
|
|
{
|
|||
|
|
"radiant_win": вероятность победы Radiant (0-100),
|
|||
|
|
"dire_win": вероятность победы Dire (0-100)
|
|||
|
|
}
|
|||
|
|
"""
|
|||
|
|
# Проверяем, есть ли хотя бы один игрок в payload
|
|||
|
|
has_players = False
|
|||
|
|
for i in range(1, 6):
|
|||
|
|
if payload.get(f"r_p{i}", -1) > 0 or payload.get(f"d_p{i}", -1) > 0:
|
|||
|
|
has_players = True
|
|||
|
|
break
|
|||
|
|
|
|||
|
|
# Если нет игроков, возвращаем 50/50
|
|||
|
|
if not has_players:
|
|||
|
|
return {
|
|||
|
|
"radiant_win": 50,
|
|||
|
|
"dire_win": 50
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
# Создаём признаки
|
|||
|
|
X = build_player_features(payload)
|
|||
|
|
|
|||
|
|
# Предсказание
|
|||
|
|
proba = modelWithPlayers.predict_proba(X)[0, 1]
|
|||
|
|
|
|||
|
|
radiant_win = round(float(np.clip(proba * 100.0, 0.0, 100.0)))
|
|||
|
|
dire_win = 100 - radiant_win
|
|||
|
|
|
|||
|
|
return {
|
|||
|
|
"radiant_win": radiant_win,
|
|||
|
|
"dire_win": dire_win
|
|||
|
|
}
|