spforge 0.8.36__tar.gz → 0.8.37__tar.gz

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.

Files changed (120) hide show
  1. {spforge-0.8.36/spforge.egg-info → spforge-0.8.37}/PKG-INFO +1 -1
  2. {spforge-0.8.36 → spforge-0.8.37}/pyproject.toml +1 -1
  3. {spforge-0.8.36 → spforge-0.8.37}/spforge/performance_transformers/_performance_manager.py +4 -4
  4. {spforge-0.8.36 → spforge-0.8.37/spforge.egg-info}/PKG-INFO +1 -1
  5. {spforge-0.8.36 → spforge-0.8.37}/tests/performance_transformers/test_performance_manager.py +98 -2
  6. {spforge-0.8.36 → spforge-0.8.37}/LICENSE +0 -0
  7. {spforge-0.8.36 → spforge-0.8.37}/MANIFEST.in +0 -0
  8. {spforge-0.8.36 → spforge-0.8.37}/README.md +0 -0
  9. {spforge-0.8.36 → spforge-0.8.37}/examples/__init__.py +0 -0
  10. {spforge-0.8.36 → spforge-0.8.37}/examples/game_level_example.py +0 -0
  11. {spforge-0.8.36 → spforge-0.8.37}/examples/lol/__init__.py +0 -0
  12. {spforge-0.8.36 → spforge-0.8.37}/examples/lol/data/__init__.py +0 -0
  13. {spforge-0.8.36 → spforge-0.8.37}/examples/lol/data/subsample_lol_data.parquet +0 -0
  14. {spforge-0.8.36 → spforge-0.8.37}/examples/lol/data/utils.py +0 -0
  15. {spforge-0.8.36 → spforge-0.8.37}/examples/lol/pipeline_transformer_example.py +0 -0
  16. {spforge-0.8.36 → spforge-0.8.37}/examples/nba/__init__.py +0 -0
  17. {spforge-0.8.36 → spforge-0.8.37}/examples/nba/cross_validation_example.py +0 -0
  18. {spforge-0.8.36 → spforge-0.8.37}/examples/nba/data/__init__.py +0 -0
  19. {spforge-0.8.36 → spforge-0.8.37}/examples/nba/data/game_player_subsample.parquet +0 -0
  20. {spforge-0.8.36 → spforge-0.8.37}/examples/nba/data/utils.py +0 -0
  21. {spforge-0.8.36 → spforge-0.8.37}/examples/nba/feature_engineering_example.py +0 -0
  22. {spforge-0.8.36 → spforge-0.8.37}/examples/nba/game_winner_example.py +0 -0
  23. {spforge-0.8.36 → spforge-0.8.37}/examples/nba/predictor_transformers_example.py +0 -0
  24. {spforge-0.8.36 → spforge-0.8.37}/setup.cfg +0 -0
  25. {spforge-0.8.36 → spforge-0.8.37}/spforge/__init__.py +0 -0
  26. {spforge-0.8.36 → spforge-0.8.37}/spforge/autopipeline.py +0 -0
  27. {spforge-0.8.36 → spforge-0.8.37}/spforge/base_feature_generator.py +0 -0
  28. {spforge-0.8.36 → spforge-0.8.37}/spforge/cross_validator/__init__.py +0 -0
  29. {spforge-0.8.36 → spforge-0.8.37}/spforge/cross_validator/_base.py +0 -0
  30. {spforge-0.8.36 → spforge-0.8.37}/spforge/cross_validator/cross_validator.py +0 -0
  31. {spforge-0.8.36 → spforge-0.8.37}/spforge/data_structures.py +0 -0
  32. {spforge-0.8.36 → spforge-0.8.37}/spforge/distributions/__init__.py +0 -0
  33. {spforge-0.8.36 → spforge-0.8.37}/spforge/distributions/_negative_binomial_estimator.py +0 -0
  34. {spforge-0.8.36 → spforge-0.8.37}/spforge/distributions/_normal_distribution_predictor.py +0 -0
  35. {spforge-0.8.36 → spforge-0.8.37}/spforge/distributions/_student_t_distribution_estimator.py +0 -0
  36. {spforge-0.8.36 → spforge-0.8.37}/spforge/estimator/__init__.py +0 -0
  37. {spforge-0.8.36 → spforge-0.8.37}/spforge/estimator/_conditional_estimator.py +0 -0
  38. {spforge-0.8.36 → spforge-0.8.37}/spforge/estimator/_frequency_bucketing_classifier.py +0 -0
  39. {spforge-0.8.36 → spforge-0.8.37}/spforge/estimator/_granularity_estimator.py +0 -0
  40. {spforge-0.8.36 → spforge-0.8.37}/spforge/estimator/_group_by_estimator.py +0 -0
  41. {spforge-0.8.36 → spforge-0.8.37}/spforge/estimator/_ordinal_classifier.py +0 -0
  42. {spforge-0.8.36 → spforge-0.8.37}/spforge/estimator/_sklearn_enhancer_estimator.py +0 -0
  43. {spforge-0.8.36 → spforge-0.8.37}/spforge/feature_generator/__init__.py +0 -0
  44. {spforge-0.8.36 → spforge-0.8.37}/spforge/feature_generator/_base.py +0 -0
  45. {spforge-0.8.36 → spforge-0.8.37}/spforge/feature_generator/_lag.py +0 -0
  46. {spforge-0.8.36 → spforge-0.8.37}/spforge/feature_generator/_net_over_predicted.py +0 -0
  47. {spforge-0.8.36 → spforge-0.8.37}/spforge/feature_generator/_regressor_feature_generator.py +0 -0
  48. {spforge-0.8.36 → spforge-0.8.37}/spforge/feature_generator/_rolling_against_opponent.py +0 -0
  49. {spforge-0.8.36 → spforge-0.8.37}/spforge/feature_generator/_rolling_mean_binary.py +0 -0
  50. {spforge-0.8.36 → spforge-0.8.37}/spforge/feature_generator/_rolling_mean_days.py +0 -0
  51. {spforge-0.8.36 → spforge-0.8.37}/spforge/feature_generator/_rolling_window.py +0 -0
  52. {spforge-0.8.36 → spforge-0.8.37}/spforge/feature_generator/_utils.py +0 -0
  53. {spforge-0.8.36 → spforge-0.8.37}/spforge/features_generator_pipeline.py +0 -0
  54. {spforge-0.8.36 → spforge-0.8.37}/spforge/hyperparameter_tuning/__init__.py +0 -0
  55. {spforge-0.8.36 → spforge-0.8.37}/spforge/hyperparameter_tuning/_default_search_spaces.py +0 -0
  56. {spforge-0.8.36 → spforge-0.8.37}/spforge/hyperparameter_tuning/_tuner.py +0 -0
  57. {spforge-0.8.36 → spforge-0.8.37}/spforge/performance_transformers/__init__.py +0 -0
  58. {spforge-0.8.36 → spforge-0.8.37}/spforge/performance_transformers/_performances_transformers.py +0 -0
  59. {spforge-0.8.36 → spforge-0.8.37}/spforge/ratings/__init__.py +0 -0
  60. {spforge-0.8.36 → spforge-0.8.37}/spforge/ratings/_base.py +0 -0
  61. {spforge-0.8.36 → spforge-0.8.37}/spforge/ratings/_player_rating.py +0 -0
  62. {spforge-0.8.36 → spforge-0.8.37}/spforge/ratings/_team_rating.py +0 -0
  63. {spforge-0.8.36 → spforge-0.8.37}/spforge/ratings/enums.py +0 -0
  64. {spforge-0.8.36 → spforge-0.8.37}/spforge/ratings/league_identifier.py +0 -0
  65. {spforge-0.8.36 → spforge-0.8.37}/spforge/ratings/league_start_rating_optimizer.py +0 -0
  66. {spforge-0.8.36 → spforge-0.8.37}/spforge/ratings/player_performance_predictor.py +0 -0
  67. {spforge-0.8.36 → spforge-0.8.37}/spforge/ratings/start_rating_generator.py +0 -0
  68. {spforge-0.8.36 → spforge-0.8.37}/spforge/ratings/team_performance_predictor.py +0 -0
  69. {spforge-0.8.36 → spforge-0.8.37}/spforge/ratings/team_start_rating_generator.py +0 -0
  70. {spforge-0.8.36 → spforge-0.8.37}/spforge/ratings/utils.py +0 -0
  71. {spforge-0.8.36 → spforge-0.8.37}/spforge/scorer/__init__.py +0 -0
  72. {spforge-0.8.36 → spforge-0.8.37}/spforge/scorer/_score.py +0 -0
  73. {spforge-0.8.36 → spforge-0.8.37}/spforge/transformers/__init__.py +0 -0
  74. {spforge-0.8.36 → spforge-0.8.37}/spforge/transformers/_base.py +0 -0
  75. {spforge-0.8.36 → spforge-0.8.37}/spforge/transformers/_net_over_predicted.py +0 -0
  76. {spforge-0.8.36 → spforge-0.8.37}/spforge/transformers/_operator.py +0 -0
  77. {spforge-0.8.36 → spforge-0.8.37}/spforge/transformers/_other_transformer.py +0 -0
  78. {spforge-0.8.36 → spforge-0.8.37}/spforge/transformers/_predictor.py +0 -0
  79. {spforge-0.8.36 → spforge-0.8.37}/spforge/transformers/_simple_transformer.py +0 -0
  80. {spforge-0.8.36 → spforge-0.8.37}/spforge/transformers/_team_ratio_predictor.py +0 -0
  81. {spforge-0.8.36 → spforge-0.8.37}/spforge/utils.py +0 -0
  82. {spforge-0.8.36 → spforge-0.8.37}/spforge.egg-info/SOURCES.txt +0 -0
  83. {spforge-0.8.36 → spforge-0.8.37}/spforge.egg-info/dependency_links.txt +0 -0
  84. {spforge-0.8.36 → spforge-0.8.37}/spforge.egg-info/requires.txt +0 -0
  85. {spforge-0.8.36 → spforge-0.8.37}/spforge.egg-info/top_level.txt +0 -0
  86. {spforge-0.8.36 → spforge-0.8.37}/tests/cross_validator/test_cross_validator.py +0 -0
  87. {spforge-0.8.36 → spforge-0.8.37}/tests/distributions/test_distribution.py +0 -0
  88. {spforge-0.8.36 → spforge-0.8.37}/tests/end_to_end/test_estimator_hyperparameter_tuning.py +0 -0
  89. {spforge-0.8.36 → spforge-0.8.37}/tests/end_to_end/test_league_start_rating_optimizer.py +0 -0
  90. {spforge-0.8.36 → spforge-0.8.37}/tests/end_to_end/test_lol_player_kills.py +0 -0
  91. {spforge-0.8.36 → spforge-0.8.37}/tests/end_to_end/test_nba_player_points.py +0 -0
  92. {spforge-0.8.36 → spforge-0.8.37}/tests/end_to_end/test_nba_player_ratings_hyperparameter_tuning.py +0 -0
  93. {spforge-0.8.36 → spforge-0.8.37}/tests/end_to_end/test_nba_prediction_consistency.py +0 -0
  94. {spforge-0.8.36 → spforge-0.8.37}/tests/estimator/test_sklearn_estimator.py +0 -0
  95. {spforge-0.8.36 → spforge-0.8.37}/tests/feature_generator/test_lag.py +0 -0
  96. {spforge-0.8.36 → spforge-0.8.37}/tests/feature_generator/test_regressor_feature_generator.py +0 -0
  97. {spforge-0.8.36 → spforge-0.8.37}/tests/feature_generator/test_rolling_against_opponent.py +0 -0
  98. {spforge-0.8.36 → spforge-0.8.37}/tests/feature_generator/test_rolling_mean_binary.py +0 -0
  99. {spforge-0.8.36 → spforge-0.8.37}/tests/feature_generator/test_rolling_mean_days.py +0 -0
  100. {spforge-0.8.36 → spforge-0.8.37}/tests/feature_generator/test_rolling_window.py +0 -0
  101. {spforge-0.8.36 → spforge-0.8.37}/tests/hyperparameter_tuning/test_estimator_tuner.py +0 -0
  102. {spforge-0.8.36 → spforge-0.8.37}/tests/hyperparameter_tuning/test_rating_tuner.py +0 -0
  103. {spforge-0.8.36 → spforge-0.8.37}/tests/performance_transformers/test_performances_transformers.py +0 -0
  104. {spforge-0.8.36 → spforge-0.8.37}/tests/ratings/test_player_rating_generator.py +0 -0
  105. {spforge-0.8.36 → spforge-0.8.37}/tests/ratings/test_player_rating_no_mutation.py +0 -0
  106. {spforge-0.8.36 → spforge-0.8.37}/tests/ratings/test_ratings_property.py +0 -0
  107. {spforge-0.8.36 → spforge-0.8.37}/tests/ratings/test_team_rating_generator.py +0 -0
  108. {spforge-0.8.36 → spforge-0.8.37}/tests/ratings/test_utils_scaled_weights.py +0 -0
  109. {spforge-0.8.36 → spforge-0.8.37}/tests/scorer/test_score.py +0 -0
  110. {spforge-0.8.36 → spforge-0.8.37}/tests/scorer/test_score_aggregation_granularity.py +0 -0
  111. {spforge-0.8.36 → spforge-0.8.37}/tests/scorer/test_scorer_name.py +0 -0
  112. {spforge-0.8.36 → spforge-0.8.37}/tests/test_autopipeline.py +0 -0
  113. {spforge-0.8.36 → spforge-0.8.37}/tests/test_autopipeline_context.py +0 -0
  114. {spforge-0.8.36 → spforge-0.8.37}/tests/test_feature_generator_pipeline.py +0 -0
  115. {spforge-0.8.36 → spforge-0.8.37}/tests/transformers/test_estimator_transformer_context.py +0 -0
  116. {spforge-0.8.36 → spforge-0.8.37}/tests/transformers/test_net_over_predicted.py +0 -0
  117. {spforge-0.8.36 → spforge-0.8.37}/tests/transformers/test_other_transformer.py +0 -0
  118. {spforge-0.8.36 → spforge-0.8.37}/tests/transformers/test_predictor_transformer.py +0 -0
  119. {spforge-0.8.36 → spforge-0.8.37}/tests/transformers/test_simple_transformer.py +0 -0
  120. {spforge-0.8.36 → spforge-0.8.37}/tests/transformers/test_team_ratio_predictor.py +0 -0
@@ -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
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "spforge"
7
- version = "0.8.36"
7
+ version = "0.8.37"
8
8
  description = "A flexible framework for generating features, ratings, and building machine learning or other models for training and inference on sports data."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -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
@@ -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
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes