Skip to content

Apply new input validation to metrics.regression - #8044

Merged
rapids-bot[bot] merged 5 commits into
NVIDIA:mainfrom
csadorf:apply-new-validation-to-metrics.regression
May 6, 2026
Merged

Apply new input validation to metrics.regression#8044
rapids-bot[bot] merged 5 commits into
NVIDIA:mainfrom
csadorf:apply-new-validation-to-metrics.regression

Conversation

@csadorf

@csadorf csadorf commented May 1, 2026

Copy link
Copy Markdown
Contributor

Applies new input validation system to metrics.regression

Part of #7998

@csadorf
csadorf requested a review from a team as a code owner May 1, 2026 22:15
@csadorf
csadorf requested a review from jcrist May 1, 2026 22:15
@github-actions github-actions Bot added the Cython / Python Cython or Python issue label May 1, 2026
@coderabbitai

coderabbitai Bot commented May 1, 2026

Copy link
Copy Markdown

Caution

Review failed

Failed to post review comments

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Summary by CodeRabbit

  • Bug Fixes

    • Improved validation for regression metrics: stricter input coercion, consistent sample-length checks, clearer errors for incompatible shapes (treats (N,1) as (N,)), and robust sample-weight validation including support for custom weights in single-output cases.
  • Tests

    • Added regression tests for scalar vs. weighted behavior, 1D/2D y equivalence with sklearn parity, and error handling for invalid inputs.
  • Chores

    • Updated test exclusions and file header metadata.

Walkthrough

Replace ad-hoc array conversion with shared validation helpers in regression metrics: y_true/y_pred validated with check_array and check_consistent_length, sample_weight with check_sample_weight; enforce dimensional checks and (N,) ↔ (N,1) equivalence; add parametrized regression metric tests; update SPDX year to 2026.

Changes

Regression metric input validation + tests

Layer / File(s) Summary
Data Shape / Types
python/cuml/cuml/metrics/regression.py
Replace input_to_cupy_array import with check_array, check_consistent_length, check_sample_weight; update file header year to 2026.
Core Validation Logic
python/cuml/cuml/metrics/regression.py
_normalize_regression_metric_args now uses check_array for y_true/y_pred, enforces consistent sample length, ravels (N,1) to (N,), and raises ValueError for incompatible ndim or mismatched 2D column counts.
Multioutput Handling
python/cuml/cuml/metrics/regression.py
Non-string multioutput is validated with check_array and must be 1D of length n_cols; prior rejection when n_cols == 1 removed.
Sample-weight Handling
python/cuml/cuml/metrics/regression.py
sample_weight validated via check_sample_weight, checked for consistent length with y_true, promoted to column-vector convention; 2D weights rejected with appropriate message.
Tests / Coverage
python/cuml/tests/test_metrics.py
Add _REGRESSION_FUNCS and parametrized tests verifying scalar sample_weight equivalence, (N,) vs (N,1) equivalence for y_true/y_pred, and error cases for inconsistent lengths and non-1D sample_weight.

scikit-learn xfail list tweak

Layer / File(s) Summary
Test Exclusions
python/cuml/cuml_accel_tests/upstream/scikit-learn/xfail-list.yaml
For scikit-learn<1.6, replaced -check_dtype_object exclusions with -check_fit2d_1feature and -check_supervised_y_2d entries for various GridSearch/Halving*SearchCV + Ridge/LogisticRegression scenarios.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

  • rapidsai/cuml#8050: Applies the same pattern of replacing input_to_cupy_array with check_array in metrics validation.

Suggested reviewers

  • jcrist
  • divyegala
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Apply new input validation to metrics.regression' directly and clearly summarizes the main change: applying new input validation to the regression metrics module.
Description check ✅ Passed The description is directly related to the changeset, explaining that it applies the new input validation system to metrics.regression and references the related issue #7998.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
python/cuml/tests/test_metrics.py (1)

790-805: ⚡ Quick win

Add a mixed (n,) vs (n, 1) regression case to this error suite

This block now checks length and sample-weight errors, but it doesn’t guard the single-output mixed-dimension normalization path. Adding that case here will prevent regressions in _normalize_regression_metric_args.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@python/cuml/tests/test_metrics.py` around lines 790 - 805, Add a test for the
single-output mixed-dimension case in test_regression_metrics_errors: create a
(n,1) target/prediction (e.g., arr_3_col = np.array([[1.0],[2.0],[3.0]])) and
call cu_metric(arr_3, arr_3_col) and cu_metric(arr_3_col, arr_3) inside
pytest.raises(ValueError) to ensure _normalize_regression_metric_args rejects
(n,) vs (n,1) mismatches; reference the existing test_regression_metrics_errors,
_REGRESSION_FUNCS and cu_metric when adding these assertions.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@python/cuml/cuml/metrics/regression.py`:
- Around line 33-49: The shape-checking rejects valid cases like y_true.ndim==1
vs y_pred.shape==(n,1); instead, first normalize 1D targets by promoting y_true
and y_pred to column vectors (the reshape logic currently in the block using
y_true.reshape and y_pred.reshape) before performing the dimensionality/shape
consistency check, then run sample_weight = check_sample_weight(...) and
check_consistent_length(...) against the normalized y_true; update references to
y_true/y_pred in the initial validation to use the promoted versions so
functions like check_sample_weight and check_consistent_length operate on the
normalized arrays.

---

Nitpick comments:
In `@python/cuml/tests/test_metrics.py`:
- Around line 790-805: Add a test for the single-output mixed-dimension case in
test_regression_metrics_errors: create a (n,1) target/prediction (e.g.,
arr_3_col = np.array([[1.0],[2.0],[3.0]])) and call cu_metric(arr_3, arr_3_col)
and cu_metric(arr_3_col, arr_3) inside pytest.raises(ValueError) to ensure
_normalize_regression_metric_args rejects (n,) vs (n,1) mismatches; reference
the existing test_regression_metrics_errors, _REGRESSION_FUNCS and cu_metric
when adding these assertions.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 86eaec2a-7c37-4066-890c-6685893d0d97

📥 Commits

Reviewing files that changed from the base of the PR and between c840432 and 2801d16.

📒 Files selected for processing (2)
  • python/cuml/cuml/metrics/regression.py
  • python/cuml/tests/test_metrics.py

Comment thread python/cuml/cuml/metrics/regression.py
@csadorf csadorf added improvement Improvement / enhancement to an existing function non-breaking Non-breaking change labels May 4, 2026
@csadorf
csadorf force-pushed the apply-new-validation-to-metrics.regression branch from 2801d16 to e934ce2 Compare May 4, 2026 22:02

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

♻️ Duplicate comments (1)
python/cuml/cuml/metrics/regression.py (1)

33-49: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Normalize 1D targets before shape mismatch checks (mixed (n,)/(n,1) should be accepted).

Current ordering raises on valid single-output mixed shapes before normalization, which breaks sklearn-compatible behavior.

Proposed fix
-    if y_true.ndim != y_pred.ndim or (
-        y_true.ndim == 2 and y_true.shape[1] != y_pred.shape[1]
-    ):
-        raise ValueError(
-            f"y_true and y_pred have different shapes: "
-            f"{y_true.shape} vs {y_pred.shape}"
-        )
-
-    if (
-        sample_weight := check_sample_weight(sample_weight, dtype=np.float64)
-    ) is not None:
-        check_consistent_length(y_true, sample_weight)
-
-    # Promote 1D inputs to column vectors
-    if y_true.ndim == 1:
-        y_true = y_true.reshape((-1, 1))
-        y_pred = y_pred.reshape((-1, 1))
+    # Promote 1D inputs to column vectors
+    if y_true.ndim == 1:
+        y_true = y_true.reshape((-1, 1))
+    if y_pred.ndim == 1:
+        y_pred = y_pred.reshape((-1, 1))
+
+    if y_true.ndim != y_pred.ndim or y_true.shape[1] != y_pred.shape[1]:
+        raise ValueError(
+            f"y_true and y_pred have different shapes: "
+            f"{y_true.shape} vs {y_pred.shape}"
+        )
+
+    if (
+        sample_weight := check_sample_weight(sample_weight, dtype=np.float64)
+    ) is not None:
+        check_consistent_length(y_true, sample_weight)
In current scikit-learn regression metrics input validation, are y_true.shape == (n_samples,) and y_pred.shape == (n_samples, 1) treated as valid by promoting 1D arrays to column vectors before shape comparison?

As per coding guidelines: “Function and parameter names or defaults must match scikit-learn without justification; behavior for edge cases (empty arrays, single sample) must match scikit-learn.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@python/cuml/cuml/metrics/regression.py` around lines 33 - 49, The current
validation raises on mixed single-output shapes because the 1D-to-column
promotion occurs after the shape mismatch check; move the "Promote 1D inputs to
column vectors" step so y_true and y_pred are reshaped to (-1,1) when ndim == 1
before any shape equality check, then run the existing shape validation (the
block that raises ValueError) and the sample_weight handling
(check_sample_weight and check_consistent_length) afterwards; update references
in this function to ensure y_true, y_pred are normalized prior to comparing
shapes so inputs like (n,) and (n,1) are accepted.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Duplicate comments:
In `@python/cuml/cuml/metrics/regression.py`:
- Around line 33-49: The current validation raises on mixed single-output shapes
because the 1D-to-column promotion occurs after the shape mismatch check; move
the "Promote 1D inputs to column vectors" step so y_true and y_pred are reshaped
to (-1,1) when ndim == 1 before any shape equality check, then run the existing
shape validation (the block that raises ValueError) and the sample_weight
handling (check_sample_weight and check_consistent_length) afterwards; update
references in this function to ensure y_true, y_pred are normalized prior to
comparing shapes so inputs like (n,) and (n,1) are accepted.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: fcc90403-2bf0-4416-8e27-95be0a7bcefe

📥 Commits

Reviewing files that changed from the base of the PR and between 2801d16 and e934ce2.

📒 Files selected for processing (2)
  • python/cuml/cuml/metrics/regression.py
  • python/cuml/tests/test_metrics.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • python/cuml/tests/test_metrics.py

@csadorf
csadorf force-pushed the apply-new-validation-to-metrics.regression branch from e934ce2 to af0c584 Compare May 5, 2026 15:37

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@python/cuml/tests/test_metrics.py`:
- Around line 786-787: Replace the brittle exact-equality asserts in
test_metrics that compare floating outputs (the two lines calling
cu_metric(y_true, y_pred, sample_weight=...) == unweighted) with tolerant float
comparisons: use a numeric-approx helper such as numpy.testing.assert_allclose
or pytest.approx to compare cu_metric(y_true, y_pred, sample_weight=...) to
unweighted with an appropriate tolerance. Update the two assertions that
reference cu_metric, y_true, y_pred, sample_weight and unweighted to use the
chosen tolerant assertion helper.
- Around line 778-827: Update the three tests to compare cuML outputs/errors
directly to scikit-learn: in test_regression_metrics_scalar_sample_weight, get
skl_metric = getattr(sklearn.metrics, func) and assert skl_metric(y_true,
y_pred) equals cu_metric(y_true, y_pred, sample_weight=1.0) and
sample_weight=2.5 (use exact equality or np.testing.assert_allclose as
appropriate); in test_regression_metrics_1d_2d_equivalence, compute expected =
skl_metric(y_true_1d, y_pred_1d) and assert got (from different shapes) matches
expected using np.testing.assert_allclose; in test_regression_metrics_errors,
call skl_metric on the same bad inputs to confirm it raises the same ValueError
patterns and use pytest.raises with similar match strings to assert parity
between cu_metric and skl_metric for inconsistent sample counts and non-1D
sample_weight. Ensure you import sklearn.metrics at top and reuse func to locate
corresponding skl function.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: ddce1068-caf9-4040-ac25-e4c0497ce4a6

📥 Commits

Reviewing files that changed from the base of the PR and between e934ce2 and af0c584.

📒 Files selected for processing (3)
  • python/cuml/cuml/metrics/regression.py
  • python/cuml/cuml_accel_tests/upstream/scikit-learn/xfail-list.yaml
  • python/cuml/tests/test_metrics.py
💤 Files with no reviewable changes (1)
  • python/cuml/cuml_accel_tests/upstream/scikit-learn/xfail-list.yaml
🚧 Files skipped from review as they are similar to previous changes (1)
  • python/cuml/cuml/metrics/regression.py

Comment thread python/cuml/tests/test_metrics.py
@csadorf
csadorf force-pushed the apply-new-validation-to-metrics.regression branch from af0c584 to 163b214 Compare May 5, 2026 17:59

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

♻️ Duplicate comments (1)
python/cuml/tests/test_metrics.py (1)

787-788: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Use tolerant float assertions for metric outputs.

At Line 787 and Line 788, exact == on floating outputs can make this test flaky across backends/dtypes. Use assert_allclose (or assert_almost_equal) for both checks.

Suggested patch
-    assert cu_metric(y_true, y_pred, sample_weight=1.0) == unweighted
-    assert cu_metric(y_true, y_pred, sample_weight=2.5) == unweighted
+    np.testing.assert_allclose(
+        cu_metric(y_true, y_pred, sample_weight=1.0), unweighted
+    )
+    np.testing.assert_allclose(
+        cu_metric(y_true, y_pred, sample_weight=2.5), unweighted
+    )
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@python/cuml/tests/test_metrics.py` around lines 787 - 788, Replace the exact
equality checks on floating metric outputs with tolerant assertions: change the
two assertions that call cu_metric(y_true, y_pred, sample_weight=1.0) and
cu_metric(y_true, y_pred, sample_weight=2.5) to use a float-tolerant check
(e.g., numpy.testing.assert_allclose or pytest.approx). Update the test to call
assert_allclose(actual, unweighted, rtol=..., atol=...) for both sample_weight
cases so small backend/dtype differences don't make the test flaky; keep
references to the cu_metric calls and the same y_true/y_pred inputs.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Duplicate comments:
In `@python/cuml/tests/test_metrics.py`:
- Around line 787-788: Replace the exact equality checks on floating metric
outputs with tolerant assertions: change the two assertions that call
cu_metric(y_true, y_pred, sample_weight=1.0) and cu_metric(y_true, y_pred,
sample_weight=2.5) to use a float-tolerant check (e.g.,
numpy.testing.assert_allclose or pytest.approx). Update the test to call
assert_allclose(actual, unweighted, rtol=..., atol=...) for both sample_weight
cases so small backend/dtype differences don't make the test flaky; keep
references to the cu_metric calls and the same y_true/y_pred inputs.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: b1fc170f-8931-435c-a7c6-9393c08d95dd

📥 Commits

Reviewing files that changed from the base of the PR and between af0c584 and 163b214.

📒 Files selected for processing (2)
  • python/cuml/cuml_accel_tests/upstream/scikit-learn/xfail-list.yaml
  • python/cuml/tests/test_metrics.py
💤 Files with no reviewable changes (1)
  • python/cuml/cuml_accel_tests/upstream/scikit-learn/xfail-list.yaml

csadorf added 2 commits May 5, 2026 21:25
…regression metrics

test_regression_metrics_scalar_sample_weight:
  Compare cuML outputs to sklearn for unweighted and sample_weight=1.0
  using np.testing.assert_allclose (exact == fails due to float drift)
  Use 1D array for sklearn sample_weight since it rejects scalar input

test_regression_metrics_1d_2d_equivalence:
  Use sklearn as expected reference instead of cuML(1d) to verify all
  shape permutations produce identical results

test_regression_metrics_errors:
  Assert both cuML and sklearn raise the same ValueError for
  inconsistent sample counts and 2D sample_weight
  Narrow regex from 'inconsistent number of samples' to 'inconsistent'
  since sklearn uses 'inconsistent numbers of samples' (plural)
sklearn standardized the error messages for invalid sample_weight
inputs in 1.7. On 1.5.x and 1.6.x the five parameterizations of
test_regression_metrics_errors fail because the match= regexes
("Sample weights must be 1D" / "inconsistent") don't match the
older messages raised by numpy.average or column_or_1d.

Mark the test xfail with strict=True when sklearn < 1.7 so the
oldest-deps CI matrix (sklearn==1.5.0) reports XFAIL instead of
FAILED, while 1.7+ continues to run and pass.
@csadorf
csadorf force-pushed the apply-new-validation-to-metrics.regression branch from 163b214 to 8cd284e Compare May 6, 2026 15:57

@jcrist jcrist left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

:shipit:

if (
sample_weight := check_sample_weight(sample_weight, dtype=np.float64)
) is not None:
check_consistent_length(y_true, sample_weight)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Not a problem, but note that check_consistent_length works fine even if some of the inputs are None. So you can unconditionally call it on all input arrays, including optional ones.

@jcrist

jcrist commented May 6, 2026

Copy link
Copy Markdown
Member

/merge

@rapids-bot
rapids-bot Bot merged commit eae528e into NVIDIA:main May 6, 2026
93 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Cython / Python Cython or Python issue improvement Improvement / enhancement to an existing function non-breaking Non-breaking change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants