spforge 0.8.36__py3-none-any.whl → 0.8.37__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.

@@ -86,8 +86,8 @@ class PerformanceManager(BaseEstimator, TransformerMixin):
86
86
  transformer_names: list[TransformerName] | None = None,
87
87
  custom_transformers: list[NarwhalsFeatureTransformer] | None = None,
88
88
  prefix: str = "performance__",
89
- min_value: float = -0.02,
90
- max_value: float = 1.02,
89
+ min_value: float = 0.0,
90
+ max_value: float = 1.0,
91
91
  zero_inflation_threshold: float = 0.15,
92
92
  ):
93
93
  self.features = features
@@ -209,8 +209,8 @@ class PerformanceWeightsManager(PerformanceManager):
209
209
  transformer_names: (
210
210
  list[Literal["partial_standard_scaler", "symmetric", "min_max"]] | None
211
211
  ) = None,
212
- max_value: float = 1.02,
213
- min_value: float = -0.02,
212
+ max_value: float = 1.0,
213
+ min_value: float = 0.0,
214
214
  prefix: str = "performance__",
215
215
  return_all_features: bool = False,
216
216
  zero_inflation_threshold: float = 0.15,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: spforge
3
- Version: 0.8.36
3
+ Version: 0.8.37
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
@@ -47,7 +47,7 @@ spforge/hyperparameter_tuning/__init__.py,sha256=Vcl8rVlJ7M708iPgqe4XxpZWgJKGux0
47
47
  spforge/hyperparameter_tuning/_default_search_spaces.py,sha256=SjwXLpvYIu_JY8uPRHeL5Kgp1aa0slWDz8qsKDaohWQ,8020
48
48
  spforge/hyperparameter_tuning/_tuner.py,sha256=M79q3saM6r0UZJsRUUgfdDr-3Qii-F2-wuSAZLFtZDo,19246
49
49
  spforge/performance_transformers/__init__.py,sha256=J-5olqi1M_BUj3sN1NqAz9s28XAbuKK9M9xHq7IGlQU,482
50
- spforge/performance_transformers/_performance_manager.py,sha256=tR_4laGoC_KFRaw3Gy0TMI-r5gnicDmvmxPEgAvl4E0,12031
50
+ spforge/performance_transformers/_performance_manager.py,sha256=_qXqj8aaVJyTuUXrZxbOSANwL5iO3Rd1yz9WBwYBTMA,12025
51
51
  spforge/performance_transformers/_performances_transformers.py,sha256=ZjkFDXoEe5fURpN-dNkrgFXpHEg4aFCWdBDnPyLtgkM,18368
52
52
  spforge/ratings/__init__.py,sha256=OZVH2Lo6END3n1X8qi4QcyAPlThIwAYwVKCiIuOQSQU,576
53
53
  spforge/ratings/_base.py,sha256=Z-VVXWmnzR0O7o2_Q2x2ru_3uiTMpWqKDGQaNBJxCMA,14927
@@ -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.36.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
74
+ spforge-0.8.37.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
@@ -92,7 +92,7 @@ tests/feature_generator/test_rolling_mean_days.py,sha256=EyOvdJDnmgPfe13uQBOkwo7
92
92
  tests/feature_generator/test_rolling_window.py,sha256=_o9oljcAIZ14iI7e8WFeAsfXxILnyqBffit21HOvII4,24378
93
93
  tests/hyperparameter_tuning/test_estimator_tuner.py,sha256=iewME41d6LR2aQ0OtohGFtN_ocJUwTeqvs6L0QDmfG4,4413
94
94
  tests/hyperparameter_tuning/test_rating_tuner.py,sha256=usjC2ioO_yWRjjNAlRTyMVYheOrCi0kKocmHQHdTmpM,18699
95
- tests/performance_transformers/test_performance_manager.py,sha256=fVXxSujE3OKE7tIRJjN5dWCLj9pkeXbuL6Zf0WrM0ZA,15698
95
+ tests/performance_transformers/test_performance_manager.py,sha256=Ja2TWq1vGoAqBSSeAWZ26drwEnsF6TmMmpQ0nsMRU_4,19163
96
96
  tests/performance_transformers/test_performances_transformers.py,sha256=HnW7GKQ6B0ova6Zy0lKbEpA6peZGFE4oi9Th6r7RnG0,18949
97
97
  tests/ratings/test_player_rating_generator.py,sha256=1Pkx0H8xJMTeLc2Fu9zJcoDpBWiY2zCVSxuBFJk2uEs,110717
98
98
  tests/ratings/test_player_rating_no_mutation.py,sha256=GzO3Hl__5K68DS3uRLefwnbcTJOvBM7cZqww4M21UZM,8493
@@ -108,7 +108,7 @@ tests/transformers/test_other_transformer.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRk
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.36.dist-info/METADATA,sha256=HxggFJqUQNu2SdjRwCHclWb3_5t1z5Ensjg1AXiVtXU,20048
112
- spforge-0.8.36.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
113
- spforge-0.8.36.dist-info/top_level.txt,sha256=6UW2M5a7WKOeaAi900qQmRKNj5-HZzE8-eUD9Y9LTq0,23
114
- spforge-0.8.36.dist-info/RECORD,,
111
+ spforge-0.8.37.dist-info/METADATA,sha256=fLFkSzIsDRPKRpyJ-H126XcKG_NAUyXmJNGDNrogq4s,20048
112
+ spforge-0.8.37.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
113
+ spforge-0.8.37.dist-info/top_level.txt,sha256=6UW2M5a7WKOeaAi900qQmRKNj5-HZzE8-eUD9Y9LTq0,23
114
+ spforge-0.8.37.dist-info/RECORD,,
@@ -203,8 +203,8 @@ def test_performance_manager_aliases_unprefixed_input_when_transformer_expects_p
203
203
  transformer_names=[],
204
204
  prefix="performance__",
205
205
  performance_column="weighted_performance",
206
- min_value=-0.02,
207
- max_value=1.02,
206
+ min_value=0.0,
207
+ max_value=1.0,
208
208
  )
209
209
 
210
210
  pm.fit(df)
@@ -434,3 +434,99 @@ class TestZeroInflationHandling:
434
434
 
435
435
  # Should have switched to quantile scaler
436
436
  assert manager._using_quantile_scaler is True
437
+
438
+
439
+ class TestAutoScalePerformanceBounds:
440
+ """Tests for ensuring scaled performance stays within [0, 1] bounds."""
441
+
442
+ @pytest.mark.parametrize("frame", ["pd", "pl"])
443
+ def test_auto_scale_performance_preserves_non_negative(self, frame):
444
+ """Scaled performance should be non-negative when input is non-negative."""
445
+ np.random.seed(42)
446
+ # Create data similar to free throw % - centered around 0.77 with some zeros
447
+ n = 400
448
+ data = []
449
+ for _ in range(n):
450
+ if np.random.random() < 0.25: # 25% zeros (missed all free throws)
451
+ data.append(0.0)
452
+ else:
453
+ # Values between 0.6 and 1.0, centered around 0.77
454
+ data.append(np.clip(np.random.normal(0.77, 0.15), 0.0, 1.0))
455
+
456
+ df = _make_native_df(frame, {"x": data})
457
+
458
+ pm = PerformanceManager(
459
+ features=["x"],
460
+ transformer_names=["symmetric", "partial_standard_scaler", "min_max"],
461
+ prefix="performance__",
462
+ performance_column="perf",
463
+ )
464
+
465
+ result = pm.fit_transform(df)
466
+ result_nw = nw.from_native(result)
467
+ scaled = result_nw["performance__perf"].to_numpy()
468
+
469
+ assert np.all(scaled >= 0), f"Scaled performance should not be negative, min was {scaled.min()}"
470
+
471
+ @pytest.mark.parametrize("frame", ["pd", "pl"])
472
+ def test_auto_scale_performance_output_range(self, frame):
473
+ """Scaled performance should be in [0, 1] when input is in [0, 1]."""
474
+ np.random.seed(42)
475
+ # Create data with performance in [0, 1] but skewed distribution
476
+ n = 400
477
+ data = []
478
+ for _ in range(n):
479
+ if np.random.random() < 0.25:
480
+ data.append(0.0)
481
+ else:
482
+ data.append(np.clip(np.random.normal(0.77, 0.15), 0.0, 1.0))
483
+
484
+ df = _make_native_df(frame, {"x": data})
485
+
486
+ pm = PerformanceManager(
487
+ features=["x"],
488
+ transformer_names=["symmetric", "partial_standard_scaler", "min_max"],
489
+ prefix="performance__",
490
+ performance_column="perf",
491
+ )
492
+
493
+ result = pm.fit_transform(df)
494
+ result_nw = nw.from_native(result)
495
+ scaled = result_nw["performance__perf"].to_numpy()
496
+
497
+ assert np.all(scaled >= 0.0), f"Scaled min should be >= 0, got {scaled.min()}"
498
+ assert np.all(scaled <= 1.0), f"Scaled max should be <= 1, got {scaled.max()}"
499
+
500
+ @pytest.mark.parametrize("frame", ["pd", "pl"])
501
+ def test_default_bounds_are_unit_interval(self, frame):
502
+ """Test that default bounds are [0, 1]."""
503
+ pm = PerformanceManager(
504
+ features=["x"],
505
+ transformer_names=[],
506
+ prefix="",
507
+ performance_column="x",
508
+ )
509
+
510
+ assert pm.min_value == 0.0
511
+ assert pm.max_value == 1.0
512
+
513
+ @pytest.mark.parametrize("frame", ["pd", "pl"])
514
+ def test_custom_bounds_still_work(self, frame):
515
+ """Test that custom bounds can still be specified."""
516
+ df = _make_native_df(frame, {"x": [-10.0, 0.5, 10.0]})
517
+
518
+ pm = PerformanceManager(
519
+ features=["x"],
520
+ transformer_names=[],
521
+ prefix="",
522
+ performance_column="x",
523
+ min_value=-0.5,
524
+ max_value=1.5,
525
+ )
526
+
527
+ result = pm.fit_transform(df)
528
+ result_nw = nw.from_native(result)
529
+ scaled = result_nw["x"].to_numpy()
530
+
531
+ assert scaled.min() >= -0.5
532
+ assert scaled.max() <= 1.5