error-parity


Nameerror-parity JSON
Version 0.3.11 PyPI version JSON
download
home_pagehttps://github.com/socialfoundations/error-parity
SummaryAchieve error-rate parity between protected groups for any predictor
upload_time2024-04-26 09:42:56
maintainerNone
docs_urlNone
authorAndreFCruz
requires_python>=3.8
licenseMIT
keywords ml optimization fairness error-parity equal-odds
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # error-parity    <!-- omit in toc -->

![Tests status](https://github.com/socialfoundations/error-parity/actions/workflows/python-tests.yml/badge.svg)
![PyPI status](https://github.com/socialfoundations/error-parity/actions/workflows/python-publish.yml/badge.svg)
![Documentation status](https://github.com/socialfoundations/error-parity/actions/workflows/python-docs.yml/badge.svg)
![PyPI version](https://badgen.net/pypi/v/error-parity)
![OSI license](https://badgen.net/pypi/license/error-parity)
![Python compatibility](https://badgen.net/pypi/python/error-parity)
<!-- ![PyPI version](https://img.shields.io/pypi/v/error-parity) -->
<!-- ![OSI license](https://img.shields.io/pypi/l/error-parity) -->
<!-- ![Compatible python versions](https://img.shields.io/pypi/pyversions/error-parity) -->

> Work presented as an _oral at ICLR 2024_, titled ["Unprocessing Seven Years of Algorithmic Fairness"](https://openreview.net/forum?id=jr03SfWsBS).


Fast postprocessing of any score-based predictor to meet fairness criteria.

The `error-parity` package can achieve strict or relaxed fairness constraint fulfillment, 
which can be useful to compare ML models at equal fairness levels.

Package documentation available [here](https://socialfoundations.github.io/error-parity/).

Contents:
- [Installing](#installing)
- [Getting started](#getting-started)
- [How it works](#how-it-works)
- [Fairness constraints](#fairness-constraints)
  - [Equalized odds relaxations](#equalized-odds-relaxations)
- [Citing](#citing)


## Installing

Install package from [PyPI](https://pypi.org/project/error-parity/):
```
pip install error-parity
```

Or, for development, you can clone the repo and install from local sources:
```
git clone https://github.com/socialfoundations/error-parity.git
pip install ./error-parity
```


## Getting started

> See detailed example notebooks under the [**examples folder**](./examples/) 
> and on the [**package documentation**](https://socialfoundations.github.io/error-parity/notebooks.html).

```py
from error_parity import RelaxedThresholdOptimizer

# Given any trained model that outputs real-valued scores
fair_clf = RelaxedThresholdOptimizer(
    predictor=lambda X: model.predict_proba(X)[:, -1],   # for sklearn API
    # predictor=model,            # use this for a callable model
    constraint="equalized_odds",  # other constraints are available
    tolerance=0.05,               # fairness constraint tolerance
)

# Fit the fairness adjustment on some data
# This will find the optimal _fair classifier_
fair_clf.fit(X=X, y=y, group=group)

# Now you can use `fair_clf` as any other classifier
# You have to provide group information to compute fair predictions
y_pred_test = fair_clf(X=X_test, group=group_test)
```


## How it works

Given a callable score-based predictor (i.e., `y_pred = predictor(X)`), and some `(X, Y, S)` data to fit, `RelaxedThresholdOptimizer` will:
1. Compute group-specific ROC curves and their convex hulls;
2. Compute the $r$-relaxed optimal solution for the chosen fairness criterion (using [cvxpy](https://www.cvxpy.org));
3. Find the set of group-specific binary classifiers that match the optimal solution found.
    - each group-specific classifier is made up of (possibly randomized) group-specific thresholds over the given predictor;
    - if a group's ROC point is in the interior of its ROC curve, partial randomization of its predictions may be necessary.


## Fairness constraints

You can choose specific fairness constraints via the `constraint` key-word argument to
the `RelaxedThresholdOptimizer` constructor.
The equation under each constraint details how it is evaluated, where $r$ is the
relaxation (or tolerance) and $\mathcal{S}$ is the set of sensitive groups.

Currently implemented fairness constraints:
- [x] equalized odds (Hardt et al., 2016) **[default]**;
  - i.e., equal group-specific TPR and FPR;
  - use `constraint="equalized_odds"`;
  - $\max_{a, b \in \mathcal{S}} \max_{y \in \{0, 1\}} \left( \mathbb{P}[\hat{Y}=1 | S=a, Y=y] - \mathbb{P}[\hat{Y}=1 | S=b, Y=y] \right) \leq r$
  - [other relaxations available](#equalized-odds-relaxations) by changing the `l_p_norm` parameter;
- [x] equal opportunity;
  - i.e., equal group-specific TPR;
  - use `constraint="true_positive_rate_parity"`;
  - $\max_{a, b \in \mathcal{S}} \left( \mathbb{P}[\hat{Y}=1 | S=a, Y=1] - \mathbb{P}[\hat{Y}=1 | S=b, Y=1] \right) \leq r$
- [x] predictive equality;
  - i.e., equal group-specific FPR;
  - use `constraint="false_positive_rate_parity"`;
  - $\max_{a, b \in \mathcal{S}} \left( \mathbb{P}[\hat{Y}=1 | S=a, Y=0] - \mathbb{P}[\hat{Y}=1 | S=b, Y=0] \right) \leq r$
- [x] demographic parity;
  - i.e., equal group-specific predicted prevalence;
  - use `constraint="demographic_parity"`;
  - $\max_{a, b \in \mathcal{S}} \left( \mathbb{P}[\hat{Y}=1 | S=a] - \mathbb{P}[\hat{Y}=1 | S=b] \right) \leq r$

> We welcome community contributions for [cvxpy](https://www.cvxpy.org) implementations of other fairness constraints.

### Equalized odds relaxations

When using `constraint="equalized_odds"`, different relaxations can be chosen by
altering the `l_p_norm` parameter (which dictates how to compute the distance 
between group-specific ROC points).

A few useful values:
- `l_p_norm=np.inf` **[default]** evaluates equalized-odds as the maximum
between group-wise TPR and FPR differences (as shown above);
- `l_p_norm=1` evaluates equalized-odds as the sum of absolute difference in group-wise TPR and FPR;
  - corresponds to *twice* the "average absolute odds" metric;
  - accordingly, use twice the `tolerance` target to constrain the `average_abs_odds_difference`;

The actual equalized odds constraint implemented is:

$\max_{a, b \in \mathcal{S}} \left\lVert ROC_a - ROC_b \right\rVert_p \leq r,$ where $ROC_a$ is the ROC point of group $S=a$ and $ROC_b$ is the ROC point of group $S=b$.



## Citing

```
@inproceedings{
  cruz2024unprocessing,
  title={Unprocessing Seven Years of Algorithmic Fairness},
  author={Andr{\'e} Cruz and Moritz Hardt},
  booktitle={The Twelfth International Conference on Learning Representations},
  year={2024},
  url={https://openreview.net/forum?id=jr03SfWsBS}
}
```

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/socialfoundations/error-parity",
    "name": "error-parity",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.8",
    "maintainer_email": null,
    "keywords": "ml, optimization, fairness, error-parity, equal-odds",
    "author": "AndreFCruz",
    "author_email": null,
    "download_url": "https://files.pythonhosted.org/packages/d9/09/cc40f372a4f53872241e7db0216d6bac6daf715c7baa2a2e86b03b6b1bae/error_parity-0.3.11.tar.gz",
    "platform": null,
    "description": "# error-parity    <!-- omit in toc -->\n\n![Tests status](https://github.com/socialfoundations/error-parity/actions/workflows/python-tests.yml/badge.svg)\n![PyPI status](https://github.com/socialfoundations/error-parity/actions/workflows/python-publish.yml/badge.svg)\n![Documentation status](https://github.com/socialfoundations/error-parity/actions/workflows/python-docs.yml/badge.svg)\n![PyPI version](https://badgen.net/pypi/v/error-parity)\n![OSI license](https://badgen.net/pypi/license/error-parity)\n![Python compatibility](https://badgen.net/pypi/python/error-parity)\n<!-- ![PyPI version](https://img.shields.io/pypi/v/error-parity) -->\n<!-- ![OSI license](https://img.shields.io/pypi/l/error-parity) -->\n<!-- ![Compatible python versions](https://img.shields.io/pypi/pyversions/error-parity) -->\n\n> Work presented as an _oral at ICLR 2024_, titled [\"Unprocessing Seven Years of Algorithmic Fairness\"](https://openreview.net/forum?id=jr03SfWsBS).\n\n\nFast postprocessing of any score-based predictor to meet fairness criteria.\n\nThe `error-parity` package can achieve strict or relaxed fairness constraint fulfillment, \nwhich can be useful to compare ML models at equal fairness levels.\n\nPackage documentation available [here](https://socialfoundations.github.io/error-parity/).\n\nContents:\n- [Installing](#installing)\n- [Getting started](#getting-started)\n- [How it works](#how-it-works)\n- [Fairness constraints](#fairness-constraints)\n  - [Equalized odds relaxations](#equalized-odds-relaxations)\n- [Citing](#citing)\n\n\n## Installing\n\nInstall package from [PyPI](https://pypi.org/project/error-parity/):\n```\npip install error-parity\n```\n\nOr, for development, you can clone the repo and install from local sources:\n```\ngit clone https://github.com/socialfoundations/error-parity.git\npip install ./error-parity\n```\n\n\n## Getting started\n\n> See detailed example notebooks under the [**examples folder**](./examples/) \n> and on the [**package documentation**](https://socialfoundations.github.io/error-parity/notebooks.html).\n\n```py\nfrom error_parity import RelaxedThresholdOptimizer\n\n# Given any trained model that outputs real-valued scores\nfair_clf = RelaxedThresholdOptimizer(\n    predictor=lambda X: model.predict_proba(X)[:, -1],   # for sklearn API\n    # predictor=model,            # use this for a callable model\n    constraint=\"equalized_odds\",  # other constraints are available\n    tolerance=0.05,               # fairness constraint tolerance\n)\n\n# Fit the fairness adjustment on some data\n# This will find the optimal _fair classifier_\nfair_clf.fit(X=X, y=y, group=group)\n\n# Now you can use `fair_clf` as any other classifier\n# You have to provide group information to compute fair predictions\ny_pred_test = fair_clf(X=X_test, group=group_test)\n```\n\n\n## How it works\n\nGiven a callable score-based predictor (i.e., `y_pred = predictor(X)`), and some `(X, Y, S)` data to fit, `RelaxedThresholdOptimizer` will:\n1. Compute group-specific ROC curves and their convex hulls;\n2. Compute the $r$-relaxed optimal solution for the chosen fairness criterion (using [cvxpy](https://www.cvxpy.org));\n3. Find the set of group-specific binary classifiers that match the optimal solution found.\n    - each group-specific classifier is made up of (possibly randomized) group-specific thresholds over the given predictor;\n    - if a group's ROC point is in the interior of its ROC curve, partial randomization of its predictions may be necessary.\n\n\n## Fairness constraints\n\nYou can choose specific fairness constraints via the `constraint` key-word argument to\nthe `RelaxedThresholdOptimizer` constructor.\nThe equation under each constraint details how it is evaluated, where $r$ is the\nrelaxation (or tolerance) and $\\mathcal{S}$ is the set of sensitive groups.\n\nCurrently implemented fairness constraints:\n- [x] equalized odds (Hardt et al., 2016) **[default]**;\n  - i.e., equal group-specific TPR and FPR;\n  - use `constraint=\"equalized_odds\"`;\n  - $\\max_{a, b \\in \\mathcal{S}} \\max_{y \\in \\{0, 1\\}} \\left( \\mathbb{P}[\\hat{Y}=1 | S=a, Y=y] - \\mathbb{P}[\\hat{Y}=1 | S=b, Y=y] \\right) \\leq r$\n  - [other relaxations available](#equalized-odds-relaxations) by changing the `l_p_norm` parameter;\n- [x] equal opportunity;\n  - i.e., equal group-specific TPR;\n  - use `constraint=\"true_positive_rate_parity\"`;\n  - $\\max_{a, b \\in \\mathcal{S}} \\left( \\mathbb{P}[\\hat{Y}=1 | S=a, Y=1] - \\mathbb{P}[\\hat{Y}=1 | S=b, Y=1] \\right) \\leq r$\n- [x] predictive equality;\n  - i.e., equal group-specific FPR;\n  - use `constraint=\"false_positive_rate_parity\"`;\n  - $\\max_{a, b \\in \\mathcal{S}} \\left( \\mathbb{P}[\\hat{Y}=1 | S=a, Y=0] - \\mathbb{P}[\\hat{Y}=1 | S=b, Y=0] \\right) \\leq r$\n- [x] demographic parity;\n  - i.e., equal group-specific predicted prevalence;\n  - use `constraint=\"demographic_parity\"`;\n  - $\\max_{a, b \\in \\mathcal{S}} \\left( \\mathbb{P}[\\hat{Y}=1 | S=a] - \\mathbb{P}[\\hat{Y}=1 | S=b] \\right) \\leq r$\n\n> We welcome community contributions for [cvxpy](https://www.cvxpy.org) implementations of other fairness constraints.\n\n### Equalized odds relaxations\n\nWhen using `constraint=\"equalized_odds\"`, different relaxations can be chosen by\naltering the `l_p_norm` parameter (which dictates how to compute the distance \nbetween group-specific ROC points).\n\nA few useful values:\n- `l_p_norm=np.inf` **[default]** evaluates equalized-odds as the maximum\nbetween group-wise TPR and FPR differences (as shown above);\n- `l_p_norm=1` evaluates equalized-odds as the sum of absolute difference in group-wise TPR and FPR;\n  - corresponds to *twice* the \"average absolute odds\" metric;\n  - accordingly, use twice the `tolerance` target to constrain the `average_abs_odds_difference`;\n\nThe actual equalized odds constraint implemented is:\n\n$\\max_{a, b \\in \\mathcal{S}} \\left\\lVert ROC_a - ROC_b \\right\\rVert_p \\leq r,$ where $ROC_a$ is the ROC point of group $S=a$ and $ROC_b$ is the ROC point of group $S=b$.\n\n\n\n## Citing\n\n```\n@inproceedings{\n  cruz2024unprocessing,\n  title={Unprocessing Seven Years of Algorithmic Fairness},\n  author={Andr{\\'e} Cruz and Moritz Hardt},\n  booktitle={The Twelfth International Conference on Learning Representations},\n  year={2024},\n  url={https://openreview.net/forum?id=jr03SfWsBS}\n}\n```\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "Achieve error-rate parity between protected groups for any predictor",
    "version": "0.3.11",
    "project_urls": {
        "Homepage": "https://github.com/socialfoundations/error-parity"
    },
    "split_keywords": [
        "ml",
        " optimization",
        " fairness",
        " error-parity",
        " equal-odds"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "bee565b9cec0ca880ef9565e07d0f423b65551838891b0b86b11072b94a36e3c",
                "md5": "8aaa1996bdc530de994f3f5eaa23ca78",
                "sha256": "efe0d9366bd8afa30584e9c30f78aef21be79b1669080f68ebcce0fdf8851cf6"
            },
            "downloads": -1,
            "filename": "error_parity-0.3.11-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "8aaa1996bdc530de994f3f5eaa23ca78",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.8",
            "size": 44212,
            "upload_time": "2024-04-26T09:42:54",
            "upload_time_iso_8601": "2024-04-26T09:42:54.475574Z",
            "url": "https://files.pythonhosted.org/packages/be/e5/65b9cec0ca880ef9565e07d0f423b65551838891b0b86b11072b94a36e3c/error_parity-0.3.11-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "d909cc40f372a4f53872241e7db0216d6bac6daf715c7baa2a2e86b03b6b1bae",
                "md5": "bc435ba28069ae1df51197ea48fb4e1a",
                "sha256": "e105d4196c8ef4c028fea0d77cdccf8bd066d43c69ef11808a2164ff7c525704"
            },
            "downloads": -1,
            "filename": "error_parity-0.3.11.tar.gz",
            "has_sig": false,
            "md5_digest": "bc435ba28069ae1df51197ea48fb4e1a",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.8",
            "size": 40912,
            "upload_time": "2024-04-26T09:42:56",
            "upload_time_iso_8601": "2024-04-26T09:42:56.177439Z",
            "url": "https://files.pythonhosted.org/packages/d9/09/cc40f372a4f53872241e7db0216d6bac6daf715c7baa2a2e86b03b6b1bae/error_parity-0.3.11.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-04-26 09:42:56",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "socialfoundations",
    "github_project": "error-parity",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "error-parity"
}
        
Elapsed time: 0.49458s