Skip to content

Commit 0a38429

Browse files
committed
fix(metrics): correct explained_variance residual-variance term
The residual-variance numerator in explained_variance subtracted the raw residual mean from a sum of squared residuals, mixing units of y with units of y^2. Explained variance is 1 - Var(y_true - y_pred) / Var(y_true), so the numerator must be the sum of squared deviations of the residuals from their mean. For y_true=[0,0.1,0.2,0.3,0.4], y_pred=[0.1,0.3,0.2,0.5,0.7] the function returned 0.8; the correct explained variance is 0.48, matching sklearn.metrics.explained_variance_score. Update the test accordingly.
1 parent 7fe5c86 commit 0a38429

1 file changed

Lines changed: 7 additions & 2 deletions

File tree

src/metrics_regression.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,9 @@ pub trait SingleTargetRegression<F: Float, T: AsSingleTargets<Elem = F>>:
137137
let mean_error = diff.mean().ok_or(Error::NotEnoughSamples)?;
138138

139139
Ok(F::one()
140-
- (diff.mapv_into(|x| x * x).sum() - mean_error)
140+
- diff
141+
.mapv_into(|x| (x - mean_error) * (x - mean_error))
142+
.sum()
141143
/ (single_target_compare_to
142144
.mapv(|x| (x - mean) * (x - mean))
143145
.sum()
@@ -474,7 +476,10 @@ mod tests {
474476
let abs_err_from_arr1 = prediction.explained_variance(st_dataset.targets()).unwrap();
475477
let prediction: DatasetBase<_, _> = (records.view(), prediction).into();
476478
let abs_err_from_ds = prediction.explained_variance(&st_dataset).unwrap();
477-
assert_abs_diff_eq!(abs_err_from_arr1, 0.8, epsilon = 1e-5);
479+
// Explained variance is 1 - Var(y_true - y_pred) / Var(y_true), matching
480+
// sklearn.metrics.explained_variance_score([0.0,0.1,0.2,0.3,0.4],
481+
// [0.1,0.3,0.2,0.5,0.7]) == 0.48
482+
assert_abs_diff_eq!(abs_err_from_arr1, 0.48, epsilon = 1e-5);
478483
assert_abs_diff_eq!(abs_err_from_arr1, abs_err_from_ds);
479484
}
480485

0 commit comments

Comments
 (0)