Skip to content

Commit

Permalink
rename build_x to use CamelCase to indicate constructors
Browse files Browse the repository at this point in the history
  • Loading branch information
ChrisMRuss committed Jun 19, 2024
1 parent 98b1896 commit 03ba45d
Show file tree
Hide file tree
Showing 17 changed files with 58 additions and 526 deletions.
478 changes: 15 additions & 463 deletions examples/building_datasets.ipynb

Large diffs are not rendered by default.

7 changes: 4 additions & 3 deletions examples/compas_autogluon.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -1156,7 +1156,8 @@
"source": [
"Now we will show how a family of fairness measures can be individually optimized. First, we consider the measures of Sagemaker Clarify. \n",
"\n",
"The following code plots a table showing the change in accuracy and the fairness measure on a held-out test set as we decrease the fairness measure to less than 0.025 (on validation) for all measures except for disparate impact which we raise to above 0.975.\n",
"The following code plots a table showing the change in accuracy and the fairness measure on a held-out test set.\n",
"We decrease each fairness measure to less than 0.025 (on validation) for all measures except for disparate impact which we raise to above 0.975.\n",
"We define a helper function for evaluation:"
]
},
Expand Down Expand Up @@ -1737,7 +1738,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"In contrast, even though the base classifiers have similar accuracy, when using inferred attributes (N.B. the base classifier is not directly trained to maximize accuracy, which is why it can have higher accuracy when it doesn't use race), we see a much greater drop in accuracy as fairness is enforced which is consistent with [Lipton et al.](https://arxiv.org/pdf/1711.07076.pdf)\n"
"In contrast, even though the base classifiers have similar accuracy, when using inferred attributes (N.B. the base classifier is not directly trained to maximize accuracy, which is why it can have higher accuracy when it doesn't use race), we see a much greater drop in accuracy as fairness is enforced. This is consistent with [Lipton et al.](https://arxiv.org/pdf/1711.07076.pdf)\n"
]
},
{
Expand Down Expand Up @@ -1881,7 +1882,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.13"
"version": "3.1.-1"
}
},
"nbformat": 4,
Expand Down
9 changes: 1 addition & 8 deletions examples/conditional_metrics.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -1178,13 +1178,6 @@
"source": [
"all_data.iloc[0]"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
Expand All @@ -1203,7 +1196,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.13"
"version": "3.8.18"
}
},
"nbformat": 4,
Expand Down
11 changes: 2 additions & 9 deletions examples/high-dim_fairlearn_comparision.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"\n",
"We use sex as the protected attribute.\n",
"\n",
"The initial dataset is balanced, and to induce unfairness in the downstream classifier, we drop half the datapoints that satisfy sex=1 and target_label=0.\n",
"The initial dataset is balanced, and to induce unfairness in the downstream classifier, we drop half the datapoints that satisfy sex=1 and target_label=0.\n",
"\n",
"Because the dataset is relatively high-dimensional (dims ~= 100) with around 1,000 training points, xgboost overfits perfectly obtaining zero error on the train set."
]
Expand Down Expand Up @@ -1125,7 +1125,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"To evaluate fairlearn, we write a helper function to evaluate performance and fairness on train or test, and concat the outputs together. "
"To evaluate fairlearn, we write a helper function to evaluate performance and fairness on train or test, and concatenate the outputs together. "
]
},
{
Expand Down Expand Up @@ -1432,13 +1432,6 @@
"out.columns = ['train', 'test']\n",
"out"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
Expand Down
4 changes: 2 additions & 2 deletions examples/levelling_up.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"metadata": {},
"source": [
"# Levelling Up\n",
"This code demonstrates new forms of fairness that 'level-up'. That is they improve measures such as recall rate or selection rates for disadvantaged groups. This is a change from standard measures of fairness that equalize harms across groups (and consequentially 'level down' and decrease rates for some groups, and harms them more than they were harmed by the original classifier).\n",
"This code demonstrates new forms of fairness that 'level-up'. That is they improve measures such as recall rate or selection rates for disadvantaged groups. This is a change from standard measures of fairness that equalize harms across groups (and consequentially 'level down' and decrease rates for some groups, and harms them more than they were harmed by the original classifier).\n",
"\n",
"More details are in the [paper](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=4331652).\n",
"\n",
Expand Down Expand Up @@ -1131,7 +1131,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.13"
"version": "3.1.-1"
},
"vscode": {
"interpreter": {
Expand Down
4 changes: 2 additions & 2 deletions examples/multi_group_fairlearn_comparision.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"A runtime comparision with FairLearn reductions on multi-group adult data.\n",
"A runtime comparison with FairLearn reductions on multi-group adult data.\n",
"\n",
"There is relatively little to see here, as both FairLearn and OxonFair naturally support multiple groups. \n",
"\n",
Expand Down Expand Up @@ -541,7 +541,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.13"
"version": "3.8.18"
}
},
"nbformat": 4,
Expand Down
9 changes: 1 addition & 8 deletions examples/pytorch_minimal_demo.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -588,7 +588,7 @@
"outputs": [],
"source": [
"# to evaluate how it's working on the test set, we'll create a new dataset holder\n",
"test_network = oxonfair.build_deep_dict(test['target'], test_output, test['groups'])"
"test_network = oxonfair.DeepDataDict(test['target'], test_output, test['groups'])"
]
},
{
Expand Down Expand Up @@ -1151,13 +1151,6 @@
"fpred_thresh.plot_frontier(prefix='Single threshold ', new_plot=False, show_original=False)\n",
"fpred.plot_frontier(prefix='Two heads ', new_plot=False)\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
Expand Down
10 changes: 5 additions & 5 deletions examples/quickstart_DeepFairPredictor_computer_vision.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@
"\n",
"We demonstrate how different notions of fairness and performance can be measured and enforced with our toolkit. \n",
"\n",
"We recommend you first consider the quickstart_xgboost.ipynb notebook for an introduction to the toolkit's functionality. \n",
"We recommend you first try [quickstart_xgboost.ipynb](quickstart_xgboost.ipynb) notebook for an introduction to the toolkit's functionality. \n",
"\n",
"We first show an example on [CelebA](https://mmlab.ie.cuhk.edu.hk/projects/CelebA.html). The protected groups are given by the labels for the attribute `Male` . You can specify which target attribute (e.g., Wearing_Earrings) you want to enforce fairness for. \n",
"We first show an example on [CelebA](https://mmlab.ie.cuhk.edu.hk/projects/CelebA.html). The protected groups are given by the labels for the attribute `Male`. You can specify which target attribute (e.g., Wearing_Earrings) you want to enforce fairness for. \n",
"You can also specify which fairness and performance metrics to measure.\n",
"\n",
"At the end of the notebook, we look at an example using medical data from [Fitzpatrick-17k](https://arxiv.org/pdf/2104.09957).\n",
Expand All @@ -22,9 +22,9 @@
"1. We need the validation and test labels for the protected and target attributes.\n",
"2. We also require the model outputs. These will typically be logits for the target attribute and probabilities for the inferred protected attribute. It is also possible to use the true group labels (non-inferred). This data used in this notebook demonstration is fetched from an anonymous repository.\n",
"\n",
"We use DeepFairPredictor (reccomended), which is optimized for deep learning classifiers. \n",
"We use DeepFairPredictor (recommended), which is optimized for deep learning classifiers. \n",
"\n",
"We also reccomend checking out this [paper](https://arxiv.org/pdf/2203.04913) for theoretically explanations into why the majority of fairness methods designed for low capacity models should not be used in settings involving high-capacity models and this [paper](https://proceedings.neurips.cc/paper_files/paper/2022/file/698c05933e5f7fde98e567a669d2c752-Paper-Conference.pdf) for more details on the two/multi headed approach for a post-processing approach to enforce fairness with validation data when working with deep learning models. \n"
"For more details about the theory, check out this [paper](https://arxiv.org/pdf/2203.04913) for theoretically explanations into why the majority of fairness methods designed for low capacity models should not be used in settings involving high-capacity models and this [paper](https://proceedings.neurips.cc/paper_files/paper/2022/file/698c05933e5f7fde98e567a669d2c752-Paper-Conference.pdf) for more details on the two/multi- headed approach for a post-processing approach to enforce fairness with validation data when working with deep learning models. \n"
]
},
{
Expand Down Expand Up @@ -1270,7 +1270,7 @@
"source": [
"### Fitzpatrick-17k Example\n",
"\n",
"Next we demonstrate how our toolkit could be used with medical data. The implementation details will be similar but practitioners may want to think carefully about how they measure and enforce fairness in high stakes domains. We reccomend a harms first approach emphasising metrics such as per group recall or selection rate. \n",
"Next we demonstrate how our toolkit could be used with medical data. The implementation details will be similar, but practitioners may want to think carefully about how they measure and enforce fairness in high stakes domains. We recommend a harms-first approach emphasizing metrics such as per group recall or selection rate. \n",
"\n",
"Here the target label classifies if a skin condition is malignant or benign. The protected label indicates race. Data is preprocessed following the description and code of [Zong et al.](https://arxiv.org/pdf/2210.01725) "
]
Expand Down
2 changes: 1 addition & 1 deletion examples/quickstart_autogluon.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -4112,7 +4112,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.13"
"version": "3.1.-1"
},
"vscode": {
"interpreter": {
Expand Down
4 changes: 2 additions & 2 deletions examples/quickstart_xgboost.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"# FairPredictor XGBoost Examples\n",
"This file contains demo code for an extended version of the example in Readme.md (additionally handling more fairness over multiple groups), and enforcing a range of fairness definition on COMPAS.\n",
"\n",
"It is a modified version of [quickstart_autogluon.ipynb](quickstart_autogluon.ipynb)\n",
"It is a modified version of [quickstart_autogluon.ipynb](./quickstart_autogluon.ipynb)\n",
"\n",
"FairPredictor is a postprocessing approach for enforcing fairness, with support for a wide range of performance metrics and fairness criteria, and support for inferred attributes, i.e., it does not require access to protected attributes at test time. \n",
"Under the hood, FairPredictor works by adjusting the decision boundary for each group individually. Where groups are not available, it makes use of inferred group membership to adjust decision boundaries.\n",
Expand Down Expand Up @@ -2525,7 +2525,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.13"
"version": "3.1.-1"
}
},
"nbformat": 4,
Expand Down
4 changes: 2 additions & 2 deletions sklearn.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ Step 1 requires considerably more preamble when using sklearn.
### We pass dictionaries that represent the entire dataset to get round this.
### They contain 'target' 'data', 'groups' (optional), and 'factor' (optional)

val_dict = fair.build_data_dict(val_target,val_data)
test_dict = fair.build_data_dict(test_target, test_data)
val_dict = fair.DataDict(val_target,val_data)
test_dict = fair.DataDict(test_target, test_data)

## Train a classifier

Expand Down
8 changes: 4 additions & 4 deletions src/oxonfair/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from .learners import (FairPredictor, inferred_attribute_builder, single_threshold, build_data_dict,
DeepFairPredictor, build_deep_dict)
from .learners import (FairPredictor, inferred_attribute_builder, single_threshold, DataDict,
DeepFairPredictor, DeepDataDict)
from .utils import performance, group_metrics, conditional_group_metrics, dataset_loader

__all__ = (FairPredictor, inferred_attribute_builder, single_threshold, build_data_dict,
performance, group_metrics, conditional_group_metrics, DeepFairPredictor, build_deep_dict, dataset_loader)
__all__ = (FairPredictor, inferred_attribute_builder, single_threshold, DataDict,
performance, group_metrics, conditional_group_metrics, DeepFairPredictor, DeepDataDict, dataset_loader)
8 changes: 4 additions & 4 deletions src/oxonfair/learners/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from .fair import (FairPredictor, inferred_attribute_builder, single_threshold, build_data_dict,
DeepFairPredictor, build_deep_dict)
from .fair import (FairPredictor, inferred_attribute_builder, single_threshold, DataDict,
DeepFairPredictor, DeepDataDict)

__all__ = (FairPredictor, inferred_attribute_builder, single_threshold, build_data_dict, DeepFairPredictor,
build_deep_dict)
__all__ = (FairPredictor, inferred_attribute_builder, single_threshold, DataDict, DeepFairPredictor,
DeepDataDict)
10 changes: 5 additions & 5 deletions src/oxonfair/learners/fair.py
Original file line number Diff line number Diff line change
Expand Up @@ -956,7 +956,7 @@ def single_threshold(x) -> np.ndarray:
return np.ones((x.shape[0], 1))


def build_data_dict(target, data, groups=None, conditioning_factor=None) -> dict:
def DataDict(target, data, groups=None, conditioning_factor=None) -> dict:
"Helper function that builds dictionaries for use with sklearn classifiers"
assert target.shape[0] == data.shape[0]
assert data.ndim == 2
Expand All @@ -974,8 +974,8 @@ def build_data_dict(target, data, groups=None, conditioning_factor=None) -> dict
return out


def build_deep_dict(target, score, groups, groups_inferred=None, *,
conditioning_factor=None) -> dict:
def DeepDataDict(target, score, groups, groups_inferred=None, *,
conditioning_factor=None) -> dict:
"""Wrapper around build_data_dict for deeplearning with inferred attributes.
It transforms the input data into a dict, and creates helper functions so
fairpredictor treats them appropriately.
Expand All @@ -998,7 +998,7 @@ def build_deep_dict(target, score, groups, groups_inferred=None, *,
else:
# assert score.shape[1] > 1, 'When groups_inferred is None, score must also contain inferred group information'
data = score
return build_data_dict(target, data, groups, conditioning_factor=conditioning_factor)
return DataDict(target, data, groups, conditioning_factor=conditioning_factor)


def DeepFairPredictor(target, score, groups, groups_inferred=None,
Expand All @@ -1020,7 +1020,7 @@ def DeepFairPredictor(target, score, groups, groups_inferred=None,
with the output of the fast pathway). By default 'hybrid' unless use_actual_groups is true, in which
case True
"""
val_data = build_deep_dict(target, score, groups, groups_inferred, conditioning_factor=conditioning_factor)
val_data = DeepDataDict(target, score, groups, groups_inferred, conditioning_factor=conditioning_factor)

def square_align(array):
return np.stack((array[:, 1], 1-array[:, 1]), 1)
Expand Down
8 changes: 4 additions & 4 deletions src/oxonfair/utils/dataset_loader.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import numpy as np
import pandas as pd
from oxonfair import build_data_dict
from oxonfair import DataDict
from sklearn.preprocessing import LabelEncoder


Expand Down Expand Up @@ -126,9 +126,9 @@ def __call__(self, groups=None, train_proportion=0.5, test_proportion=0.25, *,
test_y = target[part == 1]
test_groups = groups.iloc[part == 1]

train_dict = build_data_dict(train_y, train, train_groups)
val_dict = build_data_dict(val_y, val, val_groups)
test_dict = build_data_dict(test_y, test, test_groups)
train_dict = DataDict(train_y, train, train_groups)
val_dict = DataDict(val_y, val, val_groups)
test_dict = DataDict(test_y, test, test_groups)
return train_dict, val_dict, test_dict


Expand Down
4 changes: 2 additions & 2 deletions tests/unittests/test_additional_constraints.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@
val_dict = {"data": val, "target": val_y}
test_dict = {"data": test, "target": test_y}

val_dict_g = fair.build_data_dict(val_y, val, val['sex_ Female'])
test_dict_g = fair.build_data_dict(test_y, test, test['sex_ Female'])
val_dict_g = fair.DataDict(val_y, val, val['sex_ Female'])
test_dict_g = fair.DataDict(test_y, test, test['sex_ Female'])


def test_slack_constraints(use_fast=True):
Expand Down
4 changes: 2 additions & 2 deletions tests/unittests/test_scipy.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@
val_dict = {"data": val, "target": val_y}
test_dict = {"data": test, "target": test_y}

val_dict_g = fair.build_data_dict(val_y, val, val['sex_ Female'])
test_dict_g = fair.build_data_dict(test_y, test, test['sex_ Female'])
val_dict_g = fair.DataDict(val_y, val, val['sex_ Female'])
test_dict_g = fair.DataDict(test_y, test, test['sex_ Female'])


def test_base_functionality(val_dict=val_dict, test_dict=test_dict):
Expand Down

0 comments on commit 03ba45d

Please sign in to comment.