Skip to content

fix: import scikit-learn lazily in openstef-beam r2 metric - #981

Open
Valyrian-Code wants to merge 6 commits into
OpenSTEF:mainfrom
Valyrian-Code:fix/beam-lazy-sklearn-805
Open

fix: import scikit-learn lazily in openstef-beam r2 metric#981
Valyrian-Code wants to merge 6 commits into
OpenSTEF:mainfrom
Valyrian-Code:fix/beam-lazy-sklearn-805

Conversation

@Valyrian-Code

Copy link
Copy Markdown
Contributor

What

scikit-learn is an optional dependency of openstef-beam (it is not declared in the package's dependencies), but metrics_deterministic.py imported r2_score from sklearn.metrics at module top. As a result, importing openstef_beam.metrics (or anything that pulls it in) failed with ModuleNotFoundError when scikit-learn was not installed. Resolves #805.

Fix

Move the from sklearn.metrics import r2_score import inside the r2() function, its only use site. Importing the module no longer requires scikit-learn; only calling r2() does.

Tests

  • test_r2_score_is_imported_lazily: asserts r2_score is not bound at module level (locks the lazy import).
  • test_r2_still_computes_with_sklearn_available: confirms r2() still computes correctly.

ty check, ruff check, ruff format --check, the module doctests, and the full beam metrics suite all pass.

@Valyrian-Code
Valyrian-Code requested a review from a team June 19, 2026 17:55

@egordm egordm left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure about this one. R2 is used as default in many openstef components. Making the import lazy would notify users only at runtime that they are missing a dependency.

I don't think making it lazy is the right approach.

It is really tempting to inline R2 though, which would remove openstef-beam's dependency on sklearn.

Valyrian-Code added a commit to Valyrian-Code/openstef that referenced this pull request Jun 25, 2026
Per @egordm's review on OpenSTEF#981: instead of lazily importing sklearn's r2_score,
compute R2 directly with numpy so openstef-beam no longer depends on
scikit-learn at all. Matches scikit-learn's r2_score including sample weights
and the constant-y_true convention (1.0 for a perfect fit, else 0.0).

Signed-off-by: RAJVEER42 <irajveer.bishnoi2310@gmail.com>
@Valyrian-Code

Copy link
Copy Markdown
Contributor Author

Good call, thanks! I've inlined the R2 computation in numpy, so openstef-beam no longer depends on scikit-learn at all rather than just deferring the import to runtime. It matches scikit-learn's r2_score including sample weights and the constant-y_true convention (1.0 for a perfect fit, else 0.0), and I added value tests to lock that down. Also merged latest main.

Copilot AI review requested due to automatic review settings July 3, 2026 01:37

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@Valyrian-Code

Copy link
Copy Markdown
Contributor Author

Updated per your suggestion, @egordm: R2 is now inlined in numpy so openstef-beam no longer depends on scikit-learn. I verified it matches sklearn.r2_score exactly across 2000 random cases (with and without sample weights) and the constant-y_true / negative-R2 cases. I also made it return NaN for fewer than two samples, matching scikit-learn's behaviour there. Ready for another look when you have a moment.

…#805)

openstef-beam imported sklearn.metrics.r2_score in metrics_deterministic
but never declared scikit-learn as a dependency, so r2 failed whenever
sklearn was absent. Reimplement R2 in numpy, matching scikit-learn for
the weighted, constant-target, and fewer-than-two-sample (NaN) cases,
and add unit tests covering them.

Signed-off-by: RAJVEER42 <irajveer.bishnoi2310@gmail.com>
@Valyrian-Code
Valyrian-Code force-pushed the fix/beam-lazy-sklearn-805 branch from d520473 to 4431c97 Compare July 3, 2026 01:57
Valyrian-Code and others added 4 commits July 6, 2026 22:26
Signed-off-by: Egor Dmitriev <egor.dmitriev@alliander.com>
Signed-off-by: Egor Dmitriev <egor.dmitriev@alliander.com>
Signed-off-by: Egor Dmitriev <egor.dmitriev@alliander.com>
Signed-off-by: Egor Dmitriev <egor.dmitriev@alliander.com>
…ror.

Signed-off-by: Egor Dmitriev <egor.dmitriev@alliander.com>
Signed-off-by: Egor Dmitriev <egor.dmitriev@alliander.com>

@egordm egordm left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great now. I added handing of additional edge cases so we don't throw errors on data issues, and throw errors on structure / logic issues.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[OpenSTEF 4.0] Fix optional dependencies stef-beam

3 participants