示例#1
0
def test_error_non_binary_protected_class():
    with pytest.raises(ValueError):
        metrics.mean_difference(
            [0, 0, 0, 0, 1, 1, 1, 1],
            [1, 0, 0, 1, 2, 3, 1, 0])
    with pytest.raises(ValueError):
        metrics.normalized_mean_difference(
            [0, 0, 0, 0, 1, 1, 1, 1],
            [1, 0, 0, 1, 2, 3, 1, 0])
示例#2
0
def test_error_non_numeric_target_and_protected_class():
    # mean difference
    with pytest.raises(ValueError):
        metrics.mean_difference(
            ["a", "b", "c", "d"],
            ["a", "b", "c", "d"])
    with pytest.raises(ValueError):
        metrics.mean_difference(
            ["a", "b", "c", "d"],
            [1, 0, 0, 1])
    with pytest.raises(ValueError):
        metrics.mean_difference(
            [1, 0, 0, 1],
            ["a", "b", "c", "d"])
    # normalized mean difference
    with pytest.raises(ValueError):
        metrics.normalized_mean_difference(
            ["a", "b", "c", "d"],
            ["a", "b", "c", "d"])
    with pytest.raises(ValueError):
        metrics.normalized_mean_difference(
            ["a", "b", "c", "d"],
            [1, 0, 0, 1])
    with pytest.raises(ValueError):
        metrics.normalized_mean_difference(
            [1, 0, 0, 1],
            ["a", "b", "c", "d"])
示例#3
0
def run_experiment_iteration_themis_ml_ACF(X, X_no_sex, y, s_sex, train, test):
    metrics = []

    # define our model.
    logistic_clf = LogisticRegression(penalty='l2',
                                      C=0.001,
                                      class_weight='balanced')
    baseline_clf = logistic_clf
    rpa_clf = logistic_clf
    roc_clf = SingleROClassifier(estimator=logistic_clf)
    acf_clf = LinearACFClassifier(target_estimator=logistic_clf,
                                  binary_residual_type='absolute')

    # train baseline model
    baseline_clf.fit(X[train], y[train])
    baseline_preds = baseline_clf.predict(X[test])
    baseline_auc = roc_auc_score(y[test], baseline_preds)
    metrics.append(
        ['B',
         mean_difference(baseline_preds, s_sex[test])[0], baseline_auc])

    # train 'remove protected attributes' model. Here we have to train two
    # seperate ones for sex and foreign status.

    # model trained with no explicitly sex-related variables
    rpa_preds_no_sex = rpa_clf.fit(X_no_sex[train],
                                   y[train]).predict(X_no_sex[test])
    metrics.append([
        'RPA',
        mean_difference(rpa_preds_no_sex, s_sex[test])[0],
        roc_auc_score(y[test], rpa_preds_no_sex)
    ])

    # train reject-option classification model.
    roc_clf.fit(X[train], y[train])
    roc_preds_sex = roc_clf.predict(X[test], s_sex[test])
    metrics.append([
        'ROC',
        mean_difference(roc_preds_sex, s_sex[test])[0],
        roc_auc_score(y[test], roc_preds_sex)
    ])

    # train additive counterfactually fair model.
    acf_preds_sex = acf_clf.fit(X[train], y[train],
                                s_sex[train]).predict(X[test], s_sex[test])
    metrics.append([
        'ACF',
        mean_difference(acf_preds_sex, s_sex[test])[0],
        roc_auc_score(y[test], acf_preds_sex)
    ])

    probs = acf_clf.predict_proba(X, s_sex)
    accuracy = roc_auc_score(y[test], acf_preds_sex)
    probs_would_not_default = [prob[0] for prob in probs]

    # convert metrics list of lists into dataframe
    return {
        'prob': probs_would_not_default,
        'accuracy': accuracy,
        'acf_fit': acf_clf
    }
示例#4
0
# - "male_divorced/separated"
# - "female_divorced/separated/married"
# - "male_single"
# - "male_married/widowed"
# - "female_single
s_map = {"male": 0, "female": 1}
sex = df["personal_status_and_sex"].map(lambda x: s_map[x.split("_")[0]])

# get foreign worker status
# 1 = yes, 0 = no
foreign = df["foreign_worker"]

# The mean difference scores below suggest that men and non-foreign workers
# are more likely to have low credit risks compared to women and foreign
# workers respectively.
print("Mean difference scores:")
print("protected class = sex: %s" % mean_difference(credit_risk, sex)[0])
# 0.0748013090229
print("protected class = foreign: %s" %
      mean_difference(credit_risk, foreign)[0])
# 0.199264685246

print("\nNormalized mean difference scores:")
# normalized mean difference
print("protected class = sex: %s" %
      normalized_mean_difference(credit_risk, sex)[0])
# 0.0772946859903
print("protected class = foreign: %s" %
      normalized_mean_difference(credit_risk, foreign)[0])
# 0.63963963964
示例#5
0
def test_mean_difference_full_reverse_discrimination():
    """Binary case: advantaged group is fully discriminated against."""
    y = [0, 0, 0, 0, 1, 1, 1, 1]
    s = [0, 0, 0, 0, 1, 1, 1, 1]
    assert _get_point_est(metrics.mean_difference(y, s)) == -1
    assert _get_point_est(metrics.normalized_mean_difference(y, s)) == -1
示例#6
0
def test_mean_difference_no_discrimination():
    """Binary case: proportion in each group with +ve outcome are equal."""
    y = [0, 0, 1, 1, 0, 0, 1, 1]
    s = [0, 0, 0, 0, 1, 1, 1, 1]
    assert _get_point_est(metrics.mean_difference(y, s)) == 0
    assert _get_point_est(metrics.normalized_mean_difference(y, s)) == 0
示例#7
0
def test_mean_difference_partial_discrimination():
    """Binary case: disadvantaged group is partially discriminated against."""
    y = [1, 1, 1, 1, 0, 0, 1, 1]
    s = [0, 0, 0, 0, 1, 1, 1, 1]
    assert _get_point_est(metrics.mean_difference(y, s)) == 0.5
    assert _get_point_est(metrics.normalized_mean_difference(y, s)) == 1