spforge 0.8.4__py3-none-any.whl → 0.8.18__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.
- examples/lol/pipeline_transformer_example.py +69 -86
- examples/nba/cross_validation_example.py +4 -11
- examples/nba/feature_engineering_example.py +33 -15
- examples/nba/game_winner_example.py +24 -14
- examples/nba/predictor_transformers_example.py +29 -16
- spforge/__init__.py +1 -0
- spforge/autopipeline.py +169 -5
- spforge/estimator/_group_by_estimator.py +11 -3
- spforge/features_generator_pipeline.py +8 -4
- spforge/hyperparameter_tuning/__init__.py +12 -0
- spforge/hyperparameter_tuning/_default_search_spaces.py +159 -1
- spforge/hyperparameter_tuning/_tuner.py +192 -0
- spforge/performance_transformers/_performance_manager.py +2 -4
- spforge/ratings/__init__.py +4 -0
- spforge/ratings/_player_rating.py +142 -28
- spforge/ratings/league_start_rating_optimizer.py +201 -0
- spforge/ratings/start_rating_generator.py +1 -1
- spforge/ratings/team_start_rating_generator.py +1 -1
- spforge/ratings/utils.py +16 -6
- spforge/scorer/_score.py +42 -11
- spforge/transformers/_other_transformer.py +38 -8
- {spforge-0.8.4.dist-info → spforge-0.8.18.dist-info}/METADATA +12 -19
- {spforge-0.8.4.dist-info → spforge-0.8.18.dist-info}/RECORD +37 -31
- {spforge-0.8.4.dist-info → spforge-0.8.18.dist-info}/WHEEL +1 -1
- tests/end_to_end/test_estimator_hyperparameter_tuning.py +85 -0
- tests/end_to_end/test_league_start_rating_optimizer.py +117 -0
- tests/end_to_end/test_nba_player_ratings_hyperparameter_tuning.py +5 -0
- tests/hyperparameter_tuning/test_estimator_tuner.py +167 -0
- tests/performance_transformers/test_performance_manager.py +15 -0
- tests/ratings/test_player_rating_generator.py +154 -0
- tests/ratings/test_player_rating_no_mutation.py +214 -0
- tests/ratings/test_utils_scaled_weights.py +136 -0
- tests/scorer/test_score.py +232 -0
- tests/test_autopipeline.py +336 -6
- tests/test_feature_generator_pipeline.py +43 -0
- {spforge-0.8.4.dist-info → spforge-0.8.18.dist-info}/licenses/LICENSE +0 -0
- {spforge-0.8.4.dist-info → spforge-0.8.18.dist-info}/top_level.txt +0 -0
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
examples/__init__.py,sha256=qGLpphvrjQj0-zS9vP0Q07L-anDnmw7gFZJUEBgYG3U,158
|
|
2
2
|
examples/game_level_example.py,sha256=EOr-H0K79O3Zah4wWuqa5DLmT2iZGbfgxD-xSU2-dfI,2244
|
|
3
3
|
examples/lol/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
|
-
examples/lol/pipeline_transformer_example.py,sha256=
|
|
4
|
+
examples/lol/pipeline_transformer_example.py,sha256=XVmm6Xya5z7JyOA0s-DISOlR2I1wpUthCyhRSt9n6qE,3402
|
|
5
5
|
examples/lol/data/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
6
6
|
examples/lol/data/subsample_lol_data.parquet,sha256=tl04XDslylECJUV1e0DGeqMb6D0Uh6_48NO6TykdgQI,343549
|
|
7
7
|
examples/lol/data/utils.py,sha256=Lt3XNNa5cavvFXHaTQ-GOPxSuWmPEfEO0CVXQEyF_s0,486
|
|
8
8
|
examples/nba/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
9
|
-
examples/nba/cross_validation_example.py,sha256=
|
|
10
|
-
examples/nba/feature_engineering_example.py,sha256=
|
|
11
|
-
examples/nba/game_winner_example.py,sha256=
|
|
12
|
-
examples/nba/predictor_transformers_example.py,sha256=
|
|
9
|
+
examples/nba/cross_validation_example.py,sha256=XVnQJ5mqMou9z83ML5J0wS3gk-pa56sdvahJYQgZ8os,5056
|
|
10
|
+
examples/nba/feature_engineering_example.py,sha256=BDd5594Yi_56lGDqz3SYQkwT8NVZyFkgv3gKPCsAjz4,8197
|
|
11
|
+
examples/nba/game_winner_example.py,sha256=7VVHxGyU2uPjT9q6lDMHJ5KpkWp9gU8brxr_UZfuSHg,3189
|
|
12
|
+
examples/nba/predictor_transformers_example.py,sha256=Fl4BY_hVW0iYERolN6s-ZB2xv-UxOK547L6iI5t0r0Y,8807
|
|
13
13
|
examples/nba/data/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
14
14
|
examples/nba/data/game_player_subsample.parquet,sha256=ODJxHC-mUYbJ7r-ScUFtPU7hrFuxLUbbDSobmpCkw0w,279161
|
|
15
15
|
examples/nba/data/utils.py,sha256=41hxLQ1d6ZgBEcHa5MI0-fG5KbsRi07cclMPQZM95ek,509
|
|
16
|
-
spforge/__init__.py,sha256=
|
|
17
|
-
spforge/autopipeline.py,sha256=
|
|
16
|
+
spforge/__init__.py,sha256=8vZhy7XUpzqWkVKpXqwqOLDkQlNytRhyf4qjwObfXgU,468
|
|
17
|
+
spforge/autopipeline.py,sha256=rZ6FhJxcgNLvtr3hTVkEiW4BiorgXxADThfMuQ42orE,29866
|
|
18
18
|
spforge/base_feature_generator.py,sha256=RbD00N6oLCQQcEb_VF5wbwZztl-X8k9B0Wlaj9Os1iU,668
|
|
19
19
|
spforge/data_structures.py,sha256=k82v5r79vl0_FAVvsxVF9Nbzb5FoHqVrlHZlEXGc5gQ,7298
|
|
20
|
-
spforge/features_generator_pipeline.py,sha256=
|
|
20
|
+
spforge/features_generator_pipeline.py,sha256=n8vzZKqXNFcFRDWZhllnkhAh5NFXdOD3FEIOpHcay8E,8208
|
|
21
21
|
spforge/utils.py,sha256=2RlivUtMX5wQWpFVUyFfexDJE0wV6uZ4dnNzvoDmVhI,2644
|
|
22
22
|
spforge/cross_validator/__init__.py,sha256=1QHgTFIZ73EZ_MgJlUKimxdUmB7MFaOEy6jsUs6V0T0,134
|
|
23
23
|
spforge/cross_validator/_base.py,sha256=-zxZ2Q2tYlGIwjQQMf9_OglS_doppp47gVElkJuBY7E,1199
|
|
@@ -30,7 +30,7 @@ spforge/estimator/__init__.py,sha256=zIJ4u7WGPOALPx8kVBppBOqklI4lQPl9QBWT8JjjFoY
|
|
|
30
30
|
spforge/estimator/_conditional_estimator.py,sha256=JSHpOg5lv3kRv_VzSZ0fKbwCO2dJv9XpyLs9lS81psU,4904
|
|
31
31
|
spforge/estimator/_frequency_bucketing_classifier.py,sha256=d7wDpOCoKWf-WoXtzwahjtmAozkFdKE3-pzs477WMYc,6055
|
|
32
32
|
spforge/estimator/_granularity_estimator.py,sha256=pUNmtpDFoOVbS9mHfO-zvidPIKJgWts0y2VnhJ8VWww,3829
|
|
33
|
-
spforge/estimator/_group_by_estimator.py,sha256=
|
|
33
|
+
spforge/estimator/_group_by_estimator.py,sha256=o-xv_PJJyWBaKv5Eo4EPbOvb9i0CuebZnX4GtEFp_Js,3120
|
|
34
34
|
spforge/estimator/_ordinal_classifier.py,sha256=j_dfVHeX-6eZgPwwsYbkbP6bPrKH2a5S-N8vfP5hneA,1993
|
|
35
35
|
spforge/estimator/_sklearn_enhancer_estimator.py,sha256=DZ-UlmeazXPd6uEnlbVv79syZ5FPa64voUyKArtjjUs,4664
|
|
36
36
|
spforge/feature_generator/__init__.py,sha256=wfLfUkC_lLOCpy7NgDytK-l3HUAuhikuQXdKCgSGbuA,556
|
|
@@ -43,42 +43,45 @@ spforge/feature_generator/_rolling_mean_binary.py,sha256=lmODy-o9Dd9pb8IlA7g4UyA
|
|
|
43
43
|
spforge/feature_generator/_rolling_mean_days.py,sha256=EZQmFmYVQB-JjZV5k8bOWnaTxNpPDCZAjdfdhiiG4r4,8415
|
|
44
44
|
spforge/feature_generator/_rolling_window.py,sha256=HT8LezsRIPNAlMEoP9oTPW2bKFu55ZSRnQZGST7fncw,8836
|
|
45
45
|
spforge/feature_generator/_utils.py,sha256=KDn33ia1OYJTK8THFpvc_uRiH_Bl3fImGqqbfzs0YA4,9654
|
|
46
|
-
spforge/hyperparameter_tuning/__init__.py,sha256=
|
|
47
|
-
spforge/hyperparameter_tuning/_default_search_spaces.py,sha256=
|
|
48
|
-
spforge/hyperparameter_tuning/_tuner.py,sha256=
|
|
46
|
+
spforge/hyperparameter_tuning/__init__.py,sha256=N2sKG4SvG41hlsFT2kx_DQYMmXsQr-8031Tu_rxlxyY,1015
|
|
47
|
+
spforge/hyperparameter_tuning/_default_search_spaces.py,sha256=Sm5IrHAW0-vRC8jqCPX0pDi_C-W3L_MoEKGA8bx1Zbc,7546
|
|
48
|
+
spforge/hyperparameter_tuning/_tuner.py,sha256=uovhGqhe8-fdhi79aErUmE2h5NCycFQEIRv5WCjpC7E,16732
|
|
49
49
|
spforge/performance_transformers/__init__.py,sha256=U6d7_kltbUMLYCGBk4QAFVPJTxXD3etD9qUftV-O3q4,422
|
|
50
|
-
spforge/performance_transformers/_performance_manager.py,sha256=
|
|
50
|
+
spforge/performance_transformers/_performance_manager.py,sha256=WmjmlMEnq7y75MiI_s9Y-9eMXIyhPTUKrwsXRtgYp0k,9620
|
|
51
51
|
spforge/performance_transformers/_performances_transformers.py,sha256=0lxuWjAfWBRXRgQsNJHjw3P-nlTtHBu4_bOVdoy7hq4,15536
|
|
52
|
-
spforge/ratings/__init__.py,sha256=
|
|
52
|
+
spforge/ratings/__init__.py,sha256=OZVH2Lo6END3n1X8qi4QcyAPlThIwAYwVKCiIuOQSQU,576
|
|
53
53
|
spforge/ratings/_base.py,sha256=dRMkIGj5-2zKddygaEA4g16WCyXon7v8Xa1ymm7IuoM,14335
|
|
54
|
-
spforge/ratings/_player_rating.py,sha256=
|
|
54
|
+
spforge/ratings/_player_rating.py,sha256=JSTXdaRw_b8ZoZxgmMnZrYG7gPg8GKawqalLd16SK1M,56066
|
|
55
55
|
spforge/ratings/_team_rating.py,sha256=T0kFiv3ykYSrVGGsVRa8ZxLB0WMnagxqdFDzl9yZ_9g,24813
|
|
56
56
|
spforge/ratings/enums.py,sha256=s7z_RcZS6Nlgfa_6tasO8_IABZJwywexe7sep9DJBgo,1739
|
|
57
57
|
spforge/ratings/league_identifier.py,sha256=_KDUKOwoNU6RNFKE5jju4eYFGVNGBdJsv5mhNvMakfc,6019
|
|
58
|
+
spforge/ratings/league_start_rating_optimizer.py,sha256=Q4Vo3QT-r55qP4aD9WftsTB00UOSRvxM1khlyuAGWNM,8582
|
|
58
59
|
spforge/ratings/player_performance_predictor.py,sha256=cMxzQuk0nF1MsT_M32g-3mxVdAEbZ-S7TUjEPYdo3Yg,8361
|
|
59
|
-
spforge/ratings/start_rating_generator.py,sha256=
|
|
60
|
+
spforge/ratings/start_rating_generator.py,sha256=eSasa5Oe9n4IoTGjFCYyFQAGrJtzrBW-Qor97lmaYuM,6776
|
|
60
61
|
spforge/ratings/team_performance_predictor.py,sha256=ThQOmYQUqKBB46ONYHOMM2arXFH8AkyKpAZzs80SjHA,7217
|
|
61
|
-
spforge/ratings/team_start_rating_generator.py,sha256=
|
|
62
|
-
spforge/ratings/utils.py,sha256=
|
|
62
|
+
spforge/ratings/team_start_rating_generator.py,sha256=vK-_m8KwcHopchch_lKNHSGLiiNm5q9Lenm0d1cP_po,5110
|
|
63
|
+
spforge/ratings/utils.py,sha256=_zFemqz2jJkH8rn2EZpDt8N6FELUmYp9qCnPzRtOIGU,4497
|
|
63
64
|
spforge/scorer/__init__.py,sha256=wj8PCvYIl6742Xwmt86c3oy6iqE8Ss-OpwHud6kd9IY,256
|
|
64
|
-
spforge/scorer/_score.py,sha256=
|
|
65
|
+
spforge/scorer/_score.py,sha256=kNuqiK3F5mUEAVD7KjWYY7E_AkRrspR362QBm_jyElg,57623
|
|
65
66
|
spforge/transformers/__init__.py,sha256=IPCsMcsgBqG52d0ttATLCY4HvFCQZddExlLt74U-zuI,390
|
|
66
67
|
spforge/transformers/_base.py,sha256=-smr_McQF9bYxM5-Agx6h7Xv_fhZzPfpAdQV-qK18bs,1134
|
|
67
68
|
spforge/transformers/_net_over_predicted.py,sha256=5dC8pvA1DNO0yXPSgJSMGU8zAHi-maUELm7FqFQVo-U,2321
|
|
68
69
|
spforge/transformers/_operator.py,sha256=jOH7wdMBLg6R2hlH_FU6eA0gjs-Q0vFimTo7fXgKpjI,2964
|
|
69
|
-
spforge/transformers/_other_transformer.py,sha256=
|
|
70
|
+
spforge/transformers/_other_transformer.py,sha256=w2a7Wnki3vJe4GAkSa4kealw0GILIo6nE_9-3M10owA,4646
|
|
70
71
|
spforge/transformers/_predictor.py,sha256=2sE6gfVrilXzPVcBurSrtqHw33v2ljygQcEYXt9LhZc,3119
|
|
71
72
|
spforge/transformers/_simple_transformer.py,sha256=zGUFNQYMeoDSa2CoQejQNiNmKCBN5amWTvyOchiUHj0,5660
|
|
72
73
|
spforge/transformers/_team_ratio_predictor.py,sha256=g8_bR53Yyv0iNCtol1O9bgJSeZcIco_AfbQuUxQJkeY,6884
|
|
73
|
-
spforge-0.8.
|
|
74
|
-
tests/test_autopipeline.py,sha256=
|
|
74
|
+
spforge-0.8.18.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
75
|
+
tests/test_autopipeline.py,sha256=7cNAn-nmGolfyfk3THh9IKcHZfRA-pLYC_xAyMg-No4,26863
|
|
75
76
|
tests/test_autopipeline_context.py,sha256=IuRUY4IA6uMObvbl2pXSaXO2_tl3qX6wEbTZY0dkTMI,1240
|
|
76
|
-
tests/test_feature_generator_pipeline.py,sha256=
|
|
77
|
+
tests/test_feature_generator_pipeline.py,sha256=CK0zVL8PfTncy3RmG9i-YpgwjOIV7yJhV7Q44tbetI8,19020
|
|
77
78
|
tests/cross_validator/test_cross_validator.py,sha256=itCGhNY8-NbDbKbhxHW20wiLuRst7-Rixpmi3FSKQtA,17474
|
|
78
79
|
tests/distributions/test_distribution.py,sha256=aU8hfCgliM80TES4WGjs9KFXpV8XghBGF7Hu9sqEVSE,10982
|
|
80
|
+
tests/end_to_end/test_estimator_hyperparameter_tuning.py,sha256=fZCJ9rrED2vT68B9ovmVA1cIG2pHRTjy9xzZLxxpEBo,2513
|
|
81
|
+
tests/end_to_end/test_league_start_rating_optimizer.py,sha256=Mmct2ixp4c6L7PGym8wZc7E-Csozryt1g4_o6OCc1uI,3141
|
|
79
82
|
tests/end_to_end/test_lol_player_kills.py,sha256=RJSYUbPrZ-RzSxGggj03yN0JKYeTB1JghVGYFMYia3Y,11891
|
|
80
83
|
tests/end_to_end/test_nba_player_points.py,sha256=kyzjo7QIcvpteps29Wix6IS_eJG9d1gHLeWtIHpkWMs,9066
|
|
81
|
-
tests/end_to_end/test_nba_player_ratings_hyperparameter_tuning.py,sha256=
|
|
84
|
+
tests/end_to_end/test_nba_player_ratings_hyperparameter_tuning.py,sha256=LXRkI_6Ho2kzJVbNAM17QFhx_MP9WdDJXCO9dWgJGNA,6491
|
|
82
85
|
tests/end_to_end/test_nba_prediction_consistency.py,sha256=o3DckJasx_I1ed6MhMYZUo2WSDvQ_p3HtJa9DCWTIYU,9857
|
|
83
86
|
tests/estimator/test_sklearn_estimator.py,sha256=tVfOP9Wx-tV1b6DcHbGxQHZQzNPA0Iobq8jTcUrk59U,48668
|
|
84
87
|
tests/feature_generator/test_lag.py,sha256=5Ffrv0V9cwkbkzRMPBe3_c_YNW-W2al-XH_acQIvdeg,19531
|
|
@@ -87,13 +90,16 @@ tests/feature_generator/test_rolling_against_opponent.py,sha256=20kH1INrWy6DV7AS
|
|
|
87
90
|
tests/feature_generator/test_rolling_mean_binary.py,sha256=KuIavJ37Pt8icAb50B23lxdWEPVSHQ7NZHisD1BDpmU,16216
|
|
88
91
|
tests/feature_generator/test_rolling_mean_days.py,sha256=EyOvdJDnmgPfe13uQBOkwo7fAteBQx-tnyuGM4ng2T8,18884
|
|
89
92
|
tests/feature_generator/test_rolling_window.py,sha256=YBJo36OK3ILYeXrH06ylXqviUcCaGYaVQaK5RJzwM7Y,23239
|
|
93
|
+
tests/hyperparameter_tuning/test_estimator_tuner.py,sha256=iewME41d6LR2aQ0OtohGFtN_ocJUwTeqvs6L0QDmfG4,4413
|
|
90
94
|
tests/hyperparameter_tuning/test_rating_tuner.py,sha256=PyCFP3KPc4Iy9E_X9stCVxra14uMgC1tuRwuQ30rO_o,13195
|
|
91
|
-
tests/performance_transformers/test_performance_manager.py,sha256=
|
|
95
|
+
tests/performance_transformers/test_performance_manager.py,sha256=gjuuV_hb27kCo_kUecPKG3Cbot2Gqis1W3kw2A4ovS4,10690
|
|
92
96
|
tests/performance_transformers/test_performances_transformers.py,sha256=A-tGiCx7kXrj1cVj03Bc7prOeZ1_Ryz8YFx9uj3eK6w,11064
|
|
93
|
-
tests/ratings/test_player_rating_generator.py,sha256=
|
|
97
|
+
tests/ratings/test_player_rating_generator.py,sha256=SKLaBQBsHYslc2Nia2AxZ8A9Cy16MbZAWjLyOjvcMnA,64094
|
|
98
|
+
tests/ratings/test_player_rating_no_mutation.py,sha256=GzO3Hl__5K68DS3uRLefwnbcTJOvBM7cZqww4M21UZM,8493
|
|
94
99
|
tests/ratings/test_ratings_property.py,sha256=ckyfGILXa4tfQvsgyXEzBDNr2DUmHwFRV13N60w66iE,6561
|
|
95
100
|
tests/ratings/test_team_rating_generator.py,sha256=cDnf1zHiYC7pkgydE3MYr8wSTJIq-bPfSqhIRI_4Tic,95357
|
|
96
|
-
tests/
|
|
101
|
+
tests/ratings/test_utils_scaled_weights.py,sha256=iHxe6ZDUB_I2B6HT0xTGqXBkl7gRlqVV0e_7Lwun5po,4988
|
|
102
|
+
tests/scorer/test_score.py,sha256=rw3xJs6xqWVpalVMUQz557m2JYGR7PmhrsjfTex0b0c,79121
|
|
97
103
|
tests/scorer/test_score_aggregation_granularity.py,sha256=h-hyFOLzwp-92hYVU7CwvlRJ8jhB4DzXCtqgI-zcoqM,13677
|
|
98
104
|
tests/transformers/test_estimator_transformer_context.py,sha256=5GOHbuWCWBMFwwOTJOuD4oNDsv-qDR0OxNZYGGuMdag,1819
|
|
99
105
|
tests/transformers/test_net_over_predicted.py,sha256=vh7O1iRRPf4vcW9aLhOMAOyatfM5ZnLsQBKNAYsR3SU,3363
|
|
@@ -101,7 +107,7 @@ tests/transformers/test_other_transformer.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRk
|
|
|
101
107
|
tests/transformers/test_predictor_transformer.py,sha256=N1aBYLjN3ldpYZLwjih_gTFYSMitrZu-PNK78W6RHaQ,6877
|
|
102
108
|
tests/transformers/test_simple_transformer.py,sha256=wWR0qjLb_uS4HXrJgGdiqugOY1X7kwd1_OPS02IT2b8,4676
|
|
103
109
|
tests/transformers/test_team_ratio_predictor.py,sha256=fOUP_JvNJi-3kom3ZOs1EdG0I6Z8hpLpYKNHu1eWtOw,8562
|
|
104
|
-
spforge-0.8.
|
|
105
|
-
spforge-0.8.
|
|
106
|
-
spforge-0.8.
|
|
107
|
-
spforge-0.8.
|
|
110
|
+
spforge-0.8.18.dist-info/METADATA,sha256=54l0UTrew2ot0_4k22hLKL-oXbQ4hlA1_KAXIqf_umw,20048
|
|
111
|
+
spforge-0.8.18.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
112
|
+
spforge-0.8.18.dist-info/top_level.txt,sha256=6UW2M5a7WKOeaAi900qQmRKNj5-HZzE8-eUD9Y9LTq0,23
|
|
113
|
+
spforge-0.8.18.dist-info/RECORD,,
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import polars as pl
|
|
2
|
+
from sklearn.linear_model import LogisticRegression
|
|
3
|
+
from sklearn.metrics import mean_absolute_error
|
|
4
|
+
|
|
5
|
+
from examples import get_sub_sample_nba_data
|
|
6
|
+
from spforge import AutoPipeline, ColumnNames, EstimatorHyperparameterTuner, ParamSpec
|
|
7
|
+
from spforge.cross_validator import MatchKFoldCrossValidator
|
|
8
|
+
from spforge.scorer import SklearnScorer
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def test_nba_estimator_hyperparameter_tuning__workflow_completes():
|
|
12
|
+
df = get_sub_sample_nba_data(as_polars=True, as_pandas=False)
|
|
13
|
+
column_names = ColumnNames(
|
|
14
|
+
team_id="team_id",
|
|
15
|
+
match_id="game_id",
|
|
16
|
+
start_date="start_date",
|
|
17
|
+
player_id="player_id",
|
|
18
|
+
participation_weight="minutes_ratio",
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
df = df.sort(
|
|
22
|
+
[
|
|
23
|
+
column_names.start_date,
|
|
24
|
+
column_names.match_id,
|
|
25
|
+
column_names.team_id,
|
|
26
|
+
column_names.player_id,
|
|
27
|
+
]
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
df = df.with_columns(
|
|
31
|
+
[
|
|
32
|
+
(pl.col("minutes") / pl.col("minutes").sum().over("game_id")).alias(
|
|
33
|
+
"minutes_ratio"
|
|
34
|
+
),
|
|
35
|
+
(pl.col("points") > pl.lit(10)).cast(pl.Int64).alias("points_over_10"),
|
|
36
|
+
]
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
estimator = AutoPipeline(
|
|
40
|
+
estimator=LogisticRegression(max_iter=200),
|
|
41
|
+
estimator_features=["minutes", "minutes_ratio"],
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
cv = MatchKFoldCrossValidator(
|
|
45
|
+
match_id_column_name=column_names.match_id,
|
|
46
|
+
date_column_name=column_names.start_date,
|
|
47
|
+
target_column="points_over_10",
|
|
48
|
+
estimator=estimator,
|
|
49
|
+
prediction_column_name="points_pred",
|
|
50
|
+
n_splits=2,
|
|
51
|
+
features=estimator.required_features,
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
scorer = SklearnScorer(
|
|
55
|
+
scorer_function=mean_absolute_error,
|
|
56
|
+
pred_column="points_pred",
|
|
57
|
+
target="points_over_10",
|
|
58
|
+
validation_column="is_validation",
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
tuner = EstimatorHyperparameterTuner(
|
|
62
|
+
estimator=estimator,
|
|
63
|
+
cross_validator=cv,
|
|
64
|
+
scorer=scorer,
|
|
65
|
+
direction="minimize",
|
|
66
|
+
param_search_space={
|
|
67
|
+
"C": ParamSpec(
|
|
68
|
+
param_type="float",
|
|
69
|
+
low=0.1,
|
|
70
|
+
high=2.0,
|
|
71
|
+
log=True,
|
|
72
|
+
),
|
|
73
|
+
},
|
|
74
|
+
n_trials=3,
|
|
75
|
+
show_progress_bar=False,
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
result = tuner.optimize(df)
|
|
79
|
+
|
|
80
|
+
assert result.best_params is not None
|
|
81
|
+
assert isinstance(result.best_params, dict)
|
|
82
|
+
assert "estimator__C" in result.best_params
|
|
83
|
+
assert isinstance(result.best_value, float)
|
|
84
|
+
assert result.best_trial is not None
|
|
85
|
+
assert result.study is not None
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import pandas as pd
|
|
2
|
+
import polars as pl
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
from spforge import ColumnNames
|
|
6
|
+
from spforge.ratings import (
|
|
7
|
+
LeagueStartRatingOptimizer,
|
|
8
|
+
PlayerRatingGenerator,
|
|
9
|
+
TeamRatingGenerator,
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def _player_df():
|
|
14
|
+
dates = pd.date_range("2024-01-01", periods=3, freq="D")
|
|
15
|
+
rows = []
|
|
16
|
+
for i, date in enumerate(dates):
|
|
17
|
+
mid = f"M{i}"
|
|
18
|
+
for player_idx in range(2):
|
|
19
|
+
rows.append(
|
|
20
|
+
{
|
|
21
|
+
"pid": f"A{player_idx}",
|
|
22
|
+
"tid": "TA",
|
|
23
|
+
"mid": mid,
|
|
24
|
+
"date": date,
|
|
25
|
+
"league": "LCK",
|
|
26
|
+
"perf": 0.4,
|
|
27
|
+
}
|
|
28
|
+
)
|
|
29
|
+
for player_idx in range(2):
|
|
30
|
+
rows.append(
|
|
31
|
+
{
|
|
32
|
+
"pid": f"B{player_idx}",
|
|
33
|
+
"tid": "TB",
|
|
34
|
+
"mid": mid,
|
|
35
|
+
"date": date,
|
|
36
|
+
"league": "LEC",
|
|
37
|
+
"perf": 0.6,
|
|
38
|
+
}
|
|
39
|
+
)
|
|
40
|
+
return pd.DataFrame(rows)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def _team_df():
|
|
44
|
+
dates = pd.date_range("2024-01-01", periods=3, freq="D")
|
|
45
|
+
rows = []
|
|
46
|
+
for i, date in enumerate(dates):
|
|
47
|
+
mid = f"M{i}"
|
|
48
|
+
rows.extend(
|
|
49
|
+
[
|
|
50
|
+
{
|
|
51
|
+
"tid": "TA",
|
|
52
|
+
"mid": mid,
|
|
53
|
+
"date": date,
|
|
54
|
+
"league": "LCK",
|
|
55
|
+
"perf": 0.4,
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
"tid": "TB",
|
|
59
|
+
"mid": mid,
|
|
60
|
+
"date": date,
|
|
61
|
+
"league": "LEC",
|
|
62
|
+
"perf": 0.6,
|
|
63
|
+
},
|
|
64
|
+
]
|
|
65
|
+
)
|
|
66
|
+
return pd.DataFrame(rows)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
@pytest.mark.parametrize("use_polars", [False, True])
|
|
70
|
+
def test_league_start_rating_optimizer__adjusts_player_leagues(use_polars):
|
|
71
|
+
cn = ColumnNames(
|
|
72
|
+
player_id="pid",
|
|
73
|
+
team_id="tid",
|
|
74
|
+
match_id="mid",
|
|
75
|
+
start_date="date",
|
|
76
|
+
league="league",
|
|
77
|
+
)
|
|
78
|
+
df = _player_df()
|
|
79
|
+
if use_polars:
|
|
80
|
+
df = pl.from_pandas(df)
|
|
81
|
+
generator = PlayerRatingGenerator(performance_column="perf", column_names=cn)
|
|
82
|
+
optimizer = LeagueStartRatingOptimizer(
|
|
83
|
+
rating_generator=generator,
|
|
84
|
+
n_iterations=1,
|
|
85
|
+
learning_rate=0.5,
|
|
86
|
+
min_cross_region_rows=1,
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
result = optimizer.optimize(df)
|
|
90
|
+
|
|
91
|
+
assert result.league_ratings["LCK"] < 1000
|
|
92
|
+
assert result.league_ratings["LEC"] > 1000
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
@pytest.mark.parametrize("use_polars", [False, True])
|
|
96
|
+
def test_league_start_rating_optimizer__adjusts_team_leagues(use_polars):
|
|
97
|
+
cn = ColumnNames(
|
|
98
|
+
team_id="tid",
|
|
99
|
+
match_id="mid",
|
|
100
|
+
start_date="date",
|
|
101
|
+
league="league",
|
|
102
|
+
)
|
|
103
|
+
df = _team_df()
|
|
104
|
+
if use_polars:
|
|
105
|
+
df = pl.from_pandas(df)
|
|
106
|
+
generator = TeamRatingGenerator(performance_column="perf", column_names=cn)
|
|
107
|
+
optimizer = LeagueStartRatingOptimizer(
|
|
108
|
+
rating_generator=generator,
|
|
109
|
+
n_iterations=1,
|
|
110
|
+
learning_rate=0.5,
|
|
111
|
+
min_cross_region_rows=1,
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
result = optimizer.optimize(df)
|
|
115
|
+
|
|
116
|
+
assert result.league_ratings["LCK"] < 1000
|
|
117
|
+
assert result.league_ratings["LEC"] > 1000
|
|
@@ -97,6 +97,11 @@ def test_nba_player_ratings_hyperparameter_tuning__workflow_completes(
|
|
|
97
97
|
"confidence_max_sum",
|
|
98
98
|
"use_off_def_split",
|
|
99
99
|
"performance_predictor",
|
|
100
|
+
"start_team_weight",
|
|
101
|
+
"start_league_quantile",
|
|
102
|
+
"start_min_count_for_percentiles",
|
|
103
|
+
"start_min_match_count_team_rating",
|
|
104
|
+
"start_team_rating_subtract",
|
|
100
105
|
}
|
|
101
106
|
assert set(result.best_params.keys()) == expected_params
|
|
102
107
|
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import pandas as pd
|
|
3
|
+
import pytest
|
|
4
|
+
from sklearn.base import BaseEstimator
|
|
5
|
+
from sklearn.linear_model import LogisticRegression
|
|
6
|
+
|
|
7
|
+
from spforge import EstimatorHyperparameterTuner, ParamSpec
|
|
8
|
+
from spforge.cross_validator import MatchKFoldCrossValidator
|
|
9
|
+
from spforge.estimator import SkLearnEnhancerEstimator
|
|
10
|
+
from spforge.scorer import MeanBiasScorer
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class FakeLGBMClassifier(BaseEstimator):
|
|
14
|
+
__module__ = "lightgbm.sklearn"
|
|
15
|
+
|
|
16
|
+
def __init__(
|
|
17
|
+
self,
|
|
18
|
+
n_estimators: int = 100,
|
|
19
|
+
num_leaves: int = 31,
|
|
20
|
+
max_depth: int = 5,
|
|
21
|
+
min_child_samples: int = 20,
|
|
22
|
+
subsample: float = 1.0,
|
|
23
|
+
subsample_freq: int = 1,
|
|
24
|
+
reg_alpha: float = 0.0,
|
|
25
|
+
reg_lambda: float = 0.0,
|
|
26
|
+
):
|
|
27
|
+
self.n_estimators = n_estimators
|
|
28
|
+
self.num_leaves = num_leaves
|
|
29
|
+
self.max_depth = max_depth
|
|
30
|
+
self.min_child_samples = min_child_samples
|
|
31
|
+
self.subsample = subsample
|
|
32
|
+
self.subsample_freq = subsample_freq
|
|
33
|
+
self.reg_alpha = reg_alpha
|
|
34
|
+
self.reg_lambda = reg_lambda
|
|
35
|
+
|
|
36
|
+
def fit(self, X, y):
|
|
37
|
+
self.classes_ = np.unique(y)
|
|
38
|
+
return self
|
|
39
|
+
|
|
40
|
+
def predict_proba(self, X):
|
|
41
|
+
n = len(X)
|
|
42
|
+
if len(self.classes_) < 2:
|
|
43
|
+
return np.ones((n, 1))
|
|
44
|
+
return np.tile([0.4, 0.6], (n, 1))
|
|
45
|
+
|
|
46
|
+
def predict(self, X):
|
|
47
|
+
n = len(X)
|
|
48
|
+
if len(self.classes_) == 1:
|
|
49
|
+
return np.full(n, self.classes_[0])
|
|
50
|
+
proba = self.predict_proba(X)
|
|
51
|
+
idx = np.argmax(proba, axis=1)
|
|
52
|
+
return np.array(self.classes_)[idx]
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
@pytest.fixture
|
|
56
|
+
def sample_df():
|
|
57
|
+
dates = pd.date_range("2024-01-01", periods=12, freq="D")
|
|
58
|
+
rows = []
|
|
59
|
+
for i, date in enumerate(dates):
|
|
60
|
+
rows.append(
|
|
61
|
+
{
|
|
62
|
+
"mid": f"M{i // 2}",
|
|
63
|
+
"date": date,
|
|
64
|
+
"x1": float(i),
|
|
65
|
+
"y": 1 if i % 2 == 0 else 0,
|
|
66
|
+
}
|
|
67
|
+
)
|
|
68
|
+
return pd.DataFrame(rows)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
@pytest.fixture
|
|
72
|
+
def scorer():
|
|
73
|
+
return MeanBiasScorer(
|
|
74
|
+
pred_column="y_pred",
|
|
75
|
+
target="y",
|
|
76
|
+
validation_column="is_validation",
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def test_estimator_tuner_requires_search_space(sample_df, scorer):
|
|
81
|
+
estimator = LogisticRegression()
|
|
82
|
+
|
|
83
|
+
cv = MatchKFoldCrossValidator(
|
|
84
|
+
match_id_column_name="mid",
|
|
85
|
+
date_column_name="date",
|
|
86
|
+
target_column="y",
|
|
87
|
+
estimator=estimator,
|
|
88
|
+
prediction_column_name="y_pred",
|
|
89
|
+
n_splits=2,
|
|
90
|
+
features=["x1"],
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
tuner = EstimatorHyperparameterTuner(
|
|
94
|
+
estimator=estimator,
|
|
95
|
+
cross_validator=cv,
|
|
96
|
+
scorer=scorer,
|
|
97
|
+
direction="minimize",
|
|
98
|
+
n_trials=2,
|
|
99
|
+
show_progress_bar=False,
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
with pytest.raises(ValueError, match="param_search_space is required"):
|
|
103
|
+
tuner.optimize(sample_df)
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def test_estimator_tuner_custom_search_space(sample_df, scorer):
|
|
107
|
+
estimator = SkLearnEnhancerEstimator(estimator=LogisticRegression())
|
|
108
|
+
|
|
109
|
+
cv = MatchKFoldCrossValidator(
|
|
110
|
+
match_id_column_name="mid",
|
|
111
|
+
date_column_name="date",
|
|
112
|
+
target_column="y",
|
|
113
|
+
estimator=estimator,
|
|
114
|
+
prediction_column_name="y_pred",
|
|
115
|
+
n_splits=2,
|
|
116
|
+
features=["x1"],
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
tuner = EstimatorHyperparameterTuner(
|
|
120
|
+
estimator=estimator,
|
|
121
|
+
cross_validator=cv,
|
|
122
|
+
scorer=scorer,
|
|
123
|
+
direction="minimize",
|
|
124
|
+
param_search_space={
|
|
125
|
+
"C": ParamSpec(
|
|
126
|
+
param_type="float",
|
|
127
|
+
low=0.1,
|
|
128
|
+
high=2.0,
|
|
129
|
+
log=True,
|
|
130
|
+
)
|
|
131
|
+
},
|
|
132
|
+
n_trials=2,
|
|
133
|
+
show_progress_bar=False,
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
result = tuner.optimize(sample_df)
|
|
137
|
+
|
|
138
|
+
assert "estimator__C" in result.best_params
|
|
139
|
+
assert isinstance(result.best_value, float)
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def test_estimator_tuner_lgbm_defaults(sample_df, scorer):
|
|
143
|
+
estimator = FakeLGBMClassifier()
|
|
144
|
+
|
|
145
|
+
cv = MatchKFoldCrossValidator(
|
|
146
|
+
match_id_column_name="mid",
|
|
147
|
+
date_column_name="date",
|
|
148
|
+
target_column="y",
|
|
149
|
+
estimator=estimator,
|
|
150
|
+
prediction_column_name="y_pred",
|
|
151
|
+
n_splits=2,
|
|
152
|
+
features=["x1"],
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
tuner = EstimatorHyperparameterTuner(
|
|
156
|
+
estimator=estimator,
|
|
157
|
+
cross_validator=cv,
|
|
158
|
+
scorer=scorer,
|
|
159
|
+
direction="minimize",
|
|
160
|
+
n_trials=2,
|
|
161
|
+
show_progress_bar=False,
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
result = tuner.optimize(sample_df)
|
|
165
|
+
|
|
166
|
+
assert "n_estimators" in result.best_params
|
|
167
|
+
assert isinstance(result.best_value, float)
|
|
@@ -56,6 +56,21 @@ def test_performance_weights_manager_basic_flow(sample_data):
|
|
|
56
56
|
assert output_df["weighted_performance"].iloc[0] == pytest.approx(0.6)
|
|
57
57
|
|
|
58
58
|
|
|
59
|
+
def test_performance_weights_manager_keeps_mean_when_weights_not_normalized():
|
|
60
|
+
df = pd.DataFrame(
|
|
61
|
+
{
|
|
62
|
+
"feat_a": [0.0, 1.0, 2.0, 3.0],
|
|
63
|
+
"feat_b": [3.0, 2.0, 1.0, 0.0],
|
|
64
|
+
}
|
|
65
|
+
)
|
|
66
|
+
weights = [ColumnWeight(name="feat_a", weight=0.9), ColumnWeight(name="feat_b", weight=0.5)]
|
|
67
|
+
|
|
68
|
+
manager = PerformanceWeightsManager(weights=weights, transformer_names=["min_max"], prefix="")
|
|
69
|
+
output_df = nw.from_native(manager.fit_transform(df)).to_pandas()
|
|
70
|
+
|
|
71
|
+
assert output_df["weighted_performance"].mean() == pytest.approx(0.5, abs=1e-6)
|
|
72
|
+
|
|
73
|
+
|
|
59
74
|
def test_lower_is_better_logic():
|
|
60
75
|
df = pd.DataFrame({"feat_a": [1.0, 0.0]})
|
|
61
76
|
weights = [ColumnWeight(name="feat_a", weight=1.0, lower_is_better=True)]
|