Skip to content
Permalink
master
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
 
 
Cannot retrieve contributors at this time
executable file 123 lines (99 sloc) 4.8 KB
import numpy as np
from aif360.algorithms import Transformer
from aif360.metrics import utils
class Reweighing(Transformer):
"""Reweighing is a preprocessing technique that Weights the examples in each
(group, label) combination differently to ensure fairness before
classification [4]_.
References:
.. [4] F. Kamiran and T. Calders, "Data Preprocessing Techniques for
Classification without Discrimination," Knowledge and Information
Systems, 2012.
"""
def __init__(self, unprivileged_groups, privileged_groups):
"""
Args:
unprivileged_groups (list(dict)): Representation for unprivileged
group.
privileged_groups (list(dict)): Representation for privileged group.
"""
super(Reweighing, self).__init__(
unprivileged_groups=unprivileged_groups,
privileged_groups=privileged_groups)
self.unprivileged_groups = unprivileged_groups
self.privileged_groups = privileged_groups
self.w_p_fav = 1.
self.w_p_unfav = 1.
self.w_up_fav = 1.
self.w_up_unfav = 1.
def fit(self, dataset):
"""Compute the weights for reweighing the dataset.
Args:
dataset (BinaryLabelDataset): Dataset containing true labels.
Returns:
Reweighing: Returns self.
"""
(priv_cond, unpriv_cond, fav_cond, unfav_cond,
cond_p_fav, cond_p_unfav, cond_up_fav, cond_up_unfav) =\
self._obtain_conditionings(dataset)
n = np.sum(dataset.instance_weights, dtype=np.float64)
n_p = np.sum(dataset.instance_weights[priv_cond], dtype=np.float64)
n_up = np.sum(dataset.instance_weights[unpriv_cond], dtype=np.float64)
n_fav = np.sum(dataset.instance_weights[fav_cond], dtype=np.float64)
n_unfav = np.sum(dataset.instance_weights[unfav_cond], dtype=np.float64)
n_p_fav = np.sum(dataset.instance_weights[cond_p_fav], dtype=np.float64)
n_p_unfav = np.sum(dataset.instance_weights[cond_p_unfav],
dtype=np.float64)
n_up_fav = np.sum(dataset.instance_weights[cond_up_fav],
dtype=np.float64)
n_up_unfav = np.sum(dataset.instance_weights[cond_up_unfav],
dtype=np.float64)
# reweighing weights
self.w_p_fav = n_fav*n_p / (n*n_p_fav)
self.w_p_unfav = n_unfav*n_p / (n*n_p_unfav)
self.w_up_fav = n_fav*n_up / (n*n_up_fav)
self.w_up_unfav = n_unfav*n_up / (n*n_up_unfav)
return self
def transform(self, dataset):
"""Transform the dataset to a new dataset based on the estimated
transformation.
Args:
dataset (BinaryLabelDataset): Dataset that needs to be transformed.
Returns:
dataset (BinaryLabelDataset): Dataset with transformed
instance_weights attribute.
"""
dataset_transformed = dataset.copy(deepcopy=True)
(_, _, _, _, cond_p_fav, cond_p_unfav, cond_up_fav, cond_up_unfav) =\
self._obtain_conditionings(dataset)
# apply reweighing
dataset_transformed.instance_weights[cond_p_fav] *= self.w_p_fav
dataset_transformed.instance_weights[cond_p_unfav] *= self.w_p_unfav
dataset_transformed.instance_weights[cond_up_fav] *= self.w_up_fav
dataset_transformed.instance_weights[cond_up_unfav] *= self.w_up_unfav
return dataset_transformed
##############################
#### Supporting functions ####
##############################
def _obtain_conditionings(self, dataset):
"""Obtain the necessary conditioning boolean vectors to compute
instance level weights.
"""
# conditioning
priv_cond = utils.compute_boolean_conditioning_vector(
dataset.protected_attributes,
dataset.protected_attribute_names,
condition=self.privileged_groups)
unpriv_cond = utils.compute_boolean_conditioning_vector(
dataset.protected_attributes,
dataset.protected_attribute_names,
condition=self.unprivileged_groups)
fav_cond = dataset.labels.ravel() == dataset.favorable_label
unfav_cond = dataset.labels.ravel() == dataset.unfavorable_label
# combination of label and privileged/unpriv. groups
cond_p_fav = np.logical_and(fav_cond, priv_cond)
cond_p_unfav = np.logical_and(unfav_cond, priv_cond)
cond_up_fav = np.logical_and(fav_cond, unpriv_cond)
cond_up_unfav = np.logical_and(unfav_cond, unpriv_cond)
return (priv_cond, unpriv_cond, fav_cond, unfav_cond,
cond_p_fav, cond_p_unfav, cond_up_fav, cond_up_unfav)