def compute_metrics(dataset_true, dataset_pred, unprivileged_groups, privileged_groups, disp=True): """ Compute the key metrics """ classified_metric_pred = ClassificationMetric( dataset_true, dataset_pred, unprivileged_groups=unprivileged_groups, privileged_groups=privileged_groups) metrics = OrderedDict() metrics["Accuracy (Overall)"] = classified_metric_pred.accuracy() metrics["Accuracy (Privileged)"] = classified_metric_pred.accuracy(True) metrics["Accuracy (Unprivileged)"] = classified_metric_pred.accuracy(False) metrics["Balanced accuracy"] = 0.5 * ( classified_metric_pred.true_positive_rate() + classified_metric_pred.true_negative_rate()) metrics[ "Statistical parity difference"] = classified_metric_pred.statistical_parity_difference( ) metrics["Disparate impact"] = classified_metric_pred.disparate_impact() metrics[ "Average odds difference"] = classified_metric_pred.average_odds_difference( ) metrics[ "Equal opportunity difference"] = classified_metric_pred.equal_opportunity_difference( ) metrics["Theil index"] = classified_metric_pred.theil_index() if disp: for k in metrics: print("%s = %.4f" % (k, metrics[k])) return metrics
def get_cm_metrics(): df_pred = X.copy() df_pred[df.columns[-1]] = np.expand_dims(ypred_class, axis=1) dataset_pred = BinaryLabelDataset(df=df_pred, label_names=[ 'action_taken_name'], protected_attribute_names=['applicant_sex_name_Female']) metric_CM = ClassificationMetric( dataset, dataset_pred, privileged_groups=privileged_group, unprivileged_groups=unprivileged_group) return { "Equal Opportunity Difference": metric_CM.equal_opportunity_difference(), 'Average Odds Difference': metric_CM.average_odds_difference(), "Accuracy Male": metric_CM.accuracy(privileged=True), "Accuracy Female": metric_CM.accuracy(privileged=False) }
def get_metric_reports(true_dataset,classfied_dataset,privileged_groups,unprivileged_groups): mirror_dataset=classfied_dataset.copy(deepcopy=True) mirror_dataset.labels=copy.deepcopy(true_dataset.labels) metric=ClassificationMetric( dataset=mirror_dataset, classified_dataset=classfied_dataset, unprivileged_groups=unprivileged_groups, privileged_groups=privileged_groups) #Measuring unfairness end report=OrderedDict() report['TPR']=metric.true_positive_rate() report['TNR']=metric.true_negative_rate() report['FPR']=metric.false_positive_rate() report['FNR']=metric.false_negative_rate() report['Balanced_Acc']=0.5*(report['TPR']+report['TNR']) report['Acc']=metric.accuracy() report["Statistical parity difference"]=metric.statistical_parity_difference() report["Disparate impact"]=metric.disparate_impact() report["Equal opportunity difference"]=metric.equal_opportunity_difference() report["Average odds difference"]=metric.average_odds_difference() report["Theil index"]=metric.theil_index() report["United Fairness"]=metric.generalized_entropy_index() return report
def get_classifier_metrics(test_list, prediction_list): privileged_groups = [{'sex': 1}] unprivileged_groups = [{'sex': 0}] acc_list = [] bal_acc_list = [] avg_odds_list = [] recall_diff_list = [] precision_diff_list = [] for test_, pred_ in zip(test_list, prediction_list): model_metric = ClassificationMetric( test_, pred_, unprivileged_groups=unprivileged_groups, privileged_groups=privileged_groups) acc_list.append(model_metric.accuracy().round(3)) bal_acc_list.append(((model_metric.true_positive_rate() + model_metric.true_negative_rate()) / 2).round(3)) avg_odds_list.append(model_metric.average_odds_difference().round(3)) recall_diff_list.append( model_metric.equal_opportunity_difference().round(3)) precision_diff_list.append( (model_metric.precision(privileged=False) - model_metric.precision(privileged=True)).round(3)) return acc_list, bal_acc_list, avg_odds_list, recall_diff_list, precision_diff_list
def fairness_IBM(y_pred, Ztr, ytr, verbose=0): from aif360.datasets import BinaryLabelDataset from aif360.metrics import ClassificationMetric assert np.array_equal(np.unique(Ztr), np.array([0, 1])), "Z must contain either 0 or 1" # if len(ytr.shape) == 1: # ytr = np.expand_dims(ytr, -1) Ztr = np.squeeze(Ztr) if verbose: print(ytr.shape) print(Ztr.shape) unprivileged_groups = [{"zs": [0]}] privileged_groups = [{"zs": [1]}] metric_arrs = defaultdict(list) dict_ = {"y_true": ytr, "zs": Ztr} df = pd.DataFrame(dict_) dataset = BinaryLabelDataset(df=df, label_names=["y_true"], protected_attribute_names=["zs"], unprivileged_protected_attributes=[[0]], privileged_protected_attributes=[[1]]) dataset_pred = dataset.copy() dataset_pred.labels = y_pred metric = ClassificationMetric(dataset, dataset_pred, unprivileged_groups=unprivileged_groups, privileged_groups=privileged_groups) # metric_arrs['bal_acc'].append((metric.true_positive_rate() # + metric.true_negative_rate()) / 2) metric_arrs["EA"].append( metric.accuracy(privileged=False) - metric.accuracy(privileged=True)) # ASSUMING ALL OTHER METRICS RETURN U - P metric_arrs['EO'].append(metric.average_odds_difference()) # The ideal value of this metric is 1.0 # A value < 1 implies higher benefit for the privileged group # and a value >1 implies a higher metric_arrs['DI'].append(metric.disparate_impact() - 1) metric_arrs['DP'].append(metric.statistical_parity_difference()) metric_arrs['EQ'].append(metric.equal_opportunity_difference()) metric_arrs['TH'].append(metric.between_group_theil_index() * 10) results = pd.DataFrame(metric_arrs) return results
def fair_metrics(dataset, pred, pred_is_dataset=False): if pred_is_dataset: dataset_pred = pred else: dataset_pred = dataset.copy() dataset_pred.labels = pred cols = [ 'statistical_parity_difference', 'equal_opportunity_difference', 'average_abs_odds_difference', 'disparate_impact', 'theil_index' ] obj_fairness = [[0, 0, 0, 1, 0]] fair_metrics = pd.DataFrame(data=obj_fairness, index=['objective'], columns=cols) for attr in dataset_pred.protected_attribute_names: idx = dataset_pred.protected_attribute_names.index(attr) privileged_groups = [{ attr: dataset_pred.privileged_protected_attributes[idx][0] }] unprivileged_groups = [{ attr: dataset_pred.unprivileged_protected_attributes[idx][0] }] classified_metric = ClassificationMetric( dataset, dataset_pred, unprivileged_groups=unprivileged_groups, privileged_groups=privileged_groups) metric_pred = BinaryLabelDatasetMetric( dataset_pred, unprivileged_groups=unprivileged_groups, privileged_groups=privileged_groups) acc = classified_metric.accuracy() row = pd.DataFrame([[ metric_pred.mean_difference(), classified_metric.equal_opportunity_difference(), classified_metric.average_abs_odds_difference(), metric_pred.disparate_impact(), classified_metric.theil_index() ]], columns=cols, index=[attr]) fair_metrics = fair_metrics.append(row) fair_metrics = fair_metrics.replace([-np.inf, np.inf], 2) return fair_metrics
def fit_classifier(classifier, weights, lambda_values, X_train, y_train, X_test, y_test, test_pred): ''' Function to fit classifiers for range of Lambda values Args: classifier: SVM or Logistic regression weights: weights for each sample lambda_values: range of lambda values to assess X_train: training data y_train: training lables X_test: test data y_test: test labels test_pred: prepared format to store predictions Returns: accuracy_list: test accuracy for each model equal_opp_list: Equal Opportunity difference for each model stat_parity_list: Statistical Parity difference for each model ''' accuracy_list = [] equal_opp_list = [] stat_parity_list = [] for l in lambda_values: print("-------- \n", 'Lambda: ', "{0:.2f}".format(l)) if classifier == "Logistic Regression": learner = LogisticRegression(solver='liblinear', random_state=1, penalty='l2', C=1/l) else: learner = svm.SVC(C=1/l) learner.fit(X_train,y_train, sample_weight=weights) test_pred.labels = learner.predict(X_test) metric = ClassificationMetric(test, test_pred, unprivileged_groups=unprivileged_groups, privileged_groups=privileged_groups) print("Equal opportunity:", "{0:.3f}".format(metric.equal_opportunity_difference())) print("Statistical parity:", "{0:.3f}".format(metric.statistical_parity_difference())) print("Accuracy:", "{0:.3f}".format(metric.accuracy())) accuracy_list.append(metric.accuracy()) equal_opp_list.append(metric.equal_opportunity_difference()) stat_parity_list.append(metric.statistical_parity_difference()) return accuracy_list, equal_opp_list, stat_parity_list
def get_metrics(dataset_orig, preds): ''' Description: This code computes accuracy, balanced accuracy, max gap and gap rms for race and gender Input: dataset_orig: a BinaryLabelDataset (from the aif360 module) preds: predictions ''' dataset_learned_model = dataset_orig.copy() dataset_learned_model.labels = preds # wrt gender privileged_groups = [{'sex_ Male': 1}] unprivileged_groups = [{'sex_ Male': 0}] classified_metric = ClassificationMetric( dataset_orig, dataset_learned_model, unprivileged_groups=unprivileged_groups, privileged_groups=privileged_groups) bal_acc = compute_balanced_accuracy(classified_metric) gender_gap_rms, gender_max_gap = compute_gap_RMS_and_gap_max( classified_metric) print("Test set: gender gap rms = %f" % gender_gap_rms) print("Test set: gender max gap rms = %f" % gender_max_gap) print("Test set: Balanced TPR = %f" % bal_acc) # wrt race privileged_groups = [{'race_ White': 1}] unprivileged_groups = [{'race_ White': 0}] classified_metric = ClassificationMetric( dataset_orig, dataset_learned_model, unprivileged_groups=unprivileged_groups, privileged_groups=privileged_groups) race_gap_rms, race_max_gap = compute_gap_RMS_and_gap_max(classified_metric) print("Test set: race gap rms = %f" % race_gap_rms) print("Test set: race max gap rms = %f" % race_max_gap) return classified_metric.accuracy( ), bal_acc, race_gap_rms, race_max_gap, gender_gap_rms, gender_max_gap
def test_eqodds(): eqo = EqOddsPostprocessing(unprivileged_groups=[{ 'sex': 0 }], privileged_groups=[{ 'sex': 1 }], seed=1234567) pred_eqo = eqo.fit(val, val_pred).predict(pred) cm_eqo = ClassificationMetric(test, pred_eqo, unprivileged_groups=[{ 'sex': 0 }], privileged_groups=[{ 'sex': 1 }]) # accuracy drop should be less than 10% (arbitrary) assert (cm_lr.accuracy() - cm_eqo.accuracy()) / cm_lr.accuracy() < 0.1 # approximately equal odds assert cm_eqo.average_abs_odds_difference() < 0.1
def test_caleq(): ceo = CalibratedEqOddsPostprocessing(cost_constraint='fnr', unprivileged_groups=[{ 'sex': 0 }], privileged_groups=[{ 'sex': 1 }], seed=1234567) pred_ceo = ceo.fit(val, val_pred).predict(pred) cm_ceo = ClassificationMetric(test, pred_ceo, unprivileged_groups=[{ 'sex': 0 }], privileged_groups=[{ 'sex': 1 }]) # accuracy drop should be less than 10% (arbitrary) assert (cm_lr.accuracy() - cm_ceo.accuracy()) / cm_lr.accuracy() < 0.1 # approximate GFNR parity assert abs(cm_ceo.difference(cm_ceo.generalized_false_negative_rate)) < 0.1
def get_fair_metrics(dataset, pred, pred_is_dataset=False): """ Measure fairness metrics. Parameters: dataset (pandas dataframe): Dataset pred (array): Model predictions pred_is_dataset, optional (bool): True if prediction is already part of the dataset, column name 'labels'. Returns: fair_metrics: Fairness metrics. """ if pred_is_dataset: dataset_pred = pred else: dataset_pred = dataset.copy() dataset_pred.labels = pred cols = [ 'statistical_parity_difference', 'equal_opportunity_difference', 'average_abs_odds_difference', 'disparate_impact', 'theil_index' ] obj_fairness = [[0, 0, 0, 1, 0]] fair_metrics = pd.DataFrame(data=obj_fairness, index=['objective'], columns=cols) for attr in dataset_pred.protected_attribute_names: idx = dataset_pred.protected_attribute_names.index(attr) privileged_groups = [{ attr: dataset_pred.privileged_protected_attributes[idx][0] }] unprivileged_groups = [{ attr: dataset_pred.unprivileged_protected_attributes[idx][0] }] classified_metric = ClassificationMetric( dataset, dataset_pred, unprivileged_groups=unprivileged_groups, privileged_groups=privileged_groups) metric_pred = BinaryLabelDatasetMetric( dataset_pred, unprivileged_groups=unprivileged_groups, privileged_groups=privileged_groups) acc = classified_metric.accuracy() row = pd.DataFrame([[ metric_pred.mean_difference(), classified_metric.equal_opportunity_difference(), classified_metric.average_abs_odds_difference(), metric_pred.disparate_impact(), classified_metric.theil_index() ]], columns=cols, index=[attr]) fair_metrics = fair_metrics.append(row) fair_metrics = fair_metrics.replace([-np.inf, np.inf], 2) return fair_metrics
dataset_transf_test_pred = cpp.predict(dataset_orig_test_pred) cm_transf_valid = ClassificationMetric(dataset_orig_valid, dataset_transf_valid_pred, unprivileged_groups=unprivileged_groups, privileged_groups=privileged_groups) cm_transf_test = ClassificationMetric(dataset_orig_test, dataset_transf_test_pred, unprivileged_groups=unprivileged_groups, privileged_groups=privileged_groups) #cm_transf_test.difference for idx,PR in enumerate(privileged_options): gfnr[idx] += cm_transf_test.false_negative_rate(privileged=PR) gfpr[idx] += cm_transf_test.false_positive_rate(privileged=PR) result = cm_transf_test.accuracy(privileged=PR) acc[idx] += float(result) pbar.update(1) fns.append(gfnr/N_reps) fps.append(gfpr/N_reps) accs.append(acc/N_reps) negs.append(neg) collapse = lambda param, idx : [v[idx] for v in param] getnames = {None:"full data", True:"privileged", False:"unprivileged"} for idx,PR in enumerate(privileged_options):
print( "#### Plain model - without debiasing - classification metrics on test set" ) # print("Test set: Classification accuracy = %f" % classified_metric_nodebiasing_test.accuracy()) # print("Test set: Balanced classification accuracy = %f" % bal_acc_nodebiasing_test) # print("Test set: Statistical parity difference = %f" % classified_metric_nodebiasing_test.statistical_parity_difference()) # print("Test set: Disparate impact = %f" % classified_metric_nodebiasing_test.disparate_impact()) # print("Test set: Equal opportunity difference = %f" % classified_metric_nodebiasing_test.equal_opportunity_difference()) # print("Test set: Average odds difference = %f" % classified_metric_nodebiasing_test.average_odds_difference()) # print("Test set: Theil index = %f" % classified_metric_nodebiasing_test.theil_index()) # print("Test set: False negative rate difference = %f" % classified_metric_nodebiasing_test.false_negative_rate_difference()) metrics = { "Classification accuracy": classified_metric_nodebiasing_test.accuracy(), "Balanced classification accuracy": bal_acc_nodebiasing_test, "Statistical parity difference": classified_metric_nodebiasing_test.statistical_parity_difference(), "Disparate impact": classified_metric_nodebiasing_test.disparate_impact(), "Equal opportunity difference": classified_metric_nodebiasing_test.equal_opportunity_difference(), "Average odds difference": classified_metric_nodebiasing_test.average_odds_difference(), "Theil index": classified_metric_nodebiasing_test.theil_index(), "False negative rate difference": classified_metric_nodebiasing_test.false_negative_rate_difference() }
def run_trial(): # stores each run (4 algos without reweighing, 4 algos with reweighing) as a sublist # number of sublists = number of runs # each sublist has four elements # we ONLY predict on the testing data ########## WITHOUT REWEIGHING ############# stat_par = [] disp_imp = [] eq_opp_diff = [] avg_odds_diff = [] theil = [] acc = [] ########## WITH REWEIGHING ############# stat_par_reweigh = [] disp_imp_reweigh = [] eq_opp_diff_reweigh = [] avg_odds_diff_reweigh = [] theil_reweigh = [] acc_reweigh = [] ########################################### for i in range(10): ########################################### privileged_groups = [{'sex': 1}] unprivileged_groups = [{'sex': 0}] dataset_orig = load_preproc_data_adult() # train1, test1 are the original dataset train1, test1 = dataset_orig.split([0.7], shuffle=True) RW = Reweighing(unprivileged_groups=unprivileged_groups, privileged_groups=privileged_groups) RW.fit(train1) # dataset_transf_train, test1 are for the reweighed dataset dataset_transf_train = RW.transform(train1) ########################################### # change weights to whole numbers for i in range(dataset_transf_train.instance_weights.size): dataset_transf_train.instance_weights[i] = (round( dataset_transf_train.instance_weights[i] / 0.1) * 0.1) * 10 weights = copy.deepcopy(dataset_transf_train.instance_weights) # change dataset_transf_train.features and dataset_transf_train.labels and dataset_transf_train.protected_attributes according to the weights of each instance sum_weights = 0 for i in range(dataset_transf_train.features.shape[0]): row = copy.deepcopy(dataset_transf_train.features[i]) row_label = copy.deepcopy(dataset_transf_train.labels[i]) row_protected_attributes = copy.deepcopy( dataset_transf_train.protected_attributes[i]) row_protected_attributes.resize(1, 2) row.resize(1, 18) row_label.resize(1, 1) weight = int(weights[i]) for j in range(weight - 1): dataset_transf_train.features = np.concatenate( (dataset_transf_train.features, row)) dataset_transf_train.labels = np.concatenate( (dataset_transf_train.labels, row_label)) dataset_transf_train.protected_attributes = np.concatenate( (dataset_transf_train.protected_attributes, row_protected_attributes)) # change the dataset_transf_train to a numpy array of ones to match number of rows in features dataset_transf_train.instance_weights = np.ones( dataset_transf_train.features.shape[0]) ################## without reweighing ########################## temp_stat_par = [] temp_disp_imp = [] temp_eq_opp_diff = [] temp_avg_odds_diff = [] temp_theil = [] temp_acc = [] ##################### adversarial debiasing ##################### sess = tf.Session() debiased_model = AdversarialDebiasing( privileged_groups=privileged_groups, unprivileged_groups=unprivileged_groups, scope_name='debiased_classifier', debias=True, sess=sess) debiased_model.fit(train1) dataset_debiasing_test = debiased_model.predict(test1) sess.close() tf.reset_default_graph() ##################### metrics ##################### metric_test = BinaryLabelDatasetMetric( dataset_debiasing_test, unprivileged_groups=unprivileged_groups, privileged_groups=privileged_groups) acc_test = ClassificationMetric( test1, dataset_debiasing_test, unprivileged_groups=unprivileged_groups, privileged_groups=privileged_groups) temp_stat_par.append(metric_test.mean_difference()) temp_disp_imp.append(metric_test.disparate_impact()) temp_eq_opp_diff.append(metric_test.equal_opportunity_difference()) temp_avg_odds_diff.append(metric_test.average_odds_difference()) temp_theil.append(metric_test.theil_index()) temp_acc.append(acc_test.accuracy()) ##################### prejudice remover ##################### prejudice_model = PrejudiceRemover(eta=100, sensitive_attr='sex') prejudice_model.fit(train1) dataset_prejudice_test = prejudice_model.predict(test1) ##################### metrics ##################### metric_test = BinaryLabelDatasetMetric( dataset_prejudice_test, unprivileged_groups=unprivileged_groups, privileged_groups=privileged_groups) acc_test = ClassificationMetric( test1, dataset_prejudice_test, unprivileged_groups=unprivileged_groups, privileged_groups=privileged_groups) temp_stat_par.append(metric_test.mean_difference()) temp_disp_imp.append(metric_test.disparate_impact()) temp_eq_opp_diff.append(metric_test.equal_opportunity_difference()) temp_avg_odds_diff.append(metric_test.average_odds_difference()) temp_theil.append(metric_test.theil_index()) temp_acc.append(acc_test.accuracy()) ##################### normal neural net ##################### sess = tf.Session() neural_model = AdversarialDebiasing( privileged_groups=privileged_groups, unprivileged_groups=unprivileged_groups, scope_name='debiased_classifier', debias=False, sess=sess) neural_model.fit(train1) dataset_neural_test = neural_model.predict(test1) sess.close() tf.reset_default_graph() ##################### metrics ##################### metric_test = BinaryLabelDatasetMetric( dataset_neural_test, unprivileged_groups=unprivileged_groups, privileged_groups=privileged_groups) acc_test = ClassificationMetric( test1, dataset_neural_test, unprivileged_groups=unprivileged_groups, privileged_groups=privileged_groups) temp_stat_par.append(metric_test.mean_difference()) temp_disp_imp.append(metric_test.disparate_impact()) temp_eq_opp_diff.append(metric_test.equal_opportunity_difference()) temp_avg_odds_diff.append(metric_test.average_odds_difference()) temp_theil.append(metric_test.theil_index()) temp_acc.append(acc_test.accuracy()) ##################### ensemble ##################### pred_labels_test = [] for i in range(0, len(test1.features)): arr_test = mode([ dataset_debiasing_test[i], dataset_prejudice_test[i], dataset_neural_test[i] ]) pred_labels_test.append(arr_test[0][0]) dataset_ensemble_test = test1.copy() dataset_ensemble_test.labels = np.array(pred_labels_test) ##################### metrics ##################### metric_test = BinaryLabelDatasetMetric( dataset_ensemble_train, unprivileged_groups=unprivileged_groups, privileged_groups=privileged_groups) acc_test = ClassificationMetric( test1, dataset_ensemble_train, unprivileged_groups=unprivileged_groups, privileged_groups=privileged_groups) temp_stat_par.append(metric_test.mean_difference()) temp_disp_imp.append(metric_test.disparate_impact()) temp_eq_opp_diff.append(metric_test.equal_opportunity_difference()) temp_avg_odds_diff.append(metric_test.average_odds_difference()) temp_theil.append(metric_test.theil_index()) temp_acc.append(acc_test.accuracy()) ######### DUMP SHIT ########### stat_par.append(temp_stat_par) disp_imp.append(temp_disp_imp) eq_opp_diff.append(temp_eq_opp_diff) avg_odds_diff.append(temp_avg_odds_diff) theil.append(temp_theil) acc.append(temp_acc) ################## with reweighing ########################## temp_stat_par = [] temp_disp_imp = [] temp_eq_opp_diff = [] temp_avg_odds_diff = [] temp_theil = [] temp_acc = [] ################## adversarial debiasing ################## sess = tf.Session() debiased_model_reweighing = AdversarialDebiasing( privileged_groups=privileged_groups, unprivileged_groups=unprivileged_groups, scope_name='debiased_classifier', debias=True, sess=sess) debiased_model_reweighing.fit(dataset_transf_train) dataset_debiasing_test_reweighing = debiased_model_reweighing.predict( test1) sess.close() tf.reset_default_graph() ##################### metrics ##################### metric_test = BinaryLabelDatasetMetric( dataset_debiasing_test_reweighing, unprivileged_groups=unprivileged_groups, privileged_groups=privileged_groups) acc_test = ClassificationMetric( test1, dataset_debiasing_test_reweighing, unprivileged_groups=unprivileged_groups, privileged_groups=privileged_groups) temp_stat_par.append(metric_test.mean_difference()) temp_disp_imp.append(metric_test.disparate_impact()) temp_eq_opp_diff.append(metric_test.equal_opportunity_difference()) temp_avg_odds_diff.append(metric_test.average_odds_difference()) temp_theil.append(metric_test.theil_index()) temp_acc.append(acc_test.accuracy()) ##################### prejudice remover ##################### prejudice_model_reweighing = PrejudiceRemover(eta=100, sensitive_attr='sex') prejudice_model_reweighing.fit(dataset_transf_train) dataset_prejudice_test_reweighing = prejudice_model_reweighing.predict( test1) ##################### metrics ##################### metric_test = BinaryLabelDatasetMetric( dataset_prejudice_test_reweighing, unprivileged_groups=unprivileged_groups, privileged_groups=privileged_groups) acc_test = ClassificationMetric( test1, dataset_prejudice_test_reweighing, unprivileged_groups=unprivileged_groups, privileged_groups=privileged_groups) temp_stat_par.append(metric_test.mean_difference()) temp_disp_imp.append(metric_test.disparate_impact()) temp_eq_opp_diff.append(metric_test.equal_opportunity_difference()) temp_avg_odds_diff.append(metric_test.average_odds_difference()) temp_theil.append(metric_test.theil_index()) temp_acc.append(acc_test.accuracy()) ##################### normal neural net ##################### sess = tf.Session() neural_model = AdversarialDebiasing( privileged_groups=privileged_groups, unprivileged_groups=unprivileged_groups, scope_name='debiased_classifier', debias=False, sess=sess) neural_model.fit(dataset_transf_train) dataset_neural_test = neural_model.predict(test1) sess.close() tf.reset_default_graph() ##################### metrics ##################### metric_test = BinaryLabelDatasetMetric( dataset_neural_test, unprivileged_groups=unprivileged_groups, privileged_groups=privileged_groups) acc_test = ClassificationMetric( test1, dataset_neural_test, unprivileged_groups=unprivileged_groups, privileged_groups=privileged_groups) temp_stat_par.append(metric_test.mean_difference()) temp_disp_imp.append(metric_test.disparate_impact()) temp_eq_opp_diff.append(metric_test.equal_opportunity_difference()) temp_avg_odds_diff.append(metric_test.average_odds_difference()) temp_theil.append(metric_test.theil_index()) temp_acc.append(acc_test.accuracy()) ##################### ensemble ##################### pred_labels_test = [] for i in range(0, len(test1.features)): arr_test = mode([ dataset_debiasing_test[i], dataset_prejudice_test[i], dataset_neural_test[i] ]) pred_labels_test.append(arr_test[0][0]) dataset_ensemble_test = test1.copy() dataset_ensemble_test.labels = np.array(pred_labels_test) ##################### metrics ##################### metric_test = BinaryLabelDatasetMetric( dataset_ensemble_test, unprivileged_groups=unprivileged_groups, privileged_groups=privileged_groups) acc_test = ClassificationMetric( test1, dataset_ensemble_test, unprivileged_groups=unprivileged_groups, privileged_groups=privileged_groups) temp_stat_par.append(metric_test.mean_difference()) temp_disp_imp.append(metric_test.disparate_impact()) temp_eq_opp_diff.append(metric_test.equal_opportunity_difference()) temp_avg_odds_diff.append(metric_test.average_odds_difference()) temp_theil.append(metric_test.theil_index()) temp_acc.append(acc_test.accuracy()) ######### DUMP SHIT ########### stat_par_reweigh.append(temp_stat_par) disp_imp_reweigh.append(temp_disp_imp) eq_opp_diff_reweigh.append(temp_eq_opp_diff) avg_odds_diff_reweigh.append(temp_avg_odds_diff) theil_reweigh.append(temp_theil) acc_reweigh.append(temp_acc) without_reweighing = [ stat_par, disp_imp, eq_opp_diff, avg_odds_diff, theil, acc ] with_reweighing = [ stat_par_reweigh, disp_imp_reweigh, eq_opp_diff_reweigh, avg_odds_diff_reweigh, theil_reweigh, acc_reweigh ] for metric in range(len(without_reweighing)): name = "metric" + str(metric) sublist = without_reweighing[metric] with open(name, "wb") as csv_file: writer = csv.writer(csv_file) writer.writerows(sublist) for metric in range(len(with_reweighing)): name = "metric" + str(metric) + "reweigh" sublist = with_reweighing[metric] with open(name, "wb") as csv_file: writer = csv.writer(csv_file) writer.writerows(sublist)
def fairness_check(label_dir, model_dir): """Need to generalize the protected features""" # races_to_consider = [0,4] unprivileged_groups = [{'race': 4.0}] privileged_groups = [{'race': 0.0}] favorable_label = 0.0 unfavorable_label = 1.0 """Load the necessary labels and protected features for fairness check""" # y_train = np.loadtxt(label_dir + '/y_train.out') # p_train = np.loadtxt(label_dir + '/p_train.out') y_test = np.loadtxt(label_dir + '/y_test.out') p_test = np.loadtxt(label_dir + '/p_test.out') y_pred = np.loadtxt(label_dir + '/y_pred.out') """Calculate the fairness metrics""" # original_traning_dataset = dataset_wrapper(outcome=y_train, protected=p_train, # unprivileged_groups=unprivileged_groups, # privileged_groups=privileged_groups, # favorable_label=favorable_label, # unfavorable_label=unfavorable_label) original_test_dataset = dataset_wrapper(outcome=y_test, protected=p_test, unprivileged_groups=unprivileged_groups, privileged_groups=privileged_groups, favorable_label=favorable_label, unfavorable_label=unfavorable_label) plain_predictions_test_dataset = dataset_wrapper(outcome=y_pred, protected=p_test, unprivileged_groups=unprivileged_groups, privileged_groups=privileged_groups, favorable_label=favorable_label, unfavorable_label=unfavorable_label) classified_metric_nodebiasing_test = ClassificationMetric(original_test_dataset, plain_predictions_test_dataset, unprivileged_groups=unprivileged_groups, privileged_groups=privileged_groups) TPR = classified_metric_nodebiasing_test.true_positive_rate() TNR = classified_metric_nodebiasing_test.true_negative_rate() bal_acc_nodebiasing_test = 0.5*(TPR+TNR) print("#### Plain model - without debiasing - classification metrics on test set") # print("Test set: Classification accuracy = %f" % classified_metric_nodebiasing_test.accuracy()) # print("Test set: Balanced classification accuracy = %f" % bal_acc_nodebiasing_test) # print("Test set: Statistical parity difference = %f" % classified_metric_nodebiasing_test.statistical_parity_difference()) # print("Test set: Disparate impact = %f" % classified_metric_nodebiasing_test.disparate_impact()) # print("Test set: Equal opportunity difference = %f" % classified_metric_nodebiasing_test.equal_opportunity_difference()) # print("Test set: Average odds difference = %f" % classified_metric_nodebiasing_test.average_odds_difference()) # print("Test set: Theil index = %f" % classified_metric_nodebiasing_test.theil_index()) # print("Test set: False negative rate difference = %f" % classified_metric_nodebiasing_test.false_negative_rate_difference()) metrics = { "Classification accuracy": classified_metric_nodebiasing_test.accuracy(), "Balanced classification accuracy": bal_acc_nodebiasing_test, "Statistical parity difference": classified_metric_nodebiasing_test.statistical_parity_difference(), "Disparate impact": classified_metric_nodebiasing_test.disparate_impact(), "Equal opportunity difference": classified_metric_nodebiasing_test.equal_opportunity_difference(), "Average odds difference": classified_metric_nodebiasing_test.average_odds_difference(), "Theil index": classified_metric_nodebiasing_test.theil_index(), "False negative rate difference": classified_metric_nodebiasing_test.false_negative_rate_difference() } return {"metrics": metrics}
def comb_algorithm(l, m, n, dataset_original1, privileged_groups1, unprivileged_groups1, optim_options1): dataset_original2 = copy.deepcopy(dataset_original1) privileged_groups2 = copy.deepcopy(privileged_groups1) unprivileged_groups2 = copy.deepcopy(unprivileged_groups1) optim_options2 = copy.deepcopy(optim_options1) print(l, m, n) dataset_orig_train, dataset_orig_vt = dataset_original2.split([0.7], shuffle=True) dataset_orig_valid, dataset_orig_test = dataset_orig_vt.split([0.5], shuffle=True) if l == 0: dataset_transf_train, dataset_transf_valid, dataset_transf_test = dataset_orig_train, dataset_orig_valid, dataset_orig_test else: pre_used = preAlgorithm[l - 1] dataset_transf_train, dataset_transf_valid, dataset_transf_test = Pre( pre_used, dataset_orig_train, dataset_orig_valid, dataset_orig_test, privileged_groups2, unprivileged_groups2, optim_options2) #assert (l,m,n)!=(2,0,0) #assert not np.all(dataset_transf_train.labels.flatten()==1.0) if m == 0: dataset_transf_valid_pred, dataset_transf_test_pred = train( dataset_transf_train, dataset_transf_valid, dataset_transf_test, privileged_groups2, unprivileged_groups2) else: in_used = inAlgorithm[m - 1] if in_used == "adversarial_debiasing": dataset_transf_valid_pred, dataset_transf_test_pred = adversarial_debiasing( dataset_transf_train, dataset_transf_valid, dataset_transf_test, privileged_groups2, unprivileged_groups2) elif in_used == "art_classifier": dataset_transf_valid_pred, dataset_transf_test_pred = art_classifier( dataset_transf_train, dataset_transf_valid, dataset_transf_test, privileged_groups2, unprivileged_groups2) elif in_used == "prejudice_remover": for key, value in privileged_groups2[0].items(): sens_attr = key dataset_transf_valid_pred, dataset_transf_test_pred = prejudice_remover( dataset_transf_train, dataset_transf_valid, dataset_transf_test, privileged_groups2, unprivileged_groups2, sens_attr) if n == 0: dataset_transf_test_pred_transf = dataset_transf_test_pred else: post_used = postAlgorithm[n - 1] if post_used == "calibrated_eqodds": cpp = CalibratedEqOddsPostprocessing( privileged_groups=privileged_groups2, unprivileged_groups=unprivileged_groups2, cost_constraint=cost_constraint, seed=1) cpp = cpp.fit(dataset_transf_valid, dataset_transf_valid_pred) dataset_transf_test_pred_transf = cpp.predict( dataset_transf_test_pred) elif post_used == "eqodds": EO = EqOddsPostprocessing(unprivileged_groups=unprivileged_groups2, privileged_groups=privileged_groups2, seed=1) EO = EO.fit(dataset_transf_valid, dataset_transf_valid_pred) dataset_transf_test_pred_transf = EO.predict( dataset_transf_test_pred) elif post_used == "reject_option": ROC = RejectOptionClassification( unprivileged_groups=unprivileged_groups2, privileged_groups=privileged_groups2, low_class_thresh=0.01, high_class_thresh=0.99, num_class_thresh=100, num_ROC_margin=50, metric_name=allowed_metrics[0], metric_ub=metric_ub, metric_lb=metric_lb) ROC = ROC.fit(dataset_transf_valid, dataset_transf_valid_pred) dataset_transf_test_pred_transf = ROC.predict( dataset_transf_test_pred) metric = ClassificationMetric(dataset_transf_test, dataset_transf_test_pred_transf, unprivileged_groups=unprivileged_groups2, privileged_groups=privileged_groups2) metrics = OrderedDict() metrics["Classification accuracy"] = metric.accuracy() TPR = metric.true_positive_rate() TNR = metric.true_negative_rate() bal_acc_nodebiasing_test = 0.5 * (TPR + TNR) metrics["Balanced classification accuracy"] = bal_acc_nodebiasing_test metrics[ "Statistical parity difference"] = metric.statistical_parity_difference( ) metrics["Disparate impact"] = metric.disparate_impact() metrics[ "Equal opportunity difference"] = metric.equal_opportunity_difference( ) metrics["Average odds difference"] = metric.average_odds_difference() metrics["Theil index"] = metric.theil_index() metrics["United Fairness"] = metric.generalized_entropy_index() # print(metrics) feature = "[" for m in metrics: feature = feature + " " + str(round(metrics[m], 4)) feature = feature + "]" return feature
def k_fold_statistics(k_folds, classifier, lambda_values, dataset, unprivileged_groups, privileged_groups): ''' Function to fit classifier to k number of random train/test splits Args: k_folds: number of folds of statistics classifier: SVM or Logistic regression weights: weights for each sample lambda_value: selected level of regularisation dataset: dataset to be used Returns: accuracy_list: test accuracy for each model equal_opp_list: Equal Opportunity difference for each model stat_parity_list: Statistical Parity difference for each model ''' accuracy_list = [] equal_opp_list = [] stat_parity_list = [] for k in range(k_folds): train, test = dataset_orig.split([0.8], shuffle=True) train, validation = train.split([0.8], shuffle=True) scale_orig = StandardScaler() X_train = scale_orig.fit_transform(train.features) y_train = train.labels.ravel() X_test = scale_orig.transform(test.features) y_test = validation.labels.ravel() X_valid = scale_orig.transform(validation.features) y_valid = test.labels.ravel() test_pred = test.copy() valid_pred = validation.copy() RW = Reweighing(unprivileged_groups=unprivileged_groups, privileged_groups=privileged_groups) best_mean_statistic = 0 # fit all candidate models for lambda_value in lambda_values: train = RW.fit_transform(train) if classifier == "Logistic Regression": learner = LogisticRegression(solver='liblinear', random_state=1, penalty='l2', C=1/lambda_value) else: learner = svm.SVC(C=1/lambda_value) learner.fit(X_train,y_train, sample_weight=train.instance_weights) valid_pred.labels = learner.predict(X_valid) metric = ClassificationMetric(validation, valid_pred, unprivileged_groups=unprivileged_groups, privileged_groups=privileged_groups) mean_statistic = (1-abs(metric.equal_opportunity_difference())+metric.accuracy())/2 if mean_statistic > best_mean_statistic: best_learner = learner test_pred.labels = best_learner.predict(X_test) metric = ClassificationMetric(test, test_pred, unprivileged_groups=unprivileged_groups, privileged_groups=privileged_groups) print("----------------") print("Split {}/{}".format(k, k_folds)) print("Equal opportunity:", "{0:.3f}".format(metric.equal_opportunity_difference())) print("Statistical parity:", "{0:.3f}".format(metric.statistical_parity_difference())) print("Accuracy:", "{0:.3f}".format(metric.accuracy())) accuracy_list.append(metric.accuracy()) equal_opp_list.append(metric.equal_opportunity_difference()) stat_parity_list.append(metric.statistical_parity_difference()) accuracy_list = np.array(accuracy_list) equal_opp_list = np.array(equal_opp_list) stat_parity_list = np.array(stat_parity_list) print('The mean statistics for {} folds is:'.format(k_folds)) print("Mean Accuracy: {0:.3f},".format(np.mean(accuracy_list)), "Std: {0:.3f}".format(np.std(accuracy_list))) print("Mean Equal Opportunity: {0:.3f},".format(np.mean(equal_opp_list)), "Std: {0:.3f}".format( np.std(equal_opp_list))) print("Mean Statistical Parity: {0:.3f},".format(np.mean(stat_parity_list)), "Std: {0:.3f}".format(np.std(stat_parity_list))) return accuracy_list, equal_opp_list, stat_parity_list
unprivileged_protected_attributes=unprivileged_groups) classificaltion_metric = \ ClassificationMetric( dataset_ground_truth, dataset_classifier, unprivileged_groups=unprivileged_groups, privileged_groups=privileged_groups) TPR = classificaltion_metric.true_positive_rate() TNR = classificaltion_metric.true_negative_rate() bal_acc_nodebiasing_test = 0.5 * (TPR + TNR) metrics = { "classification_accuracy": classificaltion_metric.accuracy(), "balanced_classification_accuracy": bal_acc_nodebiasing_test, "statistical_parity_difference": classificaltion_metric.statistical_parity_difference(), "disparate_impact": classificaltion_metric.disparate_impact(), "equal_opportunity_difference": classificaltion_metric.equal_opportunity_difference(), "average_odds_difference": classificaltion_metric.average_odds_difference(), "theil_index": classificaltion_metric.theil_index(), "false_negative_rate_difference": classificaltion_metric.false_negative_rate_difference() }
def fairness_check(s3_url, bucket_name, s3_username, s3_password, training_id): cos = boto3.resource("s3", endpoint_url=s3_url, aws_access_key_id=s3_username, aws_secret_access_key=s3_password) y_test_out = 'y_test.out' p_test_out = 'p_test.out' y_pred_out = 'y_pred.out' get_s3_item(cos, bucket_name, training_id + '/' + y_test_out, y_test_out) get_s3_item(cos, bucket_name, training_id + '/' + p_test_out, p_test_out) get_s3_item(cos, bucket_name, training_id + '/' + y_pred_out, y_pred_out) """Need to generalize the protected features""" unprivileged_groups = [{'race': 4.0}] privileged_groups = [{'race': 0.0}] favorable_label = 0.0 unfavorable_label = 1.0 """Load the necessary labels and protected features for fairness check""" y_test = np.loadtxt(y_test_out) p_test = np.loadtxt(p_test_out) y_pred = np.loadtxt(y_pred_out) """Calculate the fairness metrics""" original_test_dataset = dataset_wrapper(outcome=y_test, protected=p_test, unprivileged_groups=unprivileged_groups, privileged_groups=privileged_groups, favorable_label=favorable_label, unfavorable_label=unfavorable_label) plain_predictions_test_dataset = dataset_wrapper(outcome=y_pred, protected=p_test, unprivileged_groups=unprivileged_groups, privileged_groups=privileged_groups, favorable_label=favorable_label, unfavorable_label=unfavorable_label) classified_metric_nodebiasing_test = ClassificationMetric(original_test_dataset, plain_predictions_test_dataset, unprivileged_groups=unprivileged_groups, privileged_groups=privileged_groups) TPR = classified_metric_nodebiasing_test.true_positive_rate() TNR = classified_metric_nodebiasing_test.true_negative_rate() bal_acc_nodebiasing_test = 0.5*(TPR+TNR) print("#### Plain model - without debiasing - classification metrics on test set") metrics = { "Classification accuracy": classified_metric_nodebiasing_test.accuracy(), "Balanced classification accuracy": bal_acc_nodebiasing_test, "Statistical parity difference": classified_metric_nodebiasing_test.statistical_parity_difference(), "Disparate impact": classified_metric_nodebiasing_test.disparate_impact(), "Equal opportunity difference": classified_metric_nodebiasing_test.equal_opportunity_difference(), "Average odds difference": classified_metric_nodebiasing_test.average_odds_difference(), "Theil index": classified_metric_nodebiasing_test.theil_index(), "False negative rate difference": classified_metric_nodebiasing_test.false_negative_rate_difference() } print("metrics: ", metrics) return metrics
def comb_algorithm(l, m, n, dataset_original1, privileged_groups1, unprivileged_groups1, optim_options1): dataset_original2 = copy.deepcopy(dataset_original1) privileged_groups2 = copy.deepcopy(privileged_groups1) unprivileged_groups2 = copy.deepcopy(unprivileged_groups1) optim_options2 = copy.deepcopy(optim_options1) print(l, m, n) dataset_original_train, dataset_original_vt = dataset_original2.split( [0.7], shuffle=True) dataset_original_valid, dataset_original_test = dataset_original_vt.split( [0.5], shuffle=True) dataset_original_test.labels = dataset_original_test.labels print('=======================') #print(dataset_original_test.labels) dataset_orig_train = copy.deepcopy(dataset_original_train) dataset_orig_valid = copy.deepcopy(dataset_original_valid) dataset_orig_test = copy.deepcopy(dataset_original_test) if l == 0: dataset_transfer_train = copy.deepcopy(dataset_original_train) dataset_transfer_valid = copy.deepcopy(dataset_original_valid) dataset_transfer_test = copy.deepcopy(dataset_original_test) #dataset_transf_train, dataset_transf_valid, dataset_transf_test = dataset_orig_train, dataset_orig_valid, dataset_orig_test else: pre_used = preAlgorithm[l - 1] dataset_transfer_train, dataset_transfer_valid, dataset_transfer_test = Pre( pre_used, dataset_orig_train, dataset_orig_valid, dataset_orig_test, privileged_groups2, unprivileged_groups2, optim_options2) dataset_transf_train = copy.deepcopy(dataset_transfer_train) dataset_transf_valid = copy.deepcopy(dataset_transfer_valid) dataset_transf_test = copy.deepcopy(dataset_transfer_test) if m == 0: dataset_transfer_valid_pred, dataset_transfer_test_pred = plain_model( dataset_transf_train, dataset_transf_valid, dataset_transf_test, privileged_groups2, unprivileged_groups2) else: in_used = inAlgorithm[m - 1] if in_used == "adversarial_debiasing": dataset_transfer_valid_pred, dataset_transfer_test_pred = adversarial_debiasing( dataset_transf_train, dataset_transf_valid, dataset_transf_test, privileged_groups2, unprivileged_groups2) elif in_used == "art_classifier": dataset_transfer_valid_pred, dataset_transfer_test_pred = art_classifier( dataset_transf_train, dataset_transf_valid, dataset_transf_test, privileged_groups2, unprivileged_groups2) elif in_used == "prejudice_remover": for key, value in privileged_groups2[0].items(): sens_attr = key dataset_transfer_valid_pred, dataset_transfer_test_pred = prejudice_remover( dataset_transf_train, dataset_transf_valid, dataset_transf_test, privileged_groups2, unprivileged_groups2, sens_attr) dataset_transf_valid_pred = copy.deepcopy(dataset_transfer_valid_pred) dataset_transf_test_pred = copy.deepcopy(dataset_transfer_test_pred) if n == 0: dataset_transf_test_pred_transf = copy.deepcopy( dataset_transfer_test_pred) else: post_used = postAlgorithm[n - 1] if post_used == "calibrated_eqodds": cpp = CalibratedEqOddsPostprocessing( privileged_groups=privileged_groups2, unprivileged_groups=unprivileged_groups2, cost_constraint=cost_constraint) cpp = cpp.fit(dataset_transfer_valid, dataset_transf_valid_pred) dataset_transf_test_pred_transf = cpp.predict( dataset_transf_test_pred) elif post_used == "eqodds": EO = EqOddsPostprocessing(unprivileged_groups=unprivileged_groups2, privileged_groups=privileged_groups2) EO = EO.fit(dataset_transfer_valid, dataset_transf_valid_pred) dataset_transf_test_pred_transf = EO.predict( dataset_transf_test_pred) elif post_used == "reject_option": #dataset_transf_test_pred_transf = reject_option(dataset_transf_valid, dataset_transf_valid_pred, dataset_transf_test, dataset_transf_test_pred, privileged_groups2, unprivileged_groups2) ROC = RejectOptionClassification( unprivileged_groups=unprivileged_groups2, privileged_groups=privileged_groups2) ROC = ROC.fit(dataset_transfer_valid, dataset_transf_valid_pred) dataset_transf_test_pred_transf = ROC.predict( dataset_transf_test_pred) #print('=======================') org_labels = dataset_orig_test.labels print(dataset_orig_test.labels) #print(dataset_transf_test.labels) #print('=======================') pred_labels = dataset_transf_test_pred.labels print(dataset_transf_test_pred.labels) true_pred = org_labels == pred_labels print("acc after in: ", float(np.sum(true_pred)) / pred_labels.shape[1]) #print('=======================') #print(dataset_transf_test_pred_transf.labels) #print(dataset_transf_test_pred_transf.labels.shape) metric = ClassificationMetric(dataset_transfer_test, dataset_transf_test_pred_transf, unprivileged_groups=unprivileged_groups2, privileged_groups=privileged_groups2) metrics = OrderedDict() metrics["Classification accuracy"] = metric.accuracy() TPR = metric.true_positive_rate() TNR = metric.true_negative_rate() bal_acc_nodebiasing_test = 0.5 * (TPR + TNR) metrics["Balanced classification accuracy"] = bal_acc_nodebiasing_test metrics[ "Statistical parity difference"] = metric.statistical_parity_difference( ) metrics["Disparate impact"] = metric.disparate_impact() metrics[ "Equal opportunity difference"] = metric.equal_opportunity_difference( ) metrics["Average odds difference"] = metric.average_odds_difference() metrics["Theil index"] = metric.theil_index() metrics["United Fairness"] = metric.generalized_entropy_index() feature = [] feature_str = "[" for m in metrics: data = round(metrics[m], 4) feature.append(data) feature_str = feature_str + str(data) + " " feature_str = feature_str + "]" return feature, feature_str
def fairness_check(object_storage_url, object_storage_username, object_storage_password, data_bucket_name, result_bucket_name, model_id, feature_testset_path='processed_data/X_test.npy', label_testset_path='processed_data/y_test.npy', protected_label_testset_path='processed_data/p_test.npy', model_class_file='model.py', model_class_name='model', favorable_label=0.0, unfavorable_label=1.0, privileged_groups=[{ 'race': 0.0 }], unprivileged_groups=[{ 'race': 4.0 }]): url = re.compile(r"https?://") cos = Minio(url.sub('', object_storage_url), access_key=object_storage_username, secret_key=object_storage_password, secure=False) # Local Minio server won't have HTTPS dataset_filenamex = "X_test.npy" dataset_filenamey = "y_test.npy" dataset_filenamep = "p_test.npy" weights_filename = "model.pt" model_files = model_id + '/_submitted_code/model.zip' cos.fget_object(data_bucket_name, feature_testset_path, dataset_filenamex) cos.fget_object(data_bucket_name, label_testset_path, dataset_filenamey) cos.fget_object(data_bucket_name, protected_label_testset_path, dataset_filenamep) cos.fget_object(result_bucket_name, model_id + '/' + weights_filename, weights_filename) cos.fget_object(result_bucket_name, model_files, 'model.zip') # Load PyTorch model definition from the source code. zip_ref = zipfile.ZipFile('model.zip', 'r') zip_ref.extractall('model_files') zip_ref.close() modulename = 'model_files.' + model_class_file.split('.')[0].replace( '-', '_') ''' We required users to define where the model class is located or follow some naming convention we have provided. ''' model_class = getattr(importlib.import_module(modulename), model_class_name) # load & compile model device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu') model = model_class().to(device) model.load_state_dict(torch.load(weights_filename, map_location=device)) """Load the necessary labels and protected features for fairness check""" x_test = np.load(dataset_filenamex) y_test = np.load(dataset_filenamey) p_test = np.load(dataset_filenamep) _, y_pred = evaluate(model, x_test, y_test) """Calculate the fairness metrics""" original_test_dataset = dataset_wrapper( outcome=y_test, protected=p_test, unprivileged_groups=unprivileged_groups, privileged_groups=privileged_groups, favorable_label=favorable_label, unfavorable_label=unfavorable_label) plain_predictions_test_dataset = dataset_wrapper( outcome=y_pred, protected=p_test, unprivileged_groups=unprivileged_groups, privileged_groups=privileged_groups, favorable_label=favorable_label, unfavorable_label=unfavorable_label) classified_metric_nodebiasing_test = ClassificationMetric( original_test_dataset, plain_predictions_test_dataset, unprivileged_groups=unprivileged_groups, privileged_groups=privileged_groups) TPR = classified_metric_nodebiasing_test.true_positive_rate() TNR = classified_metric_nodebiasing_test.true_negative_rate() bal_acc_nodebiasing_test = 0.5 * (TPR + TNR) print( "#### Plain model - without debiasing - classification metrics on test set" ) metrics = { "Classification accuracy": classified_metric_nodebiasing_test.accuracy(), "Balanced classification accuracy": bal_acc_nodebiasing_test, "Statistical parity difference": classified_metric_nodebiasing_test.statistical_parity_difference(), "Disparate impact": classified_metric_nodebiasing_test.disparate_impact(), "Equal opportunity difference": classified_metric_nodebiasing_test.equal_opportunity_difference(), "Average odds difference": classified_metric_nodebiasing_test.average_odds_difference(), "Theil index": classified_metric_nodebiasing_test.theil_index(), "False negative rate difference": classified_metric_nodebiasing_test.false_negative_rate_difference() } print("metrics: ", metrics) return metrics
def compute_metrics(model, X_test, y_test, X_train, y_train, dataset_test, unprivileged_groups, privileged_groups, protect_attribute, print_result): """ Calculate and return: model accuracy and fairness metrics Parameters ---------- model: scikit-learn classifier X_test: numpy 2d array y_test: numpy 1d array X_train: numpy 2d array y_train: numpy 1d array dataset_test: aif360.datasets.BinaryLabelDataset unprivileged_groups: list<dict> Dictionary where the key is the name of the sensitive column in the dataset, and the value is the value of the unprivileged group in the dataset privileged_groups: list<dict> Dictionary where the key is the name of the sensitive column in the dataset, and the value is the value of the privileged group in the dataset protect_attribute print_result """ result = {} y_pred_test = model.predict(X_test) result['acc_test'] = accuracy_score(y_true=y_test, y_pred=y_pred_test) y_pred_train = model.predict(X_train) result['acc_train'] = accuracy_score(y_true=y_train, y_pred=y_pred_train) dataset_pred = dataset_test.copy() dataset_pred.labels = y_pred_test bin_metric = BinaryLabelDatasetMetric(dataset_pred, unprivileged_groups=unprivileged_groups, privileged_groups=privileged_groups) result['disp_impact'] = bin_metric.disparate_impact() result['stat_parity'] = bin_metric.mean_difference() classif_metric = ClassificationMetric(dataset_test, dataset_pred, unprivileged_groups=unprivileged_groups, privileged_groups=privileged_groups) result['avg_odds'] = classif_metric.average_odds_difference() result['equal_opport'] = classif_metric.equal_opportunity_difference() result['false_discovery_rate'] = classif_metric.false_discovery_rate_difference() result['entropy_index'] = classif_metric.generalized_entropy_index() result['acc_test_clf'] = classif_metric.accuracy(privileged=None) result['acc_test_priv'] = classif_metric.accuracy(privileged=True) result['acc_test_unpriv'] = classif_metric.accuracy(privileged=False) result['consistency'] = consitency(X_test, y_pred_test, protect_attribute, n_neighbors=5) result['counterfactual'] = counterfactual(X_test, model, protect_attribute) if print_result: print("Train accuracy: ", result['acc_train']) print("Test accuracy: ", result['acc_test']) print("Test accuracy clf: ", result['acc_test_clf']) print("Test accuracy priv.: ", result['acc_test_priv']) print("Test accuracy unpriv.: ", result['acc_test_unpriv']) print('Disparate impact: ', result['disp_impact']) print('Mean difference: ', result['stat_parity']) print('Average odds difference:', result['avg_odds']) print('Equality of opportunity:', result['equal_opport']) print('False discovery rate difference:', result['false_discovery_rate']) print('Generalized entropy index:', result['entropy_index']) print('Consistency: ', result['consistency']) print('Counterfactual fairness: ', result['counterfactual']) return result