コード例 #1
0
    def create_local(self,
                     local_importance_values,
                     evaluation_examples=None,
                     expected_values=None):
        """Create a local explanation from the list of local feature importance values.

        :param local_importance_values: The feature importance values.
        :type local_importance_values: numpy.array or scipy.sparse.csr_matrix or list[scipy.sparse.csr_matrix]
        :param evaluation_examples: A matrix of feature vector examples (# examples x # features) on which
            to explain the model's output.
        :type evaluation_examples: numpy.array or pandas.DataFrame or scipy.sparse.csr_matrix
        :param expected_values: The expected values of the model.
        :type expected_values: numpy.array
        """
        local_importance_values = np.array(local_importance_values)
        # handle the case that the local importance values have a 2d shape for classification scenario
        # and only specify the positive class
        if len(local_importance_values.shape) == 2 and self.classification:
            local_importance_values = np.array(
                [-local_importance_values, local_importance_values])

        kwargs = {ExplainParams.METHOD: self.method}
        kwargs[ExplainParams.FEATURES] = self.features
        if self.classification:
            kwargs[ExplainParams.MODEL_TASK] = ExplainType.CLASSIFICATION
        else:
            kwargs[ExplainParams.MODEL_TASK] = ExplainType.REGRESSION
        kwargs[ExplainParams.LOCAL_IMPORTANCE_VALUES] = local_importance_values
        kwargs[ExplainParams.EXPECTED_VALUES] = expected_values
        kwargs[ExplainParams.CLASSIFICATION] = self.classification
        if evaluation_examples is not None:
            kwargs[ExplainParams.EVAL_DATA] = evaluation_examples
        return _create_local_explanation(**kwargs)
コード例 #2
0
    def test_get_raw_explanation_no_datasets_mixin(self, boston,
                                                   mimic_explainer):
        model = create_sklearn_random_forest_regressor(
            boston[DatasetConstants.X_TRAIN], boston[DatasetConstants.Y_TRAIN])

        explainer = mimic_explainer(model, boston[DatasetConstants.X_TRAIN],
                                    LGBMExplainableModel)
        global_explanation = explainer.explain_global(
            boston[DatasetConstants.X_TEST])
        assert global_explanation.method == LIGHTGBM_METHOD

        kwargs = {ExplainParams.METHOD: global_explanation.method}
        kwargs[ExplainParams.FEATURES] = global_explanation.features
        kwargs[ExplainParams.MODEL_TASK] = ExplainType.REGRESSION
        kwargs[
            ExplainParams.
            LOCAL_IMPORTANCE_VALUES] = global_explanation._local_importance_values
        kwargs[ExplainParams.EXPECTED_VALUES] = 0
        kwargs[ExplainParams.CLASSIFICATION] = False
        kwargs[ExplainParams.IS_ENG] = True
        synthetic_explanation = _create_local_explanation(**kwargs)

        num_engineered_feats = boston[DatasetConstants.X_TRAIN].shape[1]
        feature_map = np.eye(5, num_engineered_feats)
        feature_names = [str(i) for i in range(feature_map.shape[0])]
        raw_names = feature_names[:feature_map.shape[0]]
        assert not _DatasetsMixin._does_quack(synthetic_explanation)
        global_raw_explanation = synthetic_explanation.get_raw_explanation(
            [feature_map], raw_feature_names=raw_names)
        self.validate_local_explanation_regression(synthetic_explanation,
                                                   global_raw_explanation,
                                                   feature_map,
                                                   has_eng_eval_data=False,
                                                   has_raw_eval_data=False,
                                                   has_dataset_data=False)
コード例 #3
0
    def explain_local(self, evaluation_examples):
        """Explain the function locally by using LIME.

        :param evaluation_examples: A matrix of feature vector examples (# examples x # features) on which
            to explain the model's output.
        :type evaluation_examples: DatasetWrapper
        :param features: A list of feature names.
        :type features: list[str]
        :param classes: Class names as a list of strings. The order of the class names should match
            that of the model output.  Only required if explaining classifier.
        :type classes: list[str]
        :return: A model explanation object containing the local explanation.
        :rtype: LocalExplanation
        """
        if self._datamapper is not None:
            evaluation_examples = transform_with_datamapper(
                evaluation_examples, self._datamapper)

        if self._column_indexer:
            evaluation_examples.apply_indexer(self._column_indexer)

        # Compute subset info prior
        if self.explain_subset:
            evaluation_examples.take_subset(self.explain_subset)

        # sample the evaluation examples
        # note: the sampled data is also used by KNN
        if self.sampling_policy is not None and self.sampling_policy.allow_eval_sampling:
            sampling_method = self.sampling_policy.sampling_method
            max_dim_clustering = self.sampling_policy.max_dim_clustering
            evaluation_examples.sample(max_dim_clustering,
                                       sampling_method=sampling_method)
        features = self.features
        if self.explain_subset:
            features = [features[i] for i in self.explain_subset]
        kwargs = {ExplainParams.METHOD: ExplainType.LIME}
        kwargs[ExplainParams.FEATURES] = features
        kwargs[ExplainParams.NUM_FEATURES] = evaluation_examples.num_features
        original_evaluation = evaluation_examples.original_dataset
        evaluation_examples = evaluation_examples.dataset
        if len(evaluation_examples.shape) == 1:
            evaluation_examples = evaluation_examples.reshape(1, -1)

        self._logger.debug('Running LIMEExplainer')
        if self.classification:
            kwargs[ExplanationParams.CLASSES] = self.classes
            kwargs[ExplainType.MODEL_TASK] = ExplainType.CLASSIFICATION
            num_classes = len(self.classes)
            labels = list(range(num_classes))
        else:
            kwargs[ExplainType.MODEL_TASK] = ExplainType.REGRESSION
            num_classes = 1
            labels = None
        lime_explanations = []

        tqdm = get_tqdm(self._logger, self.show_progress)

        if self.explain_subset:
            self.original_data_ref[0] = original_evaluation
            self.current_index_list.append(0)
            for ex_idx, example in tqdm(enumerate(evaluation_examples)):
                self.current_index_list[0] = ex_idx
                lime_explanations.append(
                    self.explainer.explain_instance(example,
                                                    self.explainer.function,
                                                    labels=labels))
            self.current_index_list = [0]
        else:
            for ex_idx, example in tqdm(enumerate(evaluation_examples)):
                lime_explanations.append(
                    self.explainer.explain_instance(example,
                                                    self.explainer.function,
                                                    labels=labels))
        if self.classification:
            lime_values = [None] * num_classes
            for lime_explanation in lime_explanations:
                for label in labels:
                    map_values = dict(lime_explanation.as_list(label=label))
                    if lime_values[label - 1] is None:
                        lime_values[label - 1] = [[
                            map_values.get(feature, 0.0)
                            for feature in self._lime_feature_names
                        ]]
                    else:
                        lime_values[label - 1].append([
                            map_values.get(feature, 0.0)
                            for feature in self._lime_feature_names
                        ])
        else:
            lime_values = None
            for lime_explanation in lime_explanations:
                map_values = dict(lime_explanation.as_list())
                if lime_values is None:
                    lime_values = [[
                        map_values.get(feature, 0.0)
                        for feature in self._lime_feature_names
                    ]]
                else:
                    lime_values.append([
                        map_values.get(feature, 0.0)
                        for feature in self._lime_feature_names
                    ])
        expected_values = None
        if self.model is not None:
            kwargs[ExplainParams.MODEL_TYPE] = str(type(self.model))
        else:
            kwargs[ExplainParams.MODEL_TYPE] = ExplainType.FUNCTION

        kwargs[ExplainParams.CLASSIFICATION] = self.classification
        kwargs[ExplainParams.LOCAL_IMPORTANCE_VALUES] = np.array(lime_values)
        kwargs[ExplainParams.EXPECTED_VALUES] = np.array(expected_values)
        kwargs[ExplainParams.EVAL_DATA] = original_evaluation

        explanation = _create_local_explanation(**kwargs)

        # if transformations have been passed, then return raw features explanation
        raw_kwargs = _get_raw_explainer_create_explanation_kwargs(
            kwargs=kwargs)
        return explanation if self._datamapper is None else _create_raw_feats_local_explanation(
            explanation,
            feature_maps=[self._datamapper.feature_map],
            features=self.features,
            **raw_kwargs)