Measuring Effectiveness in Machine Learning Classification Models

August 25, 2023
Authored by
Franklin Cardenoso Fernandez
Researcher at Holistic AI
Measuring Effectiveness in Machine Learning Classification Models

The problem: unfair bias in ML models

Bias in machine learning (ML) refers to unfair discrimination in the outcomes produced by an algorithm for certain disadvantaged groups. Most of the time, this problem comes from the data used to train these algorithms, producing models that inadvertently encode pre-existing societal biases and prejudices.

Although different methods are being developed and applied to mitigate this problem during the different stages of an AI model's development, new questions have arisen. How can we measure the effectiveness of bias mitigation methods? And how can we calculate the method that presents the trade-off between fairness and accuracy in machine learning models?

In this blog, we will explore the fairness-accuracy trade-off analysis for classification models. This is similar in nature to a previous blog, Machine Learning Classification Models: Exploring the Fairness-Accuracy Trade-Off. However, the main difference is that this new approach allows us to categorise and benchmark bias mitigator models by measuring their effectiveness and comparing them with a baseline.

We will observe this with a pertinent case study.

The solution: Benchmarking bias mitigators with Fairea

Various methods have been developed to mitigate bias in ML models. However, improvements in fairness often come at the expense of reduced model accuracy. This is known as the trade-off between accuracy and fairness for ML models.

Taking this concept into account while also taking into consideration the diversity of mitigators, Hort et. al. presented an interesting approach, named Fairea, to benchmark bias mitigation methods and determine which ones present a better fairness-accuracy trade-off.

The core of this approach is the use of a model behaviour mutation method to create a baseline that can be used to compare quantitatively the fairness-accuracy trade-off for different bias mitigation algorithms and then evaluate their effectiveness in the given scenario.

To perform this analysis, the approach consists of three separate steps:

  1. A baseline is created by fitting a model without mitigation and then applying a model behaviour mutation that gradually changes the model outputs, simulating a series of naïve bias mitigation models.
  1. Given a set of fitted bias mitigation models, Fairea performs a mapping of these models into five mitigation regions to classify their effectiveness.
  1. The effectiveness trade-off is assessed quantitatively by measuring the gap between the mitigators' effectiveness and the baseline.

We will detail every stage in this blog post.

Step-by-step case study implementation

To put everything into practice, we will perform a case study by following the different stages of the Fairea approach, using them to perform a fairness-accuracy analysis and determine the most effective model.

For the computational implementation, we will use a Python environment with the following packages:

  • Quantitative measuring with computational geometry: Shapely package
  • Classification model and accuracy metric implementation: Scikit-learn package
  • Fairness metrics and mitigators implementation: Holisticai package.

We start with our implementation. First, we import the required packages:

import numpy as np 

import pandas as pd 

import matplotlib.pyplot as plt 

from holisticai.datasets import load_adult 

from shapely.geometry import Polygon, Point, LineString 

Dataset preprocessing

For our analysis, we will use the well-known “Adult dataset” from the UCI Machine Learning Repository, a publicly available dataset containing information about the age, education, marital status, race and gender of individuals from the United States. The objective is to predict whether an individual's income will be above or below $50K per year. The protected attribute we will use in this instance is the “Sex” feature.

This dataset can be easily imported and downloaded from the holisticai package by running the following lines:

from holisticai.datasets import load_adult 

data = load_adult() 

Next, we preprocess and format the data.  This can be achieved using the following function and running:

df = pd.concat([data["data"], data["target"]], axis=1)

df_clean, group_a, group_b = preprocess_adult_dataset(df)


Dataset preprocessing

X = df_clean.iloc[:,:-1].values

y = df_clean.iloc[:,-1].values

X_train,X_test,y_train,y_test, group_a_tr, group_a_ts, group_b_tr, group_b_ts = \

train_test_split(X, y, group_a, group_b, test_size=0.2, random_state=42) train_data = X_train, y_train, group_a_tr, group_b_tr

test_data = X_test, y_test, group_a_ts, group_b_ts

Now that we have our dataset and protected groups, we can start with the Fairea pipeline.

Step 1) Baseline creation with model behaviour mutation

The first step involves a baseline construction. This is done by fitting a simple model which serves as a baseline, before the outputs are mutated to collect a set of trade-off points that will be used later to determine the mitigation regions for the model comparison. This mutation is achieved by copying the predictions and then replacing small sets with the same label. The following image gives more details of this procedure:

Table 1. Example of mutation procedure. Inspired from here.

Samples id 1 2 3 4 5 6 7 8 9 10 Acurracy Bias
True label 0 1 0 1 0 1 1 1 0 0
Original model predictions 0 1 0 1 0 0 1 1 1 0 0.80 0.50
Mutation degree: 40% 1 1 1 1 0 0 1 1 1 0 0.60 0.17
Mutation degree: 100% 1 1 1 1 1 1 1 1 1 1 0.50 0.00

This is done by running the following code:

mutation_strategies = {"0":[1,0],"1":[0,1]}

degrees = [0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1]

baseline_points = create_baseline(X, y, group_a, group_b, data_splits=10, repetitions=10, odds=mutation_strategies,options = [0,1], degrees = degrees)

acc0 = np.array([np.mean([row[0] for row in baseline_points["0"][degree]]) for degree in degrees])

spd0 = np.array([np.mean([row[1] for row in baseline_points["0"][degree]]) for degree in degrees])

plt.plot(spd0,acc0,color="blue",marker = "|", linestyle = "solid",linewidth=3,markersize=16)

Fairness-accuracy trade-off baseline
Figure 1. Fairness-accuracy trade-off baseline

Step 2) Bias mitigation effectiveness region division

Once the baseline has been created, the approach categorises the mitigator models into five regions that represent the effectiveness of the bias mitigation. These regions are:

  • "Win-win": when a method improves the accuracy and reduces bias with respect to the original model.
  • "Lose-lose": when a method reduces the accuracy and increases bias with respect to the original model.
  • "Inverted trade-off": When a method improves accuracy but increases bias.
  • "Good trade-off": when a method reduces bias and decreases accuracy but achieves a better trade-off than the baseline.
  • "Poor trade-off": When a method reduces bias and decreases accuracy but achieves a lower trade-off than the baseline.

The following figure shows how the mitigation regions are distributed:

Mitigation regions of bias mitigation methods
Figure 2. Mitigation regions of bias mitigation methods. Taken from here.

Taking this into account, we will train our initial model next. But first, we will apply some mitigation methods. For this, we use the Correlation Remover and the Calibrated Equalized Odds methods which fall into the categories of preprocessing and postprocessing strategies respectively. We will also measure the accuracy of the models and the statistical parity as the accuracy and fairness metrics respectively.

We will do this by running the following code:

# Preprocessing methods

from holisticai.bias.mitigation import CorrelationRemover

# Postprocessing methods

from holisticai.bias.mitigation import CalibratedEqualizedOdds

methods = dict()

scaler = StandardScaler()

X = scaler.fit_transform(X_train)

preprocessing_mitigator = CorrelationRemover()

X = preprocessing_mitigator.fit_transform(X, group_a_tr, group_b_tr)

model = LogisticRegression(), y_train)

X = scaler.transform(X_test)

X = preprocessing_mitigator.transform(X, group_a_ts, group_b_ts)

y_pred = model.predict(X)

acc = metrics.accuracy_score(y_test, y_pred)

sp = statistical_parity(group_a_ts, group_b_ts, y_pred)

name = "CorrelationRemover"

methods[name] = (abs(acc),abs(sp))

scaler = StandardScaler()

X = scaler.fit_transform(X_train)

model = LogisticRegression(), y_train)

y_proba = model.predict_proba(X)

post = CalibratedEqualizedOdds(cost_constraint="fnr"), y_proba, group_a_tr, group_b_tr)

X = scaler.transform(X_test)

y_proba = model.predict_proba(X)

y_pred = post.transform(y_test, y_proba, group_a_ts, group_b_ts)["y_pred"]

acc = metrics.accuracy_score(y_test, y_pred)

sp = statistical_parity(group_a_ts, group_b_ts, y_pred)

name = "CalibratedEqualizedOdds"

methods[name] = (abs(acc),abs(sp))

If we plot the methods and the baseline we will obtain the following graph:

Inserting image...

To perform a better analysis, we will normalise the results and the graph:

normalized_accuracy, normalized_fairness, normalized_methods = normalize(acc0,spd0,methods)

Inserting image...

Now, we will classify the mitigators into the mitigation regions:

# Transform baseline to geometric shape with shapely

baseline = LineString([(x,y) for x, y in zip(normalized_fairness,normalized_accuracy)])

regions = classify_region(baseline, normalized_methods)


{'CorrelationRemover': 'good trade-off', 'CalibratedEqualizedOdds': 'good trade-off'}

For this particular case, we can see that both methods fall into the good trade-off region. This means that in, both methods, the bias has been reduced but the accuracy has also decreased.

Step 3) Quantitative evaluation of trade-off effectiveness

After the mitigators have been categorised, the effectiveness of the methods is measured. Given that the win-win, lose-lose, inverted trade-off and the poor trade-off regions provide clear signals about how the mitigator performs, this measurement is focused on the mitigators that fall into the good trade-off region.

This is achieved by calculating the area that results by projecting a horizontal and a vertical line from the mitigator position to the trade-off points of the baseline. This area represents the strength of the fairness-accuracy trade-off. Therefore, the larger the area is, the better the fairness-accuracy trade-off.

To calculate this area for our case, we use the following code:

good = {k for k,v in regions.items() if v == "good trade-off"}

normalized_methods = {k:v for k,v in normalized_methods.items() if k in good}


for k,v in normalized_methods.items():

area = compute_area(baseline,v)

print (k,area)

CorrelationRemover 0.03877697873937186

CalibratedEqualizedOdds 0.0044568567152961916

As we can see, the model that presents a better trade-off is the Correlation Remover method, since it presents a larger area in comparison with the Calibrated Equalized odds method.


During this tutorial, we have seen how to measure the effectiveness of bias mitigator strategies by following the Fairea approach, which allows the categorisation of models by comparing the fairness and accuracy with respect to a baseline. Consequently, after applying this methodology in a study case with the Adult dataset, we observe that the Correlation Remover and the Calibrated Equalized odds methods present a good fairness-accuracy trade-off. Furthermore, after measuring the effectiveness of both models through the trade-off strength calculation, represented with the area between the mitigator and the baseline, we found that the Correlation remover strategy presents a better fairness-accuracy trade-off.

For more detail on the presented approach, we recommend reading the original publication on the Fariea approach.

A complete implementation of this code can also be found here.

DISCLAIMER: This blog article is for informational purposes only. This blog article is not intended to, and does not, provide legal advice or a legal opinion. It is not a do-it-yourself guide to resolving legal issues or handling litigation. This blog article is not a substitute for experienced legal counsel and does not provide legal advice regarding any situation or employer.

Subscriber to our Newsletter
Join our mailing list to receive the latest news and updates.
We’re committed to your privacy. Holistic AI uses this information to contact you about relevant information, news, and services. You may unsubscribe at anytime. Privacy Policy.

Discover how we can help your company

Schedule a call with one of our experts

Schedule a call