Exemplo n.º 1
0
def describe_cf_instance(X,
                         explanation,
                         class_names,
                         cat_vars_ohe=None,
                         category_map=None,
                         feature_names=None,
                         eps=1e-2):
    print("Instance Outcomes and Probabilities")
    print("-" * 48)
    max_len = len(max(feature_names, key=len))
    print('{}:  {}\r\n{}   {}'.format('original'.rjust(max_len),
                                      class_names[explanation.orig_class],
                                      " " * max_len,
                                      explanation.orig_proba[0]))
    if explanation.cf != None:
        print('{}:  {}\r\n{}   {}'.format('counterfactual'.rjust(max_len),
                                          class_names[explanation.cf['class']],
                                          " " * max_len,
                                          explanation.cf['proba'][0]))
        print("\r\nCategorical Feature Counterfactual Perturbations")
        print("-" * 48)
        X_orig_ord = ohe_to_ord(X, cat_vars_ohe)[0]
        try:
            X_cf_ord = ohe_to_ord(explanation.cf['X'], cat_vars_ohe)[0]
        except:
            X_cf_ord = ohe_to_ord(explanation.cf['X'].transpose(),
                                  cat_vars_ohe)[0].transpose()
        delta_cat = {}
        for _, (i, v) in enumerate(category_map.items()):
            cat_orig = v[int(X_orig_ord[0, i])]
            cat_cf = v[int(X_cf_ord[0, i])]
            if cat_orig != cat_cf:
                delta_cat[feature_names[i]] = [cat_orig, cat_cf]
        if delta_cat:
            for k, v in delta_cat.items():
                print("\t{}:  {}  -->  {}".format(k.rjust(max_len), v[0],
                                                  v[1]))
        print("\r\nNumerical Feature Counterfactual Perturbations")
        print("-" * 48)
        num_idxs = [i for i in list(range(0,len(feature_names)))\
                    if i not in category_map.keys()]
        delta_num = X_cf_ord[0, num_idxs] - X_orig_ord[0, num_idxs]
        for i in range(delta_num.shape[0]):
            if np.abs(delta_num[i]) > eps:
                print("\t{}:  {:.2f}  -->  {:.2f}".format(
                    feature_names[i].rjust(max_len), X_orig_ord[0, i],
                    X_cf_ord[0, i]))
    else:
        print("\tNO COUNTERFACTUALS")
Exemplo n.º 2
0
def test_tf_keras_adult_explainer(disable_tf2, adult_data,
                                  tf_keras_adult_explainer, use_kdtree, k,
                                  d_type):
    model, cf = tf_keras_adult_explainer
    X_train = adult_data['preprocessor'].transform(
        adult_data['X_train']).toarray()

    # instance to be explained
    x = X_train[0].reshape(1, -1)
    pred_class = np.argmax(model.predict(x))
    not_pred_class = np.argmin(model.predict(x))

    # test fit
    cf.fit(X_train, d_type=d_type)

    # checked ragged tensor shape
    n_cat = len(list(cf.cat_vars_ord.keys()))
    max_key = max(cf.cat_vars_ord, key=cf.cat_vars_ord.get)
    max_cat = cf.cat_vars_ord[max_key]
    assert cf.d_abs_ragged.shape == (n_cat, max_cat)

    if use_kdtree:  # k-d trees
        assert len(cf.kdtrees) == cf.classes  # each class has a k-d tree
        n_by_class = 0
        for c in range(cf.classes):
            n_by_class += cf.X_by_class[c].shape[0]
        assert n_by_class == X_train.shape[
            0]  # all training instances are stored in the trees

    # test explanation
    explanation = cf.explain(x, k=k)
    if use_kdtree:
        assert cf.id_proto != pred_class
    assert np.argmax(model.predict(
        explanation.cf['X'])) == explanation.cf['class']
    num_shape = (1, 12)
    assert explanation.cf['grads_num'].shape == explanation.cf[
        'grads_graph'].shape == num_shape
    assert explanation.meta.keys() == DEFAULT_META_CFP.keys()
    assert explanation.data.keys() == DEFAULT_DATA_CFP.keys()

    # test gradient shapes
    y = np.zeros((1, cf.classes))
    np.put(y, pred_class, 1)
    cf.predict = cf.predict.predict  # make model black box
    # convert instance to numerical space
    x_ord = ohe_to_ord(x, cf.cat_vars)[0]
    x_num = ord_to_num(x_ord, cf.d_abs)
    # check gradients
    grads = cf.get_gradients(x_num, y, num_shape[1:], cf.cat_vars_ord)
    assert grads.shape == num_shape
Exemplo n.º 3
0
def test_mapping_fn():
    # ohe_to_ord_shape
    assert mp.ohe_to_ord_shape(shape_ohe, cat_vars_ohe,
                               is_ohe=True) == shape_ord

    # ohe_to_ord
    X_ohe_to_ord, cat_vars_ohe_to_ord = mp.ohe_to_ord(X_ohe, cat_vars_ohe)
    assert (X_ohe_to_ord
            == X_ord).all() and cat_vars_ohe_to_ord == cat_vars_ord

    # ord_to_ohe
    X_ord_to_ohe, cat_vars_ord_to_ohe = mp.ord_to_ohe(X_ord, cat_vars_ord)
    assert (X_ord_to_ohe
            == X_ohe).all() and cat_vars_ohe == cat_vars_ord_to_ohe

    # ord_to_num
    X_ord_to_num = mp.ord_to_num(X_ord, dist)
    assert (X_num == X_ord_to_num).all()

    # num_to_ord
    X_num_to_ord = mp.num_to_ord(X_num, dist)
    assert (X_ord == X_num_to_ord).all()