Example #1
0
 def test_predict_target_to_feature_dict(self, data, X_y, estimator):
     X, y = X_y
     target_to_feature_dict = data.draw(
         numeric_target_to_feature_dicts(n_targets=y.shape[1],
                                         n_features=X.shape[1]))
     multi_feature_multi_output_regressor = MultiFeatureMultiOutputRegressor(
         estimator)
     multi_feature_multi_output_regressor.fit(
         X, y, target_to_features_dict=target_to_feature_dict)
     X_predict = data.draw(numpy_X_matrices([100, X.shape[1]]))
     multi_feature_multi_output_regressor.predict(X_predict)
Example #2
0
 def test_error_predict_target_to_features_dict_wrong_X_shape(
         self, data, X_y, estimator):
     X, y = X_y
     target_to_features_dict = data.draw(
         numeric_target_to_features_dicts(n_targets=y.shape[1],
                                          n_features=X.shape[1]))
     multi_feature_multi_output_regressor = MultiFeatureMultiOutputRegressor(
         estimator, target_to_features_dict=target_to_features_dict)
     multi_feature_multi_output_regressor.fit(X, y)
     X_predict = data.draw(numpy_X_matrices([100, 30]))
     with pytest.raises(ValueError):
         multi_feature_multi_output_regressor.predict(X_predict)
 def test_no_infinity(self, data, shape):
     X = data.draw(numpy_X_matrices(shape, allow_nan=True, allow_infinity=False))
     assert not np.isinf(X).any()
 def test_min_max_values(self, data, shape, min_max_values):
     min_value, max_value = min_max_values
     X = data.draw(numpy_X_matrices(shape, min_value=min_value, max_value=max_value))
     assert X.min() >= min_value
     assert X.max() <= max_value
 def test_error_shape_0_smaller_shape_1(self, data):
     with pytest.raises(ValueError):
         data.draw(numpy_X_matrices([10, 20]))
 def test_input_as_strategy(self, data):
     data.draw(numpy_X_matrices(shape_matrix()))
 def test_input_as_tuples(self, data, shape):
     X = data.draw(numpy_X_matrices(shape))
     assert X.shape == shape
Example #8
0
class TestExplainableRegressor:
    @pytest.mark.parametrize("explainer_type", ["lime", "shap"])
    @given(estimator=regressors())
    def test_constructor(self, estimator, explainer_type):
        regressor = ExplainableRegressor(estimator, explainer_type)
        if explainer_type == "lime":
            assert isinstance(regressor.explainer, _LimeExplainer)
        elif explainer_type == "shap":
            assert isinstance(regressor.explainer, _ShapExplainer)

    @given(estimator=regressors())
    def test_constructor_bad_explainer(self, estimator):
        with pytest.raises(ValueError):
            ExplainableRegressor(estimator, "bad")

    @pytest.mark.parametrize("explainer_type", ["lime", "shap"])
    @given(bad_estimator=bad_regressors())
    def test_constructor_bad_regressor(self, bad_estimator, explainer_type):
        with pytest.raises(TypeError):
            ExplainableRegressor(bad_estimator, explainer_type)

    @pytest.mark.parametrize("explainer_type", ["lime", "shap"])
    @given(estimator=regressors(), X=numpy_X_matrices())
    def test_error_predict_not_fitted(self, estimator, explainer_type, X):
        regressor = ExplainableRegressor(estimator, explainer_type)
        with pytest.raises(NotFittedError):
            regressor.predict(X)

    def _get_fit_attributes(self, estimator: BaseEstimator) -> List[str]:
        return [
            v for v in vars(estimator)
            if v.endswith("_") and not v.startswith("__")
        ]

    @pytest.mark.parametrize("explainer_type", ["lime", "shap"])
    @given(estimator=regressors(),
           X_y=numpy_X_y_matrices(min_value=-100, max_value=100))
    def test_fit_values(self, estimator, explainer_type, X_y):
        X, y = X_y
        regressor = ExplainableRegressor(estimator, explainer_type)
        regressor.fit(X, y)

        cloned_estimator = clone(estimator)
        cloned_estimator.fit(X, y)

        estimator_fit_attributes = self._get_fit_attributes(
            regressor.estimator)
        cloned_estimator_fit_attributes = self._get_fit_attributes(
            cloned_estimator)

        np.testing.assert_array_equal(estimator_fit_attributes,
                                      cloned_estimator_fit_attributes)

    @settings(deadline=pd.Timedelta(milliseconds=5000), max_examples=7)
    @pytest.mark.parametrize("explainer_type", ["lime", "shap"])
    @given(estimator=regressors(),
           X_y=numpy_X_y_matrices(min_value=-100, max_value=100))
    def test_predict_values(self, estimator, explainer_type, X_y):
        X, y = X_y
        X_test = X[:1, :]
        regressor = ExplainableRegressor(estimator, explainer_type)
        regressor_predictions = regressor.fit(X, y).predict(X_test)

        cloned_estimator = clone(estimator)
        estimator_predictions = cloned_estimator.fit(X, y).predict(X_test)

        assert regressor_predictions.shape == estimator_predictions.shape
        assert regressor_predictions.shape[0] == len(regressor.explanations_)
Example #9
0
class TestMultiFeatureMultiOutputRegressor:
    def test_constructor(self, estimator):
        multi_feature_multi_output_regressor = MultiFeatureMultiOutputRegressor(
            estimator)
        assert multi_feature_multi_output_regressor.n_jobs == 1

    @given(
        data=data(),
        X_y=numpy_X_y_matrices(
            X_y_shapes=shape_X_y_matrices(y_as_vector=False),
            min_value=-10000,
            max_value=10000,
        ),
    )
    def test_fit_bad_y(self, data, estimator, X_y):
        X, y = X_y
        y = y[:, 0].flatten()
        target_to_feature_dict = data.draw(
            numeric_target_to_feature_dicts(n_targets=1,
                                            n_features=X.shape[1]))
        multi_feature_multi_output_regressor = MultiFeatureMultiOutputRegressor(
            estimator)
        with pytest.raises(ValueError):
            multi_feature_multi_output_regressor.fit(
                X, y, target_to_features_dict=target_to_feature_dict)

    @given(X_y=numpy_X_y_matrices(
        X_y_shapes=shape_X_y_matrices(y_as_vector=False),
        min_value=-10000,
        max_value=10000,
    ))
    def test_fit_as_multi_output_regressor_if_target_to_feature_none(
            self, estimator, X_y):
        X, y = X_y
        multi_feature_multi_output_regressor = MultiFeatureMultiOutputRegressor(
            estimator)
        multi_feature_multi_output_regressor.fit(X, y)

        multi_output_regressor = MultiOutputRegressor(estimator)
        multi_output_regressor.fit(X, y)

        assert_almost_equal(
            multi_feature_multi_output_regressor.predict(X),
            multi_output_regressor.predict(X),
        )

    @given(X=numpy_X_matrices(min_value=-10000, max_value=10000))
    def test_error_predict_with_no_fit(self, estimator, X):
        regressor = MultiFeatureMultiOutputRegressor(estimator)
        with pytest.raises(NotFittedError):
            regressor.predict(X)

    @given(
        data=data(),
        X_y=numpy_X_y_matrices(
            X_y_shapes=shape_X_y_matrices(y_as_vector=False),
            min_value=-10000,
            max_value=10000,
        ),
    )
    def test_fit_target_to_feature_dict_working(self, data, X_y, estimator):
        X, y = X_y
        target_to_feature_dict = data.draw(
            numeric_target_to_feature_dicts(n_targets=y.shape[1],
                                            n_features=X.shape[1]))
        multi_feature_multi_output_regressor = MultiFeatureMultiOutputRegressor(
            estimator)
        multi_feature_multi_output_regressor.fit(
            X, y, target_to_features_dict=target_to_feature_dict)

    @given(
        data=data(),
        X_y=numpy_X_y_matrices(
            X_y_shapes=shape_X_y_matrices(y_as_vector=False),
            min_value=-10000,
            max_value=10000,
        ),
    )
    def test_fit_target_to_feature_dict_consistent(self, data, X_y, estimator):
        X, y = X_y
        target_to_feature_dict = data.draw(
            numeric_target_to_feature_dicts(n_targets=y.shape[1],
                                            n_features=X.shape[1]))
        multi_feature_multi_output_regressor = MultiFeatureMultiOutputRegressor(
            estimator)
        multi_feature_multi_output_regressor.fit(
            X, y, target_to_features_dict=target_to_feature_dict)
        for i, estimator_ in enumerate(
                multi_feature_multi_output_regressor.estimators_):
            expected_n_features = len(target_to_feature_dict[i])
            assert len(estimator_.coef_) == expected_n_features

    @given(
        data=data(),
        X_y=numpy_X_y_matrices(
            X_y_shapes=shape_X_y_matrices(y_as_vector=False),
            min_value=-10000,
            max_value=10000,
        ),
    )
    def test_predict_target_to_feature_dict(self, data, X_y, estimator):
        X, y = X_y
        target_to_feature_dict = data.draw(
            numeric_target_to_feature_dicts(n_targets=y.shape[1],
                                            n_features=X.shape[1]))
        multi_feature_multi_output_regressor = MultiFeatureMultiOutputRegressor(
            estimator)
        multi_feature_multi_output_regressor.fit(
            X, y, target_to_features_dict=target_to_feature_dict)
        X_predict = data.draw(numpy_X_matrices([100, X.shape[1]]))
        multi_feature_multi_output_regressor.predict(X_predict)

    @given(
        data=data(),
        X_y=numpy_X_y_matrices(
            X_y_shapes=shape_X_y_matrices(y_as_vector=False),
            min_value=-10000,
            max_value=10000,
        ),
    )
    def test_error_predict_target_to_feature_dict_wrong_X_shape(
            self, data, X_y, estimator):
        X, y = X_y
        target_to_feature_dict = data.draw(
            numeric_target_to_feature_dicts(n_targets=y.shape[1],
                                            n_features=X.shape[1]))
        multi_feature_multi_output_regressor = MultiFeatureMultiOutputRegressor(
            estimator)
        multi_feature_multi_output_regressor.fit(
            X, y, target_to_features_dict=target_to_feature_dict)
        X_predict = data.draw(numpy_X_matrices([100, 30]))
        with pytest.raises(ValueError):
            multi_feature_multi_output_regressor.predict(X_predict)
Example #10
0
class TestAllExplainers:
    @pytest.mark.parametrize("explainer",
                             lazy_fixtures([lime_explainer, shap_explainer]))
    def test_constructor(self, explainer):
        pass

    def _check_all_parameters_fitted(self, explainer):
        assert hasattr(explainer, "model_")
        assert hasattr(explainer, "explainer_")
        assert hasattr(explainer, "feature_names_")

    @pytest.mark.parametrize("explainer",
                             lazy_fixtures([lime_explainer, shap_explainer]))
    @given(regressor=models(),
           X_y=numpy_X_y_matrices(min_value=-100, max_value=100))
    def test_fit_no_feature_names(self, explainer, regressor, X_y):
        X, y = X_y
        regressor.fit(X, y)
        explainer.fit(regressor, X)
        check_is_fitted(explainer)
        self._check_all_parameters_fitted(explainer)
        np.testing.assert_array_equal(explainer.feature_names_,
                                      [f"{i}" for i in range(X.shape[1])])

    @pytest.mark.parametrize("explainer",
                             lazy_fixtures([lime_explainer, shap_explainer]))
    @given(
        data=data(),
        regressor=models(),
        X_y=numpy_X_y_matrices(min_value=-100, max_value=100),
    )
    def test_fit_feature_names(self, data, explainer, regressor, X_y):
        X, y = X_y
        feature_names = data.draw(
            lists(elements=text(), min_size=X.shape[1], max_size=X.shape[1]))
        regressor.fit(X, y)
        explainer.fit(regressor, X, feature_names)
        check_is_fitted(explainer)
        self._check_all_parameters_fitted(explainer)

    @pytest.mark.parametrize("explainer",
                             lazy_fixtures([lime_explainer, shap_explainer]))
    @given(regressor=models(), X=numpy_X_matrices())
    def test_error_fit_regressor_not_fitted(self, explainer, regressor, X):
        with pytest.raises(NotFittedError):
            explainer.fit(regressor, X)

    def _check_predict_output(self, explainer: Explainer,
                              predictions: np.ndarray,
                              test_matrix: np.ndarray):
        assert predictions.shape[0] == test_matrix.shape[0]
        assert isinstance(explainer.explanations_, list)
        assert len(explainer.explanations_) == predictions.shape[0]
        assert all(
            isinstance(key, str) for explanation in explainer.explanations_
            for key in explanation.keys())
        assert all([
            len(explanation) == test_matrix.shape[1]
            for explanation in explainer.explanations_
        ])

    @settings(deadline=pd.Timedelta(milliseconds=5000), max_examples=7)
    @pytest.mark.parametrize("explainer",
                             lazy_fixtures([lime_explainer, shap_explainer]))
    @given(regressor=models(),
           X_y=numpy_X_y_matrices(min_value=-100, max_value=100))
    def test_predict(self, explainer, regressor, X_y):
        X, y = X_y
        regressor.fit(X, y)
        explainer.fit(regressor, X)

        test_matrix = X[:2, :]
        predictions = explainer.predict(test_matrix)
        self._check_predict_output(explainer, predictions, test_matrix)

    @pytest.mark.parametrize("explainer",
                             lazy_fixtures([lime_explainer, shap_explainer]))
    @given(X=numpy_X_matrices(min_value=-100, max_value=100))
    def test_error_predict_not_fit(self, explainer, X):
        with pytest.raises(NotFittedError):
            explainer.predict(X[:2, :])