openstef-models 4.1.2__tar.gz → 4.2.2__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.
Files changed (162) hide show
  1. {openstef_models-4.1.2 → openstef_models-4.2.2}/PKG-INFO +1 -1
  2. {openstef_models-4.1.2 → openstef_models-4.2.2}/pyproject.toml +1 -1
  3. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/models/forecasting/lgbm_forecaster.py +7 -5
  4. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/models/forecasting/lgbmlinear_forecaster.py +7 -5
  5. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/utils/multi_quantile_regressor.py +9 -7
  6. {openstef_models-4.1.2 → openstef_models-4.2.2}/tests/unit/utils/test_multi_quantile_regressor.py +25 -0
  7. {openstef_models-4.1.2 → openstef_models-4.2.2}/.gitignore +0 -0
  8. {openstef_models-4.1.2 → openstef_models-4.2.2}/README.md +0 -0
  9. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/__init__.py +0 -0
  10. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/explainability/__init__.py +0 -0
  11. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/explainability/mixins.py +0 -0
  12. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/explainability/plotters/__init__.py +0 -0
  13. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/explainability/plotters/contributions_plotter.py +0 -0
  14. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/explainability/plotters/feature_importance_plotter.py +0 -0
  15. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/integrations/__init__.py +0 -0
  16. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/integrations/joblib/__init__.py +0 -0
  17. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/integrations/joblib/joblib_model_serializer.py +0 -0
  18. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/integrations/mlflow/__init__.py +0 -0
  19. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/integrations/mlflow/mlflow_storage.py +0 -0
  20. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/integrations/mlflow/mlflow_storage_callback.py +0 -0
  21. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/integrations/optuna/__init__.py +0 -0
  22. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/integrations/optuna/tuner.py +0 -0
  23. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/mixins/__init__.py +0 -0
  24. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/mixins/callbacks.py +0 -0
  25. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/mixins/model_serializer.py +0 -0
  26. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/models/__init__.py +0 -0
  27. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/models/component_splitting/__init__.py +0 -0
  28. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/models/component_splitting/component_splitter.py +0 -0
  29. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/models/component_splitting/constant_component_splitter.py +0 -0
  30. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/models/component_splitting/linear_component_splitter.py +0 -0
  31. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/models/component_splitting/linear_component_splitter_model/linear_component_splitter_model.z +0 -0
  32. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/models/component_splitting/linear_component_splitter_model/linear_component_splitter_model.z.license +0 -0
  33. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/models/component_splitting_model.py +0 -0
  34. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/models/forecasting/__init__.py +0 -0
  35. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/models/forecasting/base_case_forecaster.py +0 -0
  36. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/models/forecasting/constant_quantile_forecaster.py +0 -0
  37. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/models/forecasting/flatliner_forecaster.py +0 -0
  38. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/models/forecasting/forecaster.py +0 -0
  39. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/models/forecasting/gblinear_forecaster.py +0 -0
  40. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/models/forecasting/median_forecaster.py +0 -0
  41. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/models/forecasting/xgboost_forecaster.py +0 -0
  42. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/models/forecasting_model.py +0 -0
  43. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/presets/__init__.py +0 -0
  44. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/presets/forecasting_workflow.py +0 -0
  45. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/testing.py +0 -0
  46. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/transforms/__init__.py +0 -0
  47. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/transforms/energy_domain/__init__.py +0 -0
  48. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/transforms/energy_domain/wind_power_feature_adder.py +0 -0
  49. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/transforms/general/__init__.py +0 -0
  50. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/transforms/general/dimensionality_reducer.py +0 -0
  51. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/transforms/general/empty_feature_remover.py +0 -0
  52. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/transforms/general/flagger.py +0 -0
  53. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/transforms/general/imputer.py +0 -0
  54. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/transforms/general/nan_dropper.py +0 -0
  55. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/transforms/general/outlier_handler.py +0 -0
  56. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/transforms/general/sample_weighter.py +0 -0
  57. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/transforms/general/scaler.py +0 -0
  58. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/transforms/general/selector.py +0 -0
  59. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/transforms/general/shifter.py +0 -0
  60. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/transforms/postprocessing/__init__.py +0 -0
  61. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/transforms/postprocessing/confidence_interval_applicator.py +0 -0
  62. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/transforms/postprocessing/isotonic_quantile_calibrator.py +0 -0
  63. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/transforms/postprocessing/quantile_sorter.py +0 -0
  64. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/transforms/time_domain/__init__.py +0 -0
  65. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/transforms/time_domain/cyclic_features_adder.py +0 -0
  66. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/transforms/time_domain/datetime_features_adder.py +0 -0
  67. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/transforms/time_domain/holiday_features_adder.py +0 -0
  68. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/transforms/time_domain/lags_adder.py +0 -0
  69. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/transforms/time_domain/rolling_aggregates_adder.py +0 -0
  70. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/transforms/time_domain/versioned_lags_adder.py +0 -0
  71. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/transforms/validation/__init__.py +0 -0
  72. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/transforms/validation/completeness_checker.py +0 -0
  73. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/transforms/validation/flatline_checker.py +0 -0
  74. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/transforms/validation/input_consistency_checker.py +0 -0
  75. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/transforms/weather_domain/__init__.py +0 -0
  76. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/transforms/weather_domain/atmosphere_derived_features_adder.py +0 -0
  77. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/transforms/weather_domain/daylight_feature_adder.py +0 -0
  78. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/transforms/weather_domain/radiation_derived_features_adder.py +0 -0
  79. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/utils/__init__.py +0 -0
  80. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/utils/data_split.py +0 -0
  81. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/utils/evaluation_functions.py +0 -0
  82. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/utils/feature_selection.py +0 -0
  83. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/utils/loss_functions.py +0 -0
  84. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/utils/xgboost.py +0 -0
  85. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/workflows/__init__.py +0 -0
  86. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/workflows/callbacks/__init__.py +0 -0
  87. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/workflows/callbacks/data_save.py +0 -0
  88. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/workflows/callbacks/model_performance_callback.py +0 -0
  89. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/workflows/custom_component_split_workflow.py +0 -0
  90. {openstef_models-4.1.2 → openstef_models-4.2.2}/src/openstef_models/workflows/custom_forecasting_workflow.py +0 -0
  91. {openstef_models-4.1.2 → openstef_models-4.2.2}/tests/__init__.py +0 -0
  92. {openstef_models-4.1.2 → openstef_models-4.2.2}/tests/integration/__init__.py +0 -0
  93. {openstef_models-4.1.2 → openstef_models-4.2.2}/tests/integration/test_integration.py +0 -0
  94. {openstef_models-4.1.2 → openstef_models-4.2.2}/tests/unit/__init__.py +0 -0
  95. {openstef_models-4.1.2 → openstef_models-4.2.2}/tests/unit/explainability/__init__.py +0 -0
  96. {openstef_models-4.1.2 → openstef_models-4.2.2}/tests/unit/explainability/plotters/__init__.py +0 -0
  97. {openstef_models-4.1.2 → openstef_models-4.2.2}/tests/unit/explainability/plotters/test_contributions_plotter.py +0 -0
  98. {openstef_models-4.1.2 → openstef_models-4.2.2}/tests/unit/integrations/__init__.py +0 -0
  99. {openstef_models-4.1.2 → openstef_models-4.2.2}/tests/unit/integrations/joblib/__init__.py +0 -0
  100. {openstef_models-4.1.2 → openstef_models-4.2.2}/tests/unit/integrations/joblib/test_joblib_model_serializer.py +0 -0
  101. {openstef_models-4.1.2 → openstef_models-4.2.2}/tests/unit/integrations/mlflow/__init__.py +0 -0
  102. {openstef_models-4.1.2 → openstef_models-4.2.2}/tests/unit/integrations/mlflow/test_mlflow_storage.py +0 -0
  103. {openstef_models-4.1.2 → openstef_models-4.2.2}/tests/unit/integrations/mlflow/test_mlflow_storage_callback.py +0 -0
  104. {openstef_models-4.1.2 → openstef_models-4.2.2}/tests/unit/integrations/optuna/__init__.py +0 -0
  105. {openstef_models-4.1.2 → openstef_models-4.2.2}/tests/unit/integrations/optuna/test_tuner.py +0 -0
  106. {openstef_models-4.1.2 → openstef_models-4.2.2}/tests/unit/models/__init__.py +0 -0
  107. {openstef_models-4.1.2 → openstef_models-4.2.2}/tests/unit/models/component_splitting/__init__.py +0 -0
  108. {openstef_models-4.1.2 → openstef_models-4.2.2}/tests/unit/models/component_splitting/test_constant_component_splitter.py +0 -0
  109. {openstef_models-4.1.2 → openstef_models-4.2.2}/tests/unit/models/component_splitting/test_linear_component_splitter.py +0 -0
  110. {openstef_models-4.1.2 → openstef_models-4.2.2}/tests/unit/models/forecasting/__init__.py +0 -0
  111. {openstef_models-4.1.2 → openstef_models-4.2.2}/tests/unit/models/forecasting/conftest.py +0 -0
  112. {openstef_models-4.1.2 → openstef_models-4.2.2}/tests/unit/models/forecasting/test_base_case_forecaster.py +0 -0
  113. {openstef_models-4.1.2 → openstef_models-4.2.2}/tests/unit/models/forecasting/test_constant_quantile_forecaster.py +0 -0
  114. {openstef_models-4.1.2 → openstef_models-4.2.2}/tests/unit/models/forecasting/test_flatliner_forecaster.py +0 -0
  115. {openstef_models-4.1.2 → openstef_models-4.2.2}/tests/unit/models/forecasting/test_gblinear_forecaster.py +0 -0
  116. {openstef_models-4.1.2 → openstef_models-4.2.2}/tests/unit/models/forecasting/test_lgbm_forecaster.py +0 -0
  117. {openstef_models-4.1.2 → openstef_models-4.2.2}/tests/unit/models/forecasting/test_lgbmlinear_forecaster.py +0 -0
  118. {openstef_models-4.1.2 → openstef_models-4.2.2}/tests/unit/models/forecasting/test_median_forecaster.py +0 -0
  119. {openstef_models-4.1.2 → openstef_models-4.2.2}/tests/unit/models/forecasting/test_xgboost_forecaster.py +0 -0
  120. {openstef_models-4.1.2 → openstef_models-4.2.2}/tests/unit/models/test_forecasting_model.py +0 -0
  121. {openstef_models-4.1.2 → openstef_models-4.2.2}/tests/unit/test_example.py +0 -0
  122. {openstef_models-4.1.2 → openstef_models-4.2.2}/tests/unit/transforms/__init__.py +0 -0
  123. {openstef_models-4.1.2 → openstef_models-4.2.2}/tests/unit/transforms/energy_domain/__init__.py +0 -0
  124. {openstef_models-4.1.2 → openstef_models-4.2.2}/tests/unit/transforms/energy_domain/test_wind_power_feature_adder.py +0 -0
  125. {openstef_models-4.1.2 → openstef_models-4.2.2}/tests/unit/transforms/general/__init__.py +0 -0
  126. {openstef_models-4.1.2 → openstef_models-4.2.2}/tests/unit/transforms/general/test_dimensionality_reducer.py +0 -0
  127. {openstef_models-4.1.2 → openstef_models-4.2.2}/tests/unit/transforms/general/test_empty_feature_remover.py +0 -0
  128. {openstef_models-4.1.2 → openstef_models-4.2.2}/tests/unit/transforms/general/test_flagger.py +0 -0
  129. {openstef_models-4.1.2 → openstef_models-4.2.2}/tests/unit/transforms/general/test_imputer.py +0 -0
  130. {openstef_models-4.1.2 → openstef_models-4.2.2}/tests/unit/transforms/general/test_nan_dropper.py +0 -0
  131. {openstef_models-4.1.2 → openstef_models-4.2.2}/tests/unit/transforms/general/test_outlier_handler.py +0 -0
  132. {openstef_models-4.1.2 → openstef_models-4.2.2}/tests/unit/transforms/general/test_sample_weighter.py +0 -0
  133. {openstef_models-4.1.2 → openstef_models-4.2.2}/tests/unit/transforms/general/test_scaler.py +0 -0
  134. {openstef_models-4.1.2 → openstef_models-4.2.2}/tests/unit/transforms/general/test_selector.py +0 -0
  135. {openstef_models-4.1.2 → openstef_models-4.2.2}/tests/unit/transforms/general/test_shifter.py +0 -0
  136. {openstef_models-4.1.2 → openstef_models-4.2.2}/tests/unit/transforms/postprocessing/__init__.py +0 -0
  137. {openstef_models-4.1.2 → openstef_models-4.2.2}/tests/unit/transforms/postprocessing/test_confidence_interval_applicator.py +0 -0
  138. {openstef_models-4.1.2 → openstef_models-4.2.2}/tests/unit/transforms/postprocessing/test_isotonic_quantile_calibrator.py +0 -0
  139. {openstef_models-4.1.2 → openstef_models-4.2.2}/tests/unit/transforms/postprocessing/test_quantile_sorter.py +0 -0
  140. {openstef_models-4.1.2 → openstef_models-4.2.2}/tests/unit/transforms/time_domain/__init__.py +0 -0
  141. {openstef_models-4.1.2 → openstef_models-4.2.2}/tests/unit/transforms/time_domain/test_cyclic_features_adder.py +0 -0
  142. {openstef_models-4.1.2 → openstef_models-4.2.2}/tests/unit/transforms/time_domain/test_datetime_features_adder.py +0 -0
  143. {openstef_models-4.1.2 → openstef_models-4.2.2}/tests/unit/transforms/time_domain/test_holiday_features_adder.py +0 -0
  144. {openstef_models-4.1.2 → openstef_models-4.2.2}/tests/unit/transforms/time_domain/test_lags_adder.py +0 -0
  145. {openstef_models-4.1.2 → openstef_models-4.2.2}/tests/unit/transforms/time_domain/test_rolling_aggregates_adder.py +0 -0
  146. {openstef_models-4.1.2 → openstef_models-4.2.2}/tests/unit/transforms/time_domain/test_versioned_lags_adder.py +0 -0
  147. {openstef_models-4.1.2 → openstef_models-4.2.2}/tests/unit/transforms/validation/__init__.py +0 -0
  148. {openstef_models-4.1.2 → openstef_models-4.2.2}/tests/unit/transforms/validation/test_completeness_checker.py +0 -0
  149. {openstef_models-4.1.2 → openstef_models-4.2.2}/tests/unit/transforms/validation/test_flatline_checker.py +0 -0
  150. {openstef_models-4.1.2 → openstef_models-4.2.2}/tests/unit/transforms/validation/test_input_consistency_checker.py +0 -0
  151. {openstef_models-4.1.2 → openstef_models-4.2.2}/tests/unit/transforms/weather_domain/__init__.py +0 -0
  152. {openstef_models-4.1.2 → openstef_models-4.2.2}/tests/unit/transforms/weather_domain/test_atmosphere_derived_features_adder.py +0 -0
  153. {openstef_models-4.1.2 → openstef_models-4.2.2}/tests/unit/transforms/weather_domain/test_daylight_feature_adder.py +0 -0
  154. {openstef_models-4.1.2 → openstef_models-4.2.2}/tests/unit/transforms/weather_domain/test_radiation_derived_featuers_adder.py +0 -0
  155. {openstef_models-4.1.2 → openstef_models-4.2.2}/tests/unit/utils/__init__.py +0 -0
  156. {openstef_models-4.1.2 → openstef_models-4.2.2}/tests/unit/utils/test_data_split.py +0 -0
  157. {openstef_models-4.1.2 → openstef_models-4.2.2}/tests/unit/utils/test_feature_selection.py +0 -0
  158. {openstef_models-4.1.2 → openstef_models-4.2.2}/tests/unit/utils/test_loss_functions.py +0 -0
  159. {openstef_models-4.1.2 → openstef_models-4.2.2}/tests/unit/workflows/__init__.py +0 -0
  160. {openstef_models-4.1.2 → openstef_models-4.2.2}/tests/unit/workflows/callbacks/__init__.py +0 -0
  161. {openstef_models-4.1.2 → openstef_models-4.2.2}/tests/unit/workflows/callbacks/test_model_performance_callback.py +0 -0
  162. {openstef_models-4.1.2 → openstef_models-4.2.2}/tests/unit/workflows/test_custom_forecasting_workflow.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: openstef-models
3
- Version: 4.1.2
3
+ Version: 4.2.2
4
4
  Summary: Core models for OpenSTEF
5
5
  Project-URL: Documentation, https://openstef.github.io/openstef/index.html
6
6
  Project-URL: Homepage, https://lfenergy.org/projects/openstef/
@@ -7,7 +7,7 @@ requires = [ "hatchling" ]
7
7
 
8
8
  [project]
9
9
  name = "openstef-models"
10
- version = "4.1.2"
10
+ version = "4.2.2"
11
11
  description = "Core models for OpenSTEF"
12
12
  readme = "README.md"
13
13
  keywords = [ "energy", "forecasting", "machinelearning" ]
@@ -111,6 +111,12 @@ class LGBMHyperParams(HyperParams):
111
111
  description="Fraction of features used when constructing each tree. Range: (0,1]",
112
112
  )
113
113
 
114
+ # Early Stopping
115
+ early_stopping_rounds: int | None = Field(
116
+ default=None,
117
+ description="Training will stop if performance doesn't improve for this many rounds. Requires validation data.",
118
+ )
119
+
114
120
  @classmethod
115
121
  def forecaster_class(cls) -> "type[LGBMForecaster]":
116
122
  """Create a LightGBM forecaster instance from this configuration.
@@ -184,10 +190,6 @@ class LGBMForecaster(Forecaster, ExplainableForecaster, ContributionsMixin):
184
190
  alias="seed",
185
191
  description="Random seed for reproducibility.",
186
192
  )
187
- early_stopping_rounds: int | None = Field(
188
- default=None,
189
- description="Training stops if performance doesn't improve for this many rounds.",
190
- )
191
193
 
192
194
  _lgbm_model: MultiQuantileRegressor = PrivateAttr()
193
195
 
@@ -229,7 +231,7 @@ class LGBMForecaster(Forecaster, ExplainableForecaster, ContributionsMixin):
229
231
  "colsample_bytree": self.hyperparams.colsample_bytree,
230
232
  # General parameters
231
233
  "random_state": self.random_state,
232
- "early_stopping_rounds": self.early_stopping_rounds,
234
+ "early_stopping_rounds": self.hyperparams.early_stopping_rounds,
233
235
  "verbosity": self.verbosity,
234
236
  "n_jobs": self.n_jobs,
235
237
  }
@@ -111,6 +111,12 @@ class LGBMLinearHyperParams(HyperParams):
111
111
  description="Fraction of features used when constructing each tree. Range: (0,1]",
112
112
  )
113
113
 
114
+ # Early Stopping
115
+ early_stopping_rounds: int | None = Field(
116
+ default=None,
117
+ description="Training will stop if performance doesn't improve for this many rounds. Requires validation data.",
118
+ )
119
+
114
120
  @classmethod
115
121
  def forecaster_class(cls) -> "type[LGBMLinearForecaster]":
116
122
  """Get forecaster class for these hyperparams.
@@ -185,10 +191,6 @@ class LGBMLinearForecaster(Forecaster, ExplainableForecaster, ContributionsMixin
185
191
  alias="seed",
186
192
  description="Random seed for reproducibility.",
187
193
  )
188
- early_stopping_rounds: int | None = Field(
189
- default=None,
190
- description="Training stops if performance doesn't improve for this many rounds.",
191
- )
192
194
 
193
195
  _lgbmlinear_model: MultiQuantileRegressor = PrivateAttr()
194
196
 
@@ -230,7 +232,7 @@ class LGBMLinearForecaster(Forecaster, ExplainableForecaster, ContributionsMixin
230
232
  "colsample_bytree": self.hyperparams.colsample_bytree,
231
233
  # General parameters
232
234
  "random_state": self.random_state,
233
- "early_stopping_rounds": self.early_stopping_rounds,
235
+ "early_stopping_rounds": self.hyperparams.early_stopping_rounds,
234
236
  "verbosity": self.verbosity,
235
237
  "n_jobs": self.n_jobs,
236
238
  }
@@ -84,6 +84,9 @@ class MultiQuantileRegressor(BaseEstimator, RegressorMixin):
84
84
  """
85
85
  # Pass model-specific eval arguments
86
86
  kwargs = {}
87
+
88
+ x_array = np.asarray(X)
89
+
87
90
  for model in self._models:
88
91
  # Check if early stopping is supported
89
92
  # Check that eval_set is supported
@@ -91,21 +94,20 @@ class MultiQuantileRegressor(BaseEstimator, RegressorMixin):
91
94
  model.set_params(early_stopping_rounds=None)
92
95
 
93
96
  if eval_set is not None and self.learner_eval_sample_weight_param is not None:
97
+ kwargs["eval_set"] = [
98
+ (x_array if eval_x is X else np.asarray(eval_x), eval_y) for eval_x, eval_y in eval_set
99
+ ]
94
100
  kwargs[self.learner_eval_sample_weight_param] = eval_sample_weight
95
-
96
- if "early_stopping_rounds" in self.hyperparams and self.learner_eval_sample_weight_param is not None:
97
- model.set_params(early_stopping_rounds=self.hyperparams["early_stopping_rounds"])
101
+ if "early_stopping_rounds" in self.hyperparams:
102
+ model.set_params(early_stopping_rounds=self.hyperparams["early_stopping_rounds"])
98
103
 
99
104
  if feature_name:
100
105
  self.model_feature_names = feature_name
101
106
  else:
102
107
  self.model_feature_names = []
103
108
 
104
- if eval_sample_weight is not None and self.learner_eval_sample_weight_param:
105
- kwargs[self.learner_eval_sample_weight_param] = eval_sample_weight
106
-
107
109
  model.fit( # type: ignore
108
- X=np.asarray(X),
110
+ X=x_array,
109
111
  y=y,
110
112
  sample_weight=sample_weight,
111
113
  **kwargs,
@@ -117,3 +117,28 @@ def test_is_fitted_true_after_fit(dataset: tuple[pd.DataFrame, pd.Series], basel
117
117
 
118
118
  # Assert
119
119
  assert model.is_fitted
120
+
121
+
122
+ def test_fit_forwards_eval_set_for_early_stopping_lgbm(dataset: tuple[pd.DataFrame, pd.Series]):
123
+ # Arrange
124
+ quantiles = [Quantile(0.1), Quantile(0.5), Quantile(0.9)]
125
+ early_stopping_rounds = 3
126
+ X, y = dataset
127
+ y = y.to_numpy()
128
+ X_train, y_train = X.iloc[:80], y[:80] # noqa: N806
129
+ X_val, y_val = X.iloc[80:], y[80:] # noqa: N806
130
+ model = MultiQuantileRegressor(
131
+ base_learner=LGBMRegressor,
132
+ quantile_param="alpha",
133
+ quantiles=quantiles,
134
+ hyperparams={"objective": "quantile", "n_estimators": 10, "early_stopping_rounds": early_stopping_rounds},
135
+ )
136
+
137
+ # Act
138
+ model.fit(X_train, y_train, eval_set=[(X_train, y_train), (X_val, y_val)])
139
+
140
+ # Assert
141
+ for estimator in model.models:
142
+ assert isinstance(estimator, LGBMRegressor)
143
+ assert estimator.get_params()["early_stopping_rounds"] == early_stopping_rounds
144
+ assert estimator.evals_result_