Skip to main content

ci PyPI version fury.io PyPI license PRs Welcome Downloads

Jurity: Fairness & Evaluation Library

Jurity (LION'23, ICMLA'21) is a research library that provides fairness metrics, recommender system evaluations, classification metrics and bias mitigation techniques. The library adheres to PEP-8 standards and is tested heavily.

Jurity is developed by the Artificial Intelligence Center of Excellence at Fidelity Investments. Documentation is available at fidelity.github.io/jurity.

Fairness Metrics

Binary Bias Mitigation Techniques

Recommenders Metrics

Classification Metrics

Quick Start: Fairness Evaluation

# Import binary and multi-class fairness metrics
from jurity.fairness import BinaryFairnessMetrics, MultiClassFairnessMetrics

# Data
binary_predictions = [1, 1, 0, 1, 0, 0]
multi_class_predictions = ["a", "b", "c", "b", "a", "a"]
multi_class_multi_label_predictions = [["a", "b"], ["b", "c"], ["b"], ["a", "b"], ["c", "a"], ["c"]]
memberships = [0, 0, 0, 1, 1, 1]
classes = ["a", "b", "c"]

# Metrics (see also other available metrics)
metric = BinaryFairnessMetrics.StatisticalParity()
multi_metric = MultiClassFairnessMetrics.StatisticalParity(classes)

# Scores
print("Metric:", metric.description)
print("Lower Bound: ", metric.lower_bound)
print("Upper Bound: ", metric.upper_bound)
print("Ideal Value: ", metric.ideal_value)
print("Binary Fairness score: ", metric.get_score(binary_predictions, memberships))
print("Multi-class Fairness scores: ", multi_metric.get_scores(multi_class_predictions, memberships))
print("Multi-class multi-label Fairness scores: ", multi_metric.get_scores(multi_class_multi_label_predictions, memberships))

Quick Start: Probabilistic Fairness Evaluation

What if we do not know the protected membership attribute of each sample? This is a practical scenario that we refer to as probabilistic fairness evaluation.

At a high-level, instead of strict 0/1 deterministic membership at individual level, consider the probability of membership to protected classes for each sample.

An easy baseline is to convert these probabilities back to the deterministic setting by taking the maximum likelihood as the protected membership. This is problematic as the goal is not to predict membership but to evaluate fairness.

Taking this a step further, while we do not have membership information at the individual level, consider access to surrogate membership at group level. We can then infer the fairness metrics directly.

Jurity offers both options to address the case where membership data is missing. We provide an in-depth study and formal treatment in Surrogate Membership for Inferred Metrics in Fairness Evaluation (LION 2023).

from jurity.fairness import BinaryFairnessMetrics

# Instead of 0/1 deterministic membership at individual level 
# consider likelihoods of membership to protected classes for each sample 
binary_predictions = [1, 1, 0, 1]
memberships = [[0.2, 0.8], [0.4, 0.6], [0.2, 0.8], [0.9, 0.1]]

# Metric
metric = BinaryFairnessMetrics.StatisticalParity()
print("Binary Fairness score: ", metric.get_score(binary_predictions, memberships))

# Surrogate membership: consider access to surrogate membership at the group level. 
surrogates = [0, 2, 0, 1]
print("Binary Fairness score: ", metric.get_score(binary_predictions, memberships, surrogates))

Quick Start: Bias Mitigation

# Import binary fairness and binary bias mitigation
from jurity.mitigation import BinaryMitigation
from jurity.fairness import BinaryFairnessMetrics

# Data
labels = [1, 1, 0, 1, 0, 0, 1, 0]
predictions = [0, 0, 0, 1, 1, 1, 1, 0]
likelihoods = [0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.1]
is_member = [0, 0, 0, 0, 1, 1, 1, 1]

# Bias Mitigation
mitigation = BinaryMitigation.EqualizedOdds()

# Training: Learn mixing rates from the labeled data
mitigation.fit(labels, predictions, likelihoods, is_member)

# Testing: Mitigate bias in predictions
fair_predictions, fair_likelihoods = mitigation.transform(predictions, likelihoods, is_member)

# Scores: Fairness before and after
print("Fairness Metrics Before:", BinaryFairnessMetrics().get_all_scores(labels, predictions, is_member), '\n'+30*'-')
print("Fairness Metrics After:", BinaryFairnessMetrics().get_all_scores(labels, fair_predictions, is_member))

Quick Start: Recommenders Evaluation

# Import recommenders metrics
from jurity.recommenders import BinaryRecoMetrics, RankingRecoMetrics, DiversityRecoMetrics
import pandas as pd

# Data
actual = pd.DataFrame({"user_id": [1, 2, 3, 4], "item_id": [1, 2, 0, 3], "clicks": [0, 1, 0, 0]})
predicted = pd.DataFrame({"user_id": [1, 2, 3, 4], "item_id": [1, 2, 2, 3], "clicks": [0.8, 0.7, 0.8, 0.7]})
item_features = pd.DataFrame({"item_id": [0, 1, 2, 3], "feature1": [1, 2, 2, 1], "feature2": [0.8, 0.7, 0.8, 0.7]})

# Metrics
auc = BinaryRecoMetrics.AUC(click_column="clicks")
ctr = BinaryRecoMetrics.CTR(click_column="clicks")
dr = BinaryRecoMetrics.CTR(click_column="clicks", estimation='dr')
ips = BinaryRecoMetrics.CTR(click_column="clicks", estimation='ips')
map_k = RankingRecoMetrics.MAP(click_column="clicks", k=2)
ncdg_k = RankingRecoMetrics.NDCG(click_column="clicks", k=3)
precision_k = RankingRecoMetrics.Precision(click_column="clicks", k=2)
recall_k = RankingRecoMetrics.Recall(click_column="clicks", k=2)
interlist_diversity_k = DiversityRecoMetrics.InterListDiversity(click_column="clicks", k=2)
intralist_diversity_k = DiversityRecoMetrics.IntraListDiversity(item_features, click_column="clicks", k=2)

# Scores
print("AUC:", auc.get_score(actual, predicted))
print("CTR:", ctr.get_score(actual, predicted))
print("Doubly Robust:", dr.get_score(actual, predicted))
print("IPS:", ips.get_score(actual, predicted))
print("MAP@K:", map_k.get_score(actual, predicted))
print("NCDG:", ncdg_k.get_score(actual, predicted))
print("Precision@K:", precision_k.get_score(actual, predicted))
print("Recall@K:", recall_k.get_score(actual, predicted))
print("Inter-List Diversity@K:", interlist_diversity_k.get_score(actual, predicted))
print("Intra-List Diversity@K:", intralist_diversity_k.get_score(actual, predicted))

Quick Start: Classification Evaluation

# Import classification metrics
from jurity.classification import BinaryClassificationMetrics

# Data
labels = [1, 1, 0, 1, 0, 0, 1, 0]
predictions = [0, 0, 0, 1, 1, 1, 1, 0]

# Available: Accuracy, F1, Precision, Recall, and AUC
f1_score = BinaryClassificationMetrics.F1()

print('F1 score is', f1_score.get_score(predictions, labels))

Installation

Jurity requires Python 3.8+ and can be installed from PyPI using pip install jurity or by building from source as shown in installation instructions.

Citation

If you use Jurity in a publication, please cite it as:

    @article{DBLP:conf/lion/Melinda23,
      author    = {Melinda Thielbar, Serdar Kadioglu, Chenhui Zhang, Rick Pack, and Lukas Dannull},
      title     = {Surrogate Membership for Inferred Metrics in Fairness Evaluation},
      booktitle = {The 17th Learning and Intelligent Optimization Conference (LION)},
      publisher = {{LION}},
      year      = {2023}
    }

    @inproceedings{DBLP:conf/icmla/MichalskyK21,
    author       = {Filip Michalsk{\'{y}} and Serdar Kadioglu},
    title        = {Surrogate Ground Truth Generation to Enhance Binary Fairness Evaluation in Uplift Modeling},
    booktitle    = {20th {IEEE} International Conference on Machine Learning and Applications, 
    {ICMLA} 2021, Pasadena, CA, USA, December 13-16, 2021},
    pages        = {1654--1659},
    publisher    = {{IEEE}},
    year         = {2021},
    url          = {https://doi.org/10.1109/ICMLA52953.2021.00264},
    doi          = {10.1109/ICMLA52953.2021.00264},
}

Support

Please submit bug reports and feature requests as Issues.

License

Jurity is licensed under the Apache License 2.0.

Metadata

Release files for jurity 2.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for jurity 2.1.0
File Size Uploaded Provenance
jurity-2.1.0.tar.gz 83.8 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for jurity 2.1.0
File Interpreter ABI Platform
jurity-2.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 169.2 kB

Release files / jurity-2.1.0.tar.gz

Download URL jurity-2.1.0.tar.gz
Size 83.8 kB
Tags Source
SHA-256 checksum
How to use checksums
2153246fe87d4cfe069f5192271f17d16191aa7ac2b49157d8936cb7107a0549
BLAKE2b-256 checksum
How to use checksums
028509caccd02320892a6ce026d181302217badf8c84109b094be5d38c1572f5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/5.1.1 CPython/3.12.5

Release files / jurity-2.1.0-py3-none-any.whl

Download URL jurity-2.1.0-py3-none-any.whl
Size 85.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
005df9ad5fc3a9d46d20a5d5267a6f8c07244bcf86376ef7f57609e17c384a77
BLAKE2b-256 checksum
How to use checksums
978497791f0e10bac21c4032d1d09ba727eed9ae57a75849d67b5aea9a7a45c8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/5.1.1 CPython/3.12.5

Security for jurity 2.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page