spforge 0.8.31__py3-none-any.whl → 0.8.33__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of spforge might be problematic. Click here for more details.
- spforge/ratings/_player_rating.py +2 -2
- spforge/scorer/_score.py +2 -4
- {spforge-0.8.31.dist-info → spforge-0.8.33.dist-info}/METADATA +1 -1
- {spforge-0.8.31.dist-info → spforge-0.8.33.dist-info}/RECORD +9 -9
- tests/ratings/test_player_rating_generator.py +35 -0
- tests/scorer/test_scorer_name.py +13 -0
- {spforge-0.8.31.dist-info → spforge-0.8.33.dist-info}/WHEEL +0 -0
- {spforge-0.8.31.dist-info → spforge-0.8.33.dist-info}/licenses/LICENSE +0 -0
- {spforge-0.8.31.dist-info → spforge-0.8.33.dist-info}/top_level.txt +0 -0
|
@@ -595,7 +595,7 @@ class PlayerRatingGenerator(RatingGenerator):
|
|
|
595
595
|
* float(pre_player.match_performance.participation_weight)
|
|
596
596
|
)
|
|
597
597
|
|
|
598
|
-
if team1_def_perf is None:
|
|
598
|
+
if team1_def_perf is None or (not self.use_off_def_split and perf_value is None):
|
|
599
599
|
def_change = 0.0
|
|
600
600
|
else:
|
|
601
601
|
def_perf = float(team1_def_perf)
|
|
@@ -689,7 +689,7 @@ class PlayerRatingGenerator(RatingGenerator):
|
|
|
689
689
|
* float(pre_player.match_performance.participation_weight)
|
|
690
690
|
)
|
|
691
691
|
|
|
692
|
-
if team2_def_perf is None:
|
|
692
|
+
if team2_def_perf is None or (not self.use_off_def_split and perf_value is None):
|
|
693
693
|
def_change = 0.0
|
|
694
694
|
else:
|
|
695
695
|
def_perf = float(team2_def_perf)
|
spforge/scorer/_score.py
CHANGED
|
@@ -388,16 +388,14 @@ class BaseScorer(ABC):
|
|
|
388
388
|
return re.sub(r'[^a-zA-Z0-9_]', '_', name)
|
|
389
389
|
|
|
390
390
|
def _count_user_filters(self) -> int:
|
|
391
|
-
"""Count filters excluding
|
|
391
|
+
"""Count filters excluding any filter on validation column."""
|
|
392
392
|
if not self.filters:
|
|
393
393
|
return 0
|
|
394
394
|
if self.validation_column is None:
|
|
395
395
|
return len(self.filters)
|
|
396
396
|
count = 0
|
|
397
397
|
for f in self.filters:
|
|
398
|
-
if
|
|
399
|
-
f.operator == Operator.EQUALS and
|
|
400
|
-
f.value == 1):
|
|
398
|
+
if f.column_name != self.validation_column:
|
|
401
399
|
count += 1
|
|
402
400
|
return count
|
|
403
401
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: spforge
|
|
3
|
-
Version: 0.8.
|
|
3
|
+
Version: 0.8.33
|
|
4
4
|
Summary: A flexible framework for generating features, ratings, and building machine learning or other models for training and inference on sports data.
|
|
5
5
|
Author-email: Mathias Holmstrøm <mathiasholmstom@gmail.com>
|
|
6
6
|
License: See LICENSE file
|
|
@@ -51,7 +51,7 @@ spforge/performance_transformers/_performance_manager.py,sha256=WmjmlMEnq7y75MiI
|
|
|
51
51
|
spforge/performance_transformers/_performances_transformers.py,sha256=0lxuWjAfWBRXRgQsNJHjw3P-nlTtHBu4_bOVdoy7hq4,15536
|
|
52
52
|
spforge/ratings/__init__.py,sha256=OZVH2Lo6END3n1X8qi4QcyAPlThIwAYwVKCiIuOQSQU,576
|
|
53
53
|
spforge/ratings/_base.py,sha256=ne4BRrYFPqMirdFPVnyDN44wjFQwOQgWoUXu_59xgWE,14687
|
|
54
|
-
spforge/ratings/_player_rating.py,sha256=
|
|
54
|
+
spforge/ratings/_player_rating.py,sha256=Ii1HNz0tC25dxZy9B2b_ULZVNwExNvdyIGw_1gRIeko,67163
|
|
55
55
|
spforge/ratings/_team_rating.py,sha256=3m90-R2zW0k5EHwjw-83Hacz91fGmxW1LQ8ZUGHlgt4,24970
|
|
56
56
|
spforge/ratings/enums.py,sha256=s7z_RcZS6Nlgfa_6tasO8_IABZJwywexe7sep9DJBgo,1739
|
|
57
57
|
spforge/ratings/league_identifier.py,sha256=_KDUKOwoNU6RNFKE5jju4eYFGVNGBdJsv5mhNvMakfc,6019
|
|
@@ -62,7 +62,7 @@ spforge/ratings/team_performance_predictor.py,sha256=ThQOmYQUqKBB46ONYHOMM2arXFH
|
|
|
62
62
|
spforge/ratings/team_start_rating_generator.py,sha256=vK-_m8KwcHopchch_lKNHSGLiiNm5q9Lenm0d1cP_po,5110
|
|
63
63
|
spforge/ratings/utils.py,sha256=_zFemqz2jJkH8rn2EZpDt8N6FELUmYp9qCnPzRtOIGU,4497
|
|
64
64
|
spforge/scorer/__init__.py,sha256=wj8PCvYIl6742Xwmt86c3oy6iqE8Ss-OpwHud6kd9IY,256
|
|
65
|
-
spforge/scorer/_score.py,sha256=
|
|
65
|
+
spforge/scorer/_score.py,sha256=DOl3wlHH0IlQelQA5CaNAfVtJhc544ZO5l-1mEno7nA,65276
|
|
66
66
|
spforge/transformers/__init__.py,sha256=IPCsMcsgBqG52d0ttATLCY4HvFCQZddExlLt74U-zuI,390
|
|
67
67
|
spforge/transformers/_base.py,sha256=-smr_McQF9bYxM5-Agx6h7Xv_fhZzPfpAdQV-qK18bs,1134
|
|
68
68
|
spforge/transformers/_net_over_predicted.py,sha256=5dC8pvA1DNO0yXPSgJSMGU8zAHi-maUELm7FqFQVo-U,2321
|
|
@@ -71,7 +71,7 @@ spforge/transformers/_other_transformer.py,sha256=w2a7Wnki3vJe4GAkSa4kealw0GILIo
|
|
|
71
71
|
spforge/transformers/_predictor.py,sha256=2sE6gfVrilXzPVcBurSrtqHw33v2ljygQcEYXt9LhZc,3119
|
|
72
72
|
spforge/transformers/_simple_transformer.py,sha256=zGUFNQYMeoDSa2CoQejQNiNmKCBN5amWTvyOchiUHj0,5660
|
|
73
73
|
spforge/transformers/_team_ratio_predictor.py,sha256=g8_bR53Yyv0iNCtol1O9bgJSeZcIco_AfbQuUxQJkeY,6884
|
|
74
|
-
spforge-0.8.
|
|
74
|
+
spforge-0.8.33.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
75
75
|
tests/test_autopipeline.py,sha256=7cNAn-nmGolfyfk3THh9IKcHZfRA-pLYC_xAyMg-No4,26863
|
|
76
76
|
tests/test_autopipeline_context.py,sha256=IuRUY4IA6uMObvbl2pXSaXO2_tl3qX6wEbTZY0dkTMI,1240
|
|
77
77
|
tests/test_feature_generator_pipeline.py,sha256=CK0zVL8PfTncy3RmG9i-YpgwjOIV7yJhV7Q44tbetI8,19020
|
|
@@ -94,21 +94,21 @@ tests/hyperparameter_tuning/test_estimator_tuner.py,sha256=iewME41d6LR2aQ0OtohGF
|
|
|
94
94
|
tests/hyperparameter_tuning/test_rating_tuner.py,sha256=usjC2ioO_yWRjjNAlRTyMVYheOrCi0kKocmHQHdTmpM,18699
|
|
95
95
|
tests/performance_transformers/test_performance_manager.py,sha256=gjuuV_hb27kCo_kUecPKG3Cbot2Gqis1W3kw2A4ovS4,10690
|
|
96
96
|
tests/performance_transformers/test_performances_transformers.py,sha256=A-tGiCx7kXrj1cVj03Bc7prOeZ1_Ryz8YFx9uj3eK6w,11064
|
|
97
|
-
tests/ratings/test_player_rating_generator.py,sha256=
|
|
97
|
+
tests/ratings/test_player_rating_generator.py,sha256=9iepzvjlAlye-CkrEX5GT6Pf4Bf4qi_uDwB6Wamo1JY,104641
|
|
98
98
|
tests/ratings/test_player_rating_no_mutation.py,sha256=GzO3Hl__5K68DS3uRLefwnbcTJOvBM7cZqww4M21UZM,8493
|
|
99
99
|
tests/ratings/test_ratings_property.py,sha256=ckyfGILXa4tfQvsgyXEzBDNr2DUmHwFRV13N60w66iE,6561
|
|
100
100
|
tests/ratings/test_team_rating_generator.py,sha256=SqQcfckNmJJc99feCdnmkNYDape-p69e92Dp8Vzpu2w,101156
|
|
101
101
|
tests/ratings/test_utils_scaled_weights.py,sha256=iHxe6ZDUB_I2B6HT0xTGqXBkl7gRlqVV0e_7Lwun5po,4988
|
|
102
102
|
tests/scorer/test_score.py,sha256=rw3xJs6xqWVpalVMUQz557m2JYGR7PmhrsjfTex0b0c,79121
|
|
103
103
|
tests/scorer/test_score_aggregation_granularity.py,sha256=O5TRlG9UE4NBpF0tL_ywZKDmkMIorwrxgTegQ75Tr7A,15871
|
|
104
|
-
tests/scorer/test_scorer_name.py,sha256=
|
|
104
|
+
tests/scorer/test_scorer_name.py,sha256=lijr8vuHkieVmu_m3zcZril7rG5ByIZ-vSJq5QJFIss,10862
|
|
105
105
|
tests/transformers/test_estimator_transformer_context.py,sha256=5GOHbuWCWBMFwwOTJOuD4oNDsv-qDR0OxNZYGGuMdag,1819
|
|
106
106
|
tests/transformers/test_net_over_predicted.py,sha256=vh7O1iRRPf4vcW9aLhOMAOyatfM5ZnLsQBKNAYsR3SU,3363
|
|
107
107
|
tests/transformers/test_other_transformer.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
108
108
|
tests/transformers/test_predictor_transformer.py,sha256=N1aBYLjN3ldpYZLwjih_gTFYSMitrZu-PNK78W6RHaQ,6877
|
|
109
109
|
tests/transformers/test_simple_transformer.py,sha256=wWR0qjLb_uS4HXrJgGdiqugOY1X7kwd1_OPS02IT2b8,4676
|
|
110
110
|
tests/transformers/test_team_ratio_predictor.py,sha256=fOUP_JvNJi-3kom3ZOs1EdG0I6Z8hpLpYKNHu1eWtOw,8562
|
|
111
|
-
spforge-0.8.
|
|
112
|
-
spforge-0.8.
|
|
113
|
-
spforge-0.8.
|
|
114
|
-
spforge-0.8.
|
|
111
|
+
spforge-0.8.33.dist-info/METADATA,sha256=LH22MH7XYeFTROBWPYVVHWyYRSwMYGozGMCtaJdkLgg,20048
|
|
112
|
+
spforge-0.8.33.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
113
|
+
spforge-0.8.33.dist-info/top_level.txt,sha256=6UW2M5a7WKOeaAi900qQmRKNj5-HZzE8-eUD9Y9LTq0,23
|
|
114
|
+
spforge-0.8.33.dist-info/RECORD,,
|
|
@@ -2874,3 +2874,38 @@ def test_defense_participation_weight_backwards_compatibility(base_cn, library):
|
|
|
2874
2874
|
assert result is not None
|
|
2875
2875
|
assert len(gen._player_off_ratings) > 0
|
|
2876
2876
|
assert len(gen._player_def_ratings) > 0
|
|
2877
|
+
|
|
2878
|
+
|
|
2879
|
+
def test_fit_transform_null_perf_with_use_off_def_split_false__no_crash(base_cn):
|
|
2880
|
+
"""
|
|
2881
|
+
Regression test: null performance with use_off_def_split=False should not crash.
|
|
2882
|
+
|
|
2883
|
+
Bug: When use_off_def_split=False and a player has null performance:
|
|
2884
|
+
- Line 598 checks `if team1_def_perf is None` (team-level avg, not None if any played)
|
|
2885
|
+
- Line 605 does `def_perf = float(perf_value)` where perf_value is None
|
|
2886
|
+
- Crash: TypeError: float() argument must be a string or a number, not 'NoneType'
|
|
2887
|
+
|
|
2888
|
+
Fix: Check `if team1_def_perf is None or perf_value is None` to skip def update
|
|
2889
|
+
for players who didn't play (null performance means no rating update).
|
|
2890
|
+
"""
|
|
2891
|
+
df = pl.DataFrame(
|
|
2892
|
+
{
|
|
2893
|
+
"pid": ["P1", "P2", "P3", "P4", "P1", "P2", "P3", "P4"],
|
|
2894
|
+
"tid": ["T1", "T1", "T2", "T2", "T1", "T1", "T2", "T2"],
|
|
2895
|
+
"mid": ["M1", "M1", "M1", "M1", "M2", "M2", "M2", "M2"],
|
|
2896
|
+
"dt": ["2024-01-01"] * 4 + ["2024-01-02"] * 4,
|
|
2897
|
+
"perf": [0.6, 0.4, 0.5, 0.5, None, 0.6, 0.5, 0.5], # P1 null in M2
|
|
2898
|
+
"pw": [1.0] * 8,
|
|
2899
|
+
}
|
|
2900
|
+
)
|
|
2901
|
+
|
|
2902
|
+
gen = PlayerRatingGenerator(
|
|
2903
|
+
performance_column="perf",
|
|
2904
|
+
column_names=base_cn,
|
|
2905
|
+
use_off_def_split=False, # This triggers the buggy code path
|
|
2906
|
+
)
|
|
2907
|
+
|
|
2908
|
+
# Should not crash - before fix this raises:
|
|
2909
|
+
# TypeError: float() argument must be a string or a number, not 'NoneType'
|
|
2910
|
+
result = gen.fit_transform(df)
|
|
2911
|
+
assert result is not None
|
tests/scorer/test_scorer_name.py
CHANGED
|
@@ -123,6 +123,19 @@ class TestScorerNameProperty:
|
|
|
123
123
|
# Validation filter auto-added but not counted
|
|
124
124
|
assert scorer.name == "mean_bias_scorer_yards"
|
|
125
125
|
|
|
126
|
+
def test_any_filter_on_validation_column_excluded_from_name(self):
|
|
127
|
+
scorer = MeanBiasScorer(
|
|
128
|
+
target="yards",
|
|
129
|
+
pred_column="pred",
|
|
130
|
+
validation_column="is_valid",
|
|
131
|
+
filters=[
|
|
132
|
+
Filter("is_valid", 0, Operator.EQUALS),
|
|
133
|
+
Filter("minutes", 10, Operator.GREATER_THAN),
|
|
134
|
+
]
|
|
135
|
+
)
|
|
136
|
+
# Any filter on validation column should be excluded, not just value=1
|
|
137
|
+
assert scorer.name == "mean_bias_scorer_yards_filters:1"
|
|
138
|
+
|
|
126
139
|
def test_complex_configuration_all_components(self):
|
|
127
140
|
scorer = MeanBiasScorer(
|
|
128
141
|
target="yards",
|
|
File without changes
|
|
File without changes
|
|
File without changes
|