<jupyter_start><jupyter_text>Equal Opportunity DatasetUsing adult income dataset from UCI repo provided by shap library. DefinitionAdds conditioning on label `y=1` compared to Demographic parity, i.e.Mathematically:$ratio <= \frac{P[h(X) = 1 | A = a, Y = 1]}{P[h(X) = 1 | Y = 1]} <= \frac{1}{ratio}, \forall a, y, y'$<jupyter_code>import numpy as np
import pandas as pd

import shap
shap.initjs()

from fairlearn.reductions import ExponentiatedGradient
from sklearn.preprocessing import LabelEncoder, StandardScaler, MinMaxScaler
X, Y = shap.datasets.adult()
sensitive_attribute = 'Sex'

A = X[sensitive_attribute]
X = pd.get_dummies(X)

sc = StandardScaler()
X_scaled = sc.fit_transform(X)
X_scaled = pd.DataFrame(X_scaled, columns=X.columns)

le = LabelEncoder()
Y = le.fit_transform(Y)

X = X.reset_index(drop=True)
A = A.reset_index(drop=True)
class LeastSquaresBinaryClassifierLearner:
    def __init__(self):
        self.weights = None

    def fit(self, X, Y, sample_weight):
        sqrtW = np.sqrt(sample_weight)
        matX = np.array(X) * sqrtW[:, np.newaxis]
        vecY = Y * sqrtW
        self.lsqinfo = np.linalg.lstsq(matX, vecY, rcond=-1)
        self.weights = pd.Series(self.lsqinfo[0], index=list(X))

    def predict(self, X):
        pred = X.dot(np.asarray(self.weights))
        return 1 * (pred > 0.5)
unmitigated_predictor = LeastSquaresBinaryClassifierLearner()
unmitigated_predictor.fit(X, Y, sample_weight=[1])
from fairlearn.reductions import TruePositiveRateDifference, ErrorRate

def Unmit(X): return unmitigated_predictor.predict(X)
# violation
disparity_moment = TruePositiveRateDifference()
disparity_moment.load_data(X, Y, sensitive_features=A)
eo_violation_unmitigated = disparity_moment.gamma(Unmit).max()

# error
error = ErrorRate()
error.load_data(X, Y, sensitive_features=A)
eo_error_unmitigated = error.gamma(Unmit)[0]<jupyter_output><empty_output><jupyter_text>Experiment 1 - Calculating violation by varying epsilon<jupyter_code># Experiment 1 - Calculating violation by varying epsilon 
eps_list = [0.001, 0.005, 0.01, 0.05, 0.1]
eo_expgrad_error = []
eo_expgrad_violation = []
eo_best_gap = []

estimator = LeastSquaresBinaryClassifierLearner()
for eps in eps_list:
    expgrad_X = ExponentiatedGradient(estimator,
                                      constraints=TruePositiveRateDifference(),
                                      eps=eps, nu=1e-6)
    
    expgrad_X.fit(X, Y, sensitive_features=A)

    def Q(X): return expgrad_X._pmf_predict(X)[:, 1]
    # violation
    disparity_moment = TruePositiveRateDifference()
    disparity_moment.load_data(X, Y, sensitive_features=A)
    disparity = disparity_moment.gamma(Q).max()
    
    # error
    error = ErrorRate()
    error.load_data(X, Y, sensitive_features=A)
    error = error.gamma(Q)[0]
    
    eo_expgrad_violation.append(disparity)
    eo_expgrad_error.append(error)
    eo_best_gap.append(expgrad_X._best_gap)
print('{}\t\t{}\t\t\t{}\t\t\t{}'.format('Epsilon', 'Max Violation', 'Error', 'Best Gap'))
for i in range(len(eps_list)):
    print('{}\t\t{}\t\t{}\t{}'.format(eps_list[i], eo_expgrad_violation[i],
                                  eo_expgrad_error[i], eo_best_gap[i]))
print('{}\t\t{}\t\t{}\t{}'.format('Unmit.', eo_violation_unmitigated,
                              eo_error_unmitigated, '-'))
import matplotlib.pyplot as plt

plt.scatter(eo_expgrad_violation, eo_expgrad_error, label="expgrad")
plt.plot(eo_violation_unmitigated, eo_error_unmitigated, 'ro', label="unmitigated")
plt.xlabel('Violation of the fairness constraint')
plt.ylabel('Error')
plt.title('Adult UCI / TruePositiveRateDifference / Simple Learner')
plt.legend()
plt.show()<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.12881447475020255, 'fraction_numerical': 0.00945179584120983, 'mean_word_length': 4.261363636363637, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 10, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 3, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '2', 'dir': 'jupyter-structured-clean-dedup', 'id': '156261', 'license': 'MIT', 'n_tokens_mistral': 1399, 'n_tokens_neox': 1319, 'n_words': 248, 'path': 'notebooks/EqualOpportunity-experiment-on-adult-dataset.ipynb', 'repo_name': 'GeGao2014/fairlearn', 'size': '3703'}