pyhealth.metrics.fairness#
fairness_metrics_fn is also importable directly from the top-level
pyhealth.metrics package (from pyhealth.metrics import
fairness_metrics_fn), not just from this submodule.
- pyhealth.metrics.fairness.fairness_metrics_fn(y_true, y_prob, sensitive_attributes, favorable_outcome=1, metrics=None, threshold=0.5)[source]#
Computes metrics for binary classification.
User can specify which metrics to compute by passing a list of metric names. The accepted metric names are:
disparate_impact:
statistical_parity_difference:
If no metrics are disparate_impact, and statistical_parity_difference are computed by default.
- Parameters:
y_true (
ndarray) – True target values of shape (n_samples,).y_prob (
ndarray) – Predicted probabilities of shape (n_samples,).sensitive_attributes (
ndarray) – Sensitive attributes of shape (n_samples,) where 1 is the protected group and 0 is the unprotected group.favorable_outcome (
int) – Label value which is considered favorable (i.e. “positive”).metrics (
Optional[List[str]]) – List of metrics to compute. Default is [“disparate_impact”, “statistical_parity_difference”].threshold (
float) – Threshold for binary classification. Default is 0.5.
- Return type:
- Returns:
- Dictionary of metrics whose keys are the metric names and values are
the metric values.
Both disparate_impact and statistical_parity_difference raise
ValueError if either the protected or unprotected group has zero
instances – the favorable-outcome rate is undefined for an empty group,
so this is always an error rather than a value (e.g. 0 or NaN) that could
silently poison a downstream average across folds/seeds.
- pyhealth.metrics.fairness_utils.disparate_impact(sensitive_attributes, y_pred, favorable_outcome=1, allow_zero_division=False, epsilon=1e-08)[source]#
Computes the disparate impact between the the protected and unprotected group.
disparate_impact = P(y_pred = favorable_outcome | P) / P(y_pred = favorable_outcome | U)
- Parameters:
sensitive_attributes (
ndarray) – Sensitive attributes of shape (n_samples,) where 1 is the protected group and 0 is the unprotected group.y_pred (
ndarray) – Predicted target values of shape (n_samples,).favorable_outcome (
int) – Label value which is considered favorable (i.e. “positive”).allow_zero_division – If True, use epsilon instead of 0 in the denominator if the denominator is 0. Otherwise, raise a ValueError.
- Return type:
- Returns:
The disparate impact between the protected and unprotected group.
- Raises:
ValueError – If either group has no instances at all (this is always an error, regardless of allow_zero_division – there is no meaningful epsilon substitute for a group we have zero information about), or if the unprotected group’s favorable-outcome rate is exactly 0 and allow_zero_division is False.
Examples
>>> import numpy as np >>> from pyhealth.metrics.fairness_utils import disparate_impact >>> sensitive_attributes = np.array([0, 0, 1, 1, 1]) >>> y_pred = np.array([1, 0, 1, 1, 0]) >>> disparate_impact(sensitive_attributes, y_pred) 1.3333333333333333
- pyhealth.metrics.fairness_utils.statistical_parity_difference(sensitive_attributes, y_pred, favorable_outcome=1)[source]#
Computes the statistical parity difference between the the protected and unprotected group.
statistical_parity_difference = P(y_pred = favorable_outcome | P) - P(y_pred = favorable_outcome | U) :type sensitive_attributes:
ndarray:param sensitive_attributes: Sensitive attributes of shape (n_samples,) where 1 is the protected group and 0 is the unprotected group. :type y_pred:ndarray:param y_pred: Predicted target values of shape (n_samples,). :type favorable_outcome:int:param favorable_outcome: Label value which is considered favorable (i.e. “positive”).- Return type:
- Returns:
The statistical parity difference between the protected and unprotected group.
- Raises:
ValueError – If either group has no instances at all. Unlike disparate_impact, a favorable-outcome rate of exactly 0 for a non-empty group is not an error here (it’s a legitimate value for a difference, e.g. 0 - 0.3 = -0.3).
Examples
>>> import numpy as np >>> from pyhealth.metrics.fairness_utils import statistical_parity_difference >>> sensitive_attributes = np.array([0, 0, 1, 1, 1]) >>> y_pred = np.array([1, 0, 1, 1, 0]) >>> statistical_parity_difference(sensitive_attributes, y_pred) 0.16666666666666663
- pyhealth.metrics.fairness_utils.sensitive_attributes_from_patient_ids(dataset, patient_ids, sensitive_attribute, protected_group)[source]#
Returns the desired sensitive attribute array from patient_ids.
- Parameters:
dataset (
BaseDataset) – Dataset object (must implementget_patient(patient_id)returning aPatientwith a"patients"-typed demographic event).sensitive_attribute (
str) – Sensitive attribute to extract.protected_group (
str) – Value of the protected group.
- Return type:
ndarray- Returns:
Sensitive attribute array of shape (n_samples,).
Examples
>>> import polars as pl >>> from datetime import datetime >>> from pyhealth.data import Patient >>> event_df = pl.DataFrame({ ... "patient_id": ["patient-0", "patient-1"], ... "event_type": ["patients", "patients"], ... "timestamp": [datetime(2020, 1, 1), datetime(2020, 1, 1)], ... "patients/gender": ["F", "M"], ... }) >>> class ToyDataset: ... def get_patient(self, patient_id): ... return Patient( ... patient_id=patient_id, ... data_source=event_df.filter(pl.col("patient_id") == patient_id), ... ) >>> sensitive_attributes_from_patient_ids( ... ToyDataset(), ["patient-0", "patient-1"], "gender", "F" ... ) array([1., 0.])