Spaces:
Runtime error
Runtime error
| 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) | |