File size: 3,699 Bytes
62f41ca
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
"""
Scoring wrapper: takes a filtered DF and tunable weights, returns scored rows.
Reuses the existing functions in scouting_score.py.
"""

import sys
from functools import lru_cache
from pathlib import Path

import pandas as pd

# Allow importing scouting_score.py from the parent directory in dev. In the Docker
# image, scouting_score.py is copied into /app so this is a no-op.
_PARENT = Path(__file__).resolve().parent.parent
if str(_PARENT) not in sys.path:
    sys.path.insert(0, str(_PARENT))

import scouting_score as ss

APP_DIR = Path(__file__).parent

# weights xlsx path — searched in DATA_DIR first, fallback to project root
def _weights_path():
    import os
    data_dir = Path(os.environ.get('DATA_DIR', APP_DIR.parent / 'data' / 'clean'))
    candidates = [
        data_dir / 'PESOS_POR_VARIABLE.xlsx',
        data_dir / 'PESOS POR VARIABLE (BLOQUES).xlsx',
        APP_DIR.parent / 'PESOS POR VARIABLE (BLOQUES).xlsx',
    ]
    for c in candidates:
        if c.exists():
            return c
    raise FileNotFoundError(f'weights xlsx not found; tried: {candidates}')


@lru_cache(maxsize=1)
def get_block_weights():
    return ss.load_weights(_weights_path())


def score_with_weights(df: pd.DataFrame,
                       perf_weight=0.6, prof_weight=0.4,
                       w_age=0.35, w_eu=0.25, w_league=0.20, w_mv=0.20):
    if df.empty:
        return df.assign(performance_score=pd.NA, profile_score=pd.NA,
                         scouting_score=pd.NA, percentile_rank_in_position=pd.NA)

    weights = get_block_weights()
    df = df.copy()
    df['mapped_position'] = df['Posicion'].map(ss.POSITION_MAP)
    df = df[df['mapped_position'].notna()].copy()

    df = ss.compute_percentile_ranks(df, weights)
    df = ss.compute_performance_scores(df, weights)

    def age_factor(a):
        try:
            a = float(a)
        except (TypeError, ValueError):
            return None
        if pd.isna(a):
            return None
        if a < 23:
            return 1.0
        if a <= 25:
            return 0.5
        return 0.0

    df['age_factor'] = df['_age_num'].apply(age_factor)
    df['eu_nationality_factor'] = df['_eu'].astype(float)

    def mv_factor(mv):
        if mv is None or pd.isna(mv):
            return None
        if mv < 3:
            return 1.0
        if mv <= 5:
            return 0.5
        return -1
    df['market_value_factor'] = df['mv_millions'].apply(mv_factor)
    df['league_tier_factor'] = df['Competencia'].map(ss.LEAGUE_TIERS).fillna(ss.DEFAULT_LEAGUE_TIER)

    weights_p = {'age': w_age, 'eu_nationality': w_eu, 'league_tier': w_league, 'market_value': w_mv}

    def profile_score(row):
        comps, w_total = [], 0
        if row['age_factor'] is not None:
            comps.append(weights_p['age'] * row['age_factor']); w_total += weights_p['age']
        comps.append(weights_p['eu_nationality'] * row['eu_nationality_factor']); w_total += weights_p['eu_nationality']
        comps.append(weights_p['league_tier'] * row['league_tier_factor']); w_total += weights_p['league_tier']
        if row['market_value_factor'] is not None and row['market_value_factor'] >= 0:
            comps.append(weights_p['market_value'] * row['market_value_factor']); w_total += weights_p['market_value']
        return sum(comps) / w_total if w_total else 0

    df['profile_score'] = df.apply(profile_score, axis=1)
    df['scouting_score'] = (perf_weight * df['performance_score'].fillna(0)
                            + prof_weight * df['profile_score'].fillna(0))
    df['percentile_rank_in_position'] = (
        df.groupby(['mapped_position', 'Temporada'])['performance_score'].rank(pct=True)
    )
    return df