Пример #1
0
 def fit(self, X: Any) -> None:
     self._explainer = AnchorTabularExplainer(
         class_names=['0', '1'],
         feature_names=list(range(X.shape[1])),
         train_data=X,
         # discretizer='quartile')
         discretizer='decile')
Пример #2
0
def main():
    m = 5
    n = 10

    n_features = 2
    random_state = 1

    factor = 10
    sampling = 0.5

    srbc = generate_syntetic_rule_based_classifier(n_features=n_features,
                                                   n_all_features=m,
                                                   random_state=random_state,
                                                   factor=factor,
                                                   sampling=sampling)

    X = srbc['X']
    feature_names = srbc['feature_names']
    class_values = srbc['class_values']
    predict_proba = srbc['predict_proba']
    predict = srbc['predict']

    X_test = np.random.uniform(np.min(X), np.max(X), size=(n, m))
    Y_test = predict_proba(X_test)

    explainer = AnchorTabularExplainer(class_names=class_values,
                                       feature_names=feature_names,
                                       categorical_names={})
    explainer.fit(X_test, Y_test, X_test, Y_test)

    for i, x in enumerate(X_test):
        print(x)
        exp, exp_dict = explainer.explain_instance_ric(x,
                                                       predict,
                                                       threshold=0.95)
        # print(exp.features())
        # print(exp_dict)
        # print(exp.exp_map['exp_dict'])
        # break
        expl_val = np.array(
            [1 if e in exp.features() else 0 for e in range(m)])
        gt_val = get_rule_explanation(x, srbc, n_features, get_values=False)
        gt_dict = get_rule_explanation_complete(x, srbc, n_features)
        rbs = rule_based_similarity(expl_val, gt_val)
        rbsc = rule_based_similarity_complete(exp_dict, gt_dict, eps=0.1)
        print(expl_val)
        print(gt_val)
        print(rbs)
        print('')
        print(exp_dict)
        print(gt_dict)
        print(rbsc)
        print('----')

        if i == 10:
            break
Пример #3
0
    def set_parameters(self, **kwargs):
        """Parameter setter for anchor_tabular.

        # Arguments
            **kwargs: Parameters setter. For more detail, please check https://lime-ml.readthedocs.io/en/latest/index.html.
        """
        class_names = kwargs.pop("class_names", self.class_names)
        feature_names = kwargs.pop("feature_names", self.feature_names)
        data = kwargs.pop("data", self.data)
        categorical_names = kwargs.pop("categorical_names",
                                       self.categorical_names)
        self.explainer = AnchorTabularExplainer(
            class_names,
            feature_names,
            data=data,
            categorical_names=categorical_names)
Пример #4
0
class Anchors2(FeatureImportance):
    """
    Feature importance method by [RIB]_.

    References
    ----------
    .. [RIB] Ribeiro, et al, "Anchors: High-precision model-agnostic explanations",
     Proceedings of the AAAI Conference on Artificial Intelligence, Volume 32, 2018.

    """

    def __init__(self, model: Any, seed: int = SEED):
        super().__init__(seed=seed)
        self._model = assign_model(model=model)
        self._explainer = None

    def fit(self, X: Any) -> None:
        self._explainer = AnchorTabularExplainer(
            class_names=['0', '1'],
            feature_names=list(range(X.shape[1])),
            train_data=X,
            # discretizer='quartile')
            discretizer='decile')

    def _compute_anchors_per_sample(self, X: np.ndarray, idx: int) -> List:
        result = self._explainer.explain_instance(
            data_row=X[idx, :], classifier_fn=self._model.predict)
        return result.exp_map['feature']

    @staticmethod
    def _calculate_importance(anchors: List, output_shape: Tuple) -> np.ndarray:
        importance = np.zeros(shape=output_shape)
        for k, anchor in enumerate(anchors):
            if isinstance(anchor, list):
                importance[k, anchor] = 1
            else:
                importance[anchor] = 1
        return importance

    def _compute_anchors(self, X: np.ndarray, num_jobs: int) -> List:
        return Parallel(n_jobs=num_jobs)(
            delayed(self._compute_anchors_per_sample)(X, sample_idx)
            for sample_idx in range(X.shape[0]))

    def explain(self, X: np.ndarray, sample_idx: int) -> np.ndarray:
        anchors = self._compute_anchors_per_sample(X=X, idx=sample_idx)
        return self._calculate_importance(anchors=anchors, output_shape=(X.shape[1],))

    def explain_batch(self, X: np.ndarray, num_jobs: int = 2) -> np.ndarray:
        np.random.seed(self._seed)
        anchors = self._compute_anchors(X=X, num_jobs=num_jobs)
        return self._calculate_importance(anchors=anchors, output_shape=X.shape)
Пример #5
0
class XDeepAnchorTabularExplainer(Explainer):
    def __init__(self,
                 class_names,
                 feature_names,
                 data,
                 categorical_names=None):
        """Init function.

        # Arguments
            class_names: List. A list of class names, ordered according to whatever the classifier is using.
            feature_names: List. list of names (strings) corresponding to the columns in the training data.
            data: Array. Full data including train data, validation_data and test data.
            categorical_names: Dict. A dict which maps from int to list of names, where categorical_names[x][y] represents the name of the yth value of column x.
        """
        Explainer.__init__(self, None, class_names)
        self.feature_names = feature_names
        self.data = data
        self.categorical_names = categorical_names
        # Initialize explainer
        self.set_parameters()

    def set_parameters(self, **kwargs):
        """Parameter setter for anchor_tabular.

        # Arguments
            **kwargs: Parameters setter. For more detail, please check https://lime-ml.readthedocs.io/en/latest/index.html.
        """
        class_names = kwargs.pop("class_names", self.class_names)
        feature_names = kwargs.pop("feature_names", self.feature_names)
        data = kwargs.pop("data", self.data)
        categorical_names = kwargs.pop("categorical_names",
                                       self.categorical_names)
        self.explainer = AnchorTabularExplainer(
            class_names,
            feature_names,
            data=data,
            categorical_names=categorical_names)

    def get_anchor_encoder(self,
                           train_data,
                           train_labels,
                           validation_data,
                           validation_labels,
                           discretizer='quartile'):
        """Get encoder for tabular data.

        If you want to use 'anchor' to explain tabular classifier. You need to get this encoder to encode your data, and train another model.

        # Arguments
            train_data: Array. Train data.
            train_labels: Array. Train labels.
            validation_data: Array. Validation set.
            validation_labels: Array. Validation labels.
            discretizer: Str. Discretizer for data. Please choose between 'quartile' and 'decile'.
            
        # Return
            A encoder object which has function 'transform'.
        """
        self.explainer.fit(train_data,
                           train_labels,
                           validation_data,
                           validation_labels,
                           discretizer=discretizer)
        return self.explainer.encoder

    def set_anchor_predict_proba(self, predict_proba):
        """Predict function setter.

        # Arguments
            predict_proba: Function. A classifier prediction probability function.
        """
        self.predict_proba = predict_proba

    def explain(self, instance, top_labels=None, labels=(1, ), **kwargs):
        """Generate explanation for a prediction using certain method.
        Anchor does not use top_labels and labels.

        # Arguments
            instance: Array. One row of tabular data to be explained.
            **kwarg: Parameters setter. For more detail, please check https://lime-ml.readthedocs.io/en/latest/index.html.
        """
        if self.predict_proba is None:
            raise XDeepError(
                "Please call set_anchor_predict_proba to pass in your new predict function."
            )

        def predict_label(x):
            return np.argmax(self.predict_proba(x), axis=1)

        self.instance = instance
        self.labels = self.predict_proba(
            self.explainer.encoder.transform([instance])).argsort()[0][-1:]
        self.explanation = self.explainer.explain_instance(
            instance, predict_label, **kwargs)

    def show_explanation(self, show_in_note_book=True, verbose=True):
        """Visualization of explanation of anchor_tabular.

        # Arguments
            show_in_note_book: Boolean. Whether show in jupyter notebook.
            verbose: Boolean. Whether print out examples and counter examples.
        """
        Explainer.show_explanation(self)
        exp = self.explanation

        print()
        print("Anchor Explanation")
        print()
        if verbose:
            print()
            print(
                'Examples where anchor applies and model predicts same to instance:'
            )
            print()
            print(exp.examples(only_same_prediction=True))
            print()
            print(
                'Examples where anchor applies and model predicts different with instance:'
            )
            print()
            print(exp.examples(only_different_prediction=True))

        label = self.labels[0]
        print('Prediction: {}'.format(label))
        print('Anchor: %s' % (' AND '.join(exp.names())))
        print('Precision: %.2f' % exp.precision())
        print('Coverage: %.2f' % exp.coverage())
        if show_in_note_book:
            exp.show_in_notebook()
Пример #6
0
    shap_plot = shap.force_plot(explainer.expected_value[i],
                                shap_values[i],
                                user_encoded,
                                feature_names=feature_names,
                                out_names=class_names[i])
    shap_plot_reprs.append(shap_plot._repr_html_())

shap_html_repr = "".join(shap_plot_reprs)

bundle_path = Path(shap.__file__).parent / 'plots' / 'resources' / "bundle.js"
with bundle_path.open('r') as f:
    bundle_data = f.read()
    shape_js = f"<script charset='utf-8'>{bundle_data}</script>"

componenets.html(f"{shape_js}{shap_html_repr}", height=420)

st.header("Anchors")

X_encoded = clf[:-1].transform(X)
anchor_explainer = AnchorTabularExplainer(class_names,
                                          feature_names,
                                          X_encoded,
                                          categorical_names={
                                              0: metadata['island_categories'],
                                              1: metadata['gender_categories']
                                          })

exp = anchor_explainer.explain_instance(user_encoded[0, :], clf[-1].predict)
exp_html = exp.as_html()
componenets.html(exp_html, height=700)