fix(xgboost): return error instead of panicking on empty training data - #448
Conversation
Signed-off-by: Sai Asish Y <say.apm35@gmail.com>
|
thanks. I am looking into this |
Code ReviewThanks for the fix, @SAY-5 — this is a well-scoped, sensible change. Here are some observations and suggestions: ✅ What works well
🟡 Suggestions / Minor Issues1. Error message wording "Training data must have at least one row."This is fine, but it could be slightly more actionable. Consider: "Training data must contain at least one sample; got 0 rows."This makes it immediately obvious to a user reading the error message what went wrong without having to trace back the call. 2. The panic originates in 3. Test: let full = DenseMatrix::from_2d_vec(&vec![vec![1.0, 1.0], vec![2.0, 1.0]]).unwrap();The two columns here are arbitrary; a comment like 4. let y: Vec<f64> = vec![];The type annotation is necessary here because 🔴 Edge case to considerZero columns ( The guard checks
For this PR, at minimum documenting this as a known limitation in a follow-up comment would be helpful. SummaryThe core fix is correct and the test covers the reported panic path. The main ask before merging is a check of whether |
Code Review —
|
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #448 +/- ##
===========================================
+ Coverage 43.97% 63.92% +19.95%
===========================================
Files 85 95 +10
Lines 7281 8217 +936
===========================================
+ Hits 3202 5253 +2051
+ Misses 4079 2964 -1115 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
Please check the code coverage report: #448 (comment) |
Mec-iS
left a comment
There was a problem hiding this comment.
thanks.
I will merge this and add some minor changes
- Extend guard to also reject zero-feature matrices (n_features == 0) - Improve error message to 'Training data must contain at least one sample and one feature.' - Add test_fit_on_zero_features_returns_error - Add comment on scaffold matrix in test_fit_on_empty_data_returns_error
* fix: fuse StandardScaler::transform to single-allocation pass Replace per-column take_column/sub_scalar/div_scalar/build_matrix_from_columns pattern with a single M::fill + element-wise (x - mean) / std loop. Eliminates O(d) medium Vec allocations and several full-matrix temporaries that caused ~9500x wall-time regression and RSS inflation on large matrices (4000x4000: 85.9s → 0.009s per issue #449). Remove now-dead build_matrix_from_columns helper and its test. Add comprehensive test covering all parameter combinations (with_mean, with_std, zero-variance columns, column-count mismatch) verified against numpy. * fix(xgboost): harden empty-data guard per #448 review - Extend guard to also reject zero-feature matrices (n_features == 0) - Improve error message to 'Training data must contain at least one sample and one feature.' - Add test_fit_on_zero_features_returns_error - Add comment on scaffold matrix in test_fit_on_empty_data_returns_error * fix(tree): guard all tree/ensemble fit methods against empty data Add n_samples == 0 || n_features == 0 guards to: - DecisionTreeClassifier::fit - BaseTreeRegressor::fit - RandomForestClassifier::fit - BaseForestRegressor::fit All return FailedError::ParametersError with message: 'Training data must contain at least one sample and one feature.' Previously these could panic (divide-by-zero, empty-range) or produce undefined models when called with zero-row or zero-column matrices. Regression tests added for each guarded path. * fix(preprocessing): row-major loop order in StandardScaler::transform Swap fused transform loop from column-outer/row-inner to row-outer/ col-inner with pre-computed (mean, std) Vec. DenseMatrix uses row-major layout, so the previous ordering caused strided reads and writes on large matrices. Also add zero-features regression tests for DecisionTreeClassifier and BaseForestRegressor to match BaseTreeRegressor coverage. Audit: ExtraTreesRegressor and RandomForestRegressor both delegate to BaseForestRegressor::fit which already has the guard — no changes needed. Addresses review feedback from Mec-iS on PR #450.
Fixes #446
Checklist
Current behaviour
XGRegressor::fitpanics on a training set with zero rows.find_best_splitruns0..sorted_idxs.len() - 1, which underflows on an empty slice; in debug builds this isattempt to subtract with overflowand in release builds it surfaces asindex out of bounds. A zero-row matrix is reachable through the publicArray2::take, so this is reachable from safe user code.New expected behaviour
fitvalidates that the training data has at least one row and returnsErr(Failed::because(FailedError::ParametersError, ...))for empty data, mirroring the existingsubsamplevalidation a few lines above. A model trained on no data is not useful, so this matches the error direction the reporter preferred. Non-empty inputs are unaffected. A regression test covers the empty-data case.