Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@ repos:
- id: check-yaml
- id: check-toml
- id: check-added-large-files
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.12.5
hooks:
- id: ruff-check
- id: ruff-format
- repo: https://github.com/nestauk/pre-commit-hooks
rev: v1.2.0
hooks:
- id: nbstripout-preserve-timestamp
- id: jupytext-enforce-pairing
- id: jupytext-smart-sync
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.12.5
hooks:
- id: ruff-check
- id: ruff-format
112 changes: 105 additions & 7 deletions daindex/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,8 +141,8 @@ class DAIndex(object):
`evaluate_all_groups_by_models` methods can be called to calculate the DAI for all groups relative to a
single reference group.

The results can be accessed using the `get_group_ratios` and `get_group_figures` methods, or printed using
the `present_results` and `present_all_results` methods.
The results can be accessed using the `get_group_ratio` and `get_group_figure` methods (with a reference and
other group), or printed using the `present_results` and `present_all_results` methods.
Comment on lines +144 to +145

Copilot AI Jul 25, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The documentation update refers to get_group_ratios and get_group_figures as renamed methods, but should clarify that these are the new method names replacing the old ones to avoid confusion.

Suggested change
The results can be accessed using the `get_group_ratio` and `get_group_figure` methods (with a reference and
other group), or printed using the `present_results` and `present_all_results` methods.
The results can be accessed using the `get_group_ratios` and `get_group_figures` methods (with a reference and
other group). These are the new method names replacing the old `get_group_ratio` and `get_group_figure` methods,
to ensure consistency. Results can also be printed using the `present_results` and `present_all_results` methods.

Copilot uses AI. Check for mistakes.

Args:
cohort: The DataFrame containing the data for the cohort.
Expand All @@ -160,7 +160,7 @@ class DAIndex(object):
weight_sum_steps: The number of bins for the weighted sum of k-step cutoffs.
n_jobs: The number of jobs to run in parallel.
model_name: The name of the model to use in the plots.
decision_boundary: The decision boundary for the DA curve.
decision_boundary: The decision boundary for the DA curve. Defaults to 0.5.

Methods:
setup_groups: Set up the groups for the DAI calculation.
Expand All @@ -174,10 +174,16 @@ class DAIndex(object):
model objects.
present_results: Print the DAI results for a pair of groups.
present_all_results: Print the DAI results for all group pairs.
get_group_ratios: Get the DAI ratios for a pair of groups.
get_group_figures: Get the DAI figures for a pair of groups.
get_group_ratio: Get the DAI ratios for a pair of groups.
get_group_figure: Get the DAI figure for a pair of groups.
get_all_ratios: Get the DAI ratios for all group pairs.
get_all_figures: Get the DAI figures for all group pairs.
get_group_step_samples: Get the number of samples used for each step for a specific group.
get_group_sub_optimal_steps: Get information about sub-optimal steps for a specific group.
get_group_failed_steps: Get information about failed steps for a specific group.
get_all_groups_step_samples: Get step sample information for all evaluated groups.
get_all_groups_sub_optimal_steps: Get sub-optimal step information for all evaluated groups.
get_all_groups_failed_steps: Get failed step information for all evaluated groups.
"""

def __init__(
Expand Down Expand Up @@ -221,6 +227,10 @@ def __init__(
self.group_ratios = {}
self.group_figures = {}
self.issues = []
# New attributes to track step information
self.group_sub_optimal_steps = {} # Stores sub-optimal steps for each group
self.group_failed_steps = {} # Stores failed steps for each group
self.group_step_samples = {} # Stores sample counts for each step for each group

def setup_groups(self, groups: Group | list[Group], group_col: str = None) -> None:
if not isinstance(groups, list):
Expand Down Expand Up @@ -485,6 +495,16 @@ def process_step(s: int) -> tuple[float, int, float, bool, bool]:
delayed(process_step)(s)
for s in tqdm(self.step_scores, desc=f"Calculating k-steps for '{group}' group", position=1, leave=False)
)

# Store step information internally
sub_opt_steps = {s[0]: s[1] for s in ret if s[3]}
failed_steps = {s[0]: s[1] for s in ret if s[4]}
step_samples = {s[0]: s[1] for s in ret}

self.group_sub_optimal_steps[group] = sub_opt_steps
self.group_failed_steps[group] = failed_steps
self.group_step_samples[group] = step_samples

sub_opt_list = ", ".join([f"{s[0]}: {s[1]}" for s in ret if s[3]])
failed_list = ", ".join([f"{s[0]}: {s[1]}" for s in ret if s[4]])
if sub_opt_list or failed_list:
Expand Down Expand Up @@ -745,10 +765,10 @@ def present_all_results(self) -> None:
for group_pair in self.group_figures.keys():
self.present_results(*group_pair)

def get_group_ratios(self, reference_group: str, other_group: str) -> dict[str, float | str]:
def get_group_ratio(self, reference_group: str, other_group: str) -> dict[str, float | str]:
return self.group_ratios[(reference_group, other_group)]

def get_group_figures(self, reference_group: str, other_group: str) -> plt.Figure:
def get_group_figure(self, reference_group: str, other_group: str) -> plt.Figure:
return self.group_figures[(reference_group, other_group)]

def get_all_ratios(self) -> pd.DataFrame:
Expand All @@ -758,3 +778,81 @@ def get_all_ratios(self) -> pd.DataFrame:

def get_all_figures(self) -> dict[tuple[str, str], plt.Figure]:
return self.group_figures

def get_group_step_samples(self, group: str) -> dict[float, int]:
"""
Returns the number of samples used for each step for the specified group.

Args:
group: The name of the group to get step sample information for.

Returns:
A dictionary mapping step scores to the number of samples used.
"""
if group not in self.group_step_samples:
raise ValueError(f"No step information available for group '{group}'. Run evaluation first.")
return self.group_step_samples[group]

def get_group_sub_optimal_steps(self, group: str) -> dict[float, int]:
"""
Returns information about sub-optimal steps for the specified group.
These are steps where the number of samples was below the preferred threshold
but still acceptable.

Args:
group: The name of the group to get sub-optimal step information for.

Returns:
A dictionary mapping step scores to the number of samples used for
sub-optimal steps.
"""
if group not in self.group_sub_optimal_steps:
raise ValueError(f"No step information available for group '{group}'. Run evaluation first.")
return self.group_sub_optimal_steps[group]

def get_group_failed_steps(self, group: str) -> dict[float, int]:
"""
Returns information about failed steps for the specified group.
These are steps where the number of samples was below the minimum threshold
and the step was excluded from the analysis.

Args:
group: The name of the group to get failed step information for.

Returns:
A dictionary mapping step scores to the number of samples used for
failed steps.
"""
if group not in self.group_failed_steps:
raise ValueError(f"No step information available for group '{group}'. Run evaluation first.")
return self.group_failed_steps[group]

def get_all_groups_step_samples(self) -> dict[str, dict[float, int]]:
"""
Returns the number of samples used for each step for all evaluated groups.

Returns:
A dictionary mapping group names to dictionaries of step scores and
their corresponding sample counts.
"""
return self.group_step_samples.copy()

def get_all_groups_sub_optimal_steps(self) -> dict[str, dict[float, int]]:
"""
Returns information about sub-optimal steps for all evaluated groups.

Returns:
A dictionary mapping group names to dictionaries of step scores and
their corresponding sample counts for sub-optimal steps.
"""
return self.group_sub_optimal_steps.copy()

def get_all_groups_failed_steps(self) -> dict[str, dict[float, int]]:
"""
Returns information about failed steps for all evaluated groups.

Returns:
A dictionary mapping group names to dictionaries of step scores and
their corresponding sample counts for failed steps.
"""
return self.group_failed_steps.copy()
9 changes: 7 additions & 2 deletions daindex/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,13 @@ def compare_two_groups(


def area_under_curve(w_data: np.ndarray, decision_boundary: float = 0.5) -> tuple[float, float]:
"""
calculate the area under curve - do NOT do interpolation
"""Calculate the area under curve - do NOT do interpolation

Args:
w_data: The weighted data, should be a 2D array with shape (n, 3) where
the first column is the x values, the second column is the y values,
and the third column is the weights.
decision_boundary: The decision boundary for calculating the area under curve.
"""
prev = None
area = 0.0
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ authors = [
{ name = "Harrison Wilde", email = "h.wilde@ucl.ac.uk" },
{ name = "Honghan Wu", email = "honghan.wu@gmail.com" },
]
version = "0.7.3"
version = "0.8.0"
description = "Deterioration Allocation Index Framework"
license = "MIT"
readme = "README.md"
Expand Down
31 changes: 28 additions & 3 deletions tutorials/meps_tutorial.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -494,9 +494,13 @@
" cohort=df,\n",
" groups=groups,\n",
" det_feature=det_feature,\n",
" decision_boundary=0.75, # Set decision boundary for DA curve\n",
")\n",
"index.evaluate_all_groups_by_models(\n",
" models=lr_orig_panel19, feature_list=feature_list, reference_group=\"White\", n_jobs=6\n",
" models=lr_orig_panel19,\n",
" feature_list=feature_list,\n",
" reference_group=\"White\",\n",
" n_jobs=1, # Up n_jobs to parallelize if needed\n",
")"
]
},
Expand All @@ -518,6 +522,24 @@
"index.get_all_ratios()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"index.get_group_ratio(\"White\", \"Asian\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"index.get_all_groups_failed_steps()"
]
},
{
"cell_type": "code",
"execution_count": null,
Expand All @@ -527,8 +549,11 @@
}
],
"metadata": {
"jupytext": {
"formats": "ipynb,py:percent"
},
"kernelspec": {
"display_name": "daindex",
"display_name": ".venv",
"language": "python",
"name": "python3"
},
Expand All @@ -542,7 +567,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.5"
"version": "3.10.18"
}
},
"nbformat": 4,
Expand Down
2 changes: 1 addition & 1 deletion uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading