Source code for RuleTree.evaluation.fairness

"""Fairness of a partition of the instances (clusters or predicted classes) with respect to a sensitive attribute."""

import numpy as np

from RuleTree.utils.fairness_metrics import balance_metric, max_fairness_cost


[docs] def evaluate_fairness(labels, sensitive_attribute, ideal_distribution=None) -> dict: """ Fairness of the groups of a partition (clusters, leaves or predicted classes) with respect to a sensitive attribute. Parameters ---------- labels : array-like of shape (n_samples,) Group of each instance, e.g. its cluster. sensitive_attribute : array-like of shape (n_samples,) Value of the sensitive attribute of each instance. ideal_distribution : dict, default=None Value of the sensitive attribute -> ideal fraction in each group. If None, the distribution in the whole data set. Returns ------- scores : dict ``balance``: the smallest ratio between the fraction of a value of the sensitive attribute in a group and in the whole data set (or its inverse), from 0 to 1, the higher the fairer; ``max_fairness_cost``: the largest mean absolute difference between the distribution of the sensitive attribute in a group and the ideal one, the lower the fairer. See Also -------- RuleTree.stumps.regression.FairTreeStumpRegressor : the stump that builds fair trees. Examples -------- >>> import numpy as np >>> from RuleTree.evaluation import evaluate_fairness >>> labels = np.array([0, 0, 0, 0, 1, 1, 1, 1]) >>> sex = np.array(["F", "M", "F", "M", "F", "F", "F", "M"]) >>> evaluate_fairness(labels, sex) {'balance': 0.6666666666666666, 'max_fairness_cost': 0.125} """ labels, sensitive_attribute = np.asarray(labels), np.asarray(sensitive_attribute) if ideal_distribution is None: values, counts = np.unique(sensitive_attribute, return_counts=True) ideal_distribution = dict(zip(values, counts / counts.sum())) return { "balance": float(balance_metric(labels, sensitive_attribute)), "max_fairness_cost": float(max_fairness_cost(labels, sensitive_attribute, ideal_distribution)), }