Description
The EXACT_FAST and SUBSET_SAMPLING Shapley approximation methods in dowhy.gcm.shapley return incorrect values on scikit-learn 1.9.0. Three tests fail:
test_given_many_features_when_estimate_shapley_values_exact_fast_then_returns_correct_linear_shapley_values
test_given_many_features_when_estimate_shapley_values_with_subset_sampling_then_returns_correct_linear_shapley_values
test_given_specific_random_seed_when_estimate_shapley_values_with_subset_sampling_then_returns_deterministic_result
Caught by the latest-deps CI work in #1665 / #1672 (fails there on every run with scikit-learn 1.9.0; passes on 1.8.0).
Root cause
_approximate_shapley_values_via_least_squares_regression solves a weighted least squares problem via LinearRegression().fit(..., sample_weight=weights) where the full/empty subsets get weight 10**20 (to approximate equality constraints) and all other subsets weight ~1. scikit-learn 1.9 changed LinearRegression's solve path for sample weights, and with weights spanning 20 orders of magnitude the solution now loses all precision.
Minimal repro independent of DoWhy:
import numpy as np
from sklearn.linear_model import LinearRegression
rng = np.random.RandomState(0)
X = (rng.uniform(size=(500, 12)) < 0.5).astype(float)
X[0] = 0.0; X[1] = 1.0
beta = rng.normal(size=12)
y = X @ beta + 3.0
w = np.ones(500); w[0] = w[1] = 1e20
coef = LinearRegression().fit(X, y, sample_weight=w).coef_
print(np.max(np.abs(coef - beta)))
# scikit-learn 1.8.0: ~1e-14
# scikit-learn 1.9.0: ~2.08
Fix
Solve the weighted least squares explicitly (weighted centering + np.linalg.lstsq on the square-root-weighted system), which reproduces the numerically stable behavior and makes the result independent of solver changes in third-party libraries. PR: #1699.
Note
test_anomaly_attribution.py::...feature_relevance... also fails in the latest-deps CI runs, but that turns out to be a pre-existing order/RNG-sensitive test (it fails on main with scikit-learn 1.8 too depending on the random state; the @flaky retries can't save it in CI because the suite ordering makes the failure deterministic). That's a separate test-robustness issue.
Description
The
EXACT_FASTandSUBSET_SAMPLINGShapley approximation methods indowhy.gcm.shapleyreturn incorrect values on scikit-learn 1.9.0. Three tests fail:test_given_many_features_when_estimate_shapley_values_exact_fast_then_returns_correct_linear_shapley_valuestest_given_many_features_when_estimate_shapley_values_with_subset_sampling_then_returns_correct_linear_shapley_valuestest_given_specific_random_seed_when_estimate_shapley_values_with_subset_sampling_then_returns_deterministic_resultCaught by the latest-deps CI work in #1665 / #1672 (fails there on every run with scikit-learn 1.9.0; passes on 1.8.0).
Root cause
_approximate_shapley_values_via_least_squares_regressionsolves a weighted least squares problem viaLinearRegression().fit(..., sample_weight=weights)where the full/empty subsets get weight10**20(to approximate equality constraints) and all other subsets weight ~1. scikit-learn 1.9 changedLinearRegression's solve path for sample weights, and with weights spanning 20 orders of magnitude the solution now loses all precision.Minimal repro independent of DoWhy:
Fix
Solve the weighted least squares explicitly (weighted centering +
np.linalg.lstsqon the square-root-weighted system), which reproduces the numerically stable behavior and makes the result independent of solver changes in third-party libraries. PR: #1699.Note
test_anomaly_attribution.py::...feature_relevance...also fails in the latest-deps CI runs, but that turns out to be a pre-existing order/RNG-sensitive test (it fails onmainwith scikit-learn 1.8 too depending on the random state; the@flakyretries can't save it in CI because the suite ordering makes the failure deterministic). That's a separate test-robustness issue.