Skip to content

[codex] Fix survival evaluation edge cases and estimator consistency#20

Merged
shi-ang merged 36 commits into
mainfrom
bug-fixes
Jun 8, 2026
Merged

[codex] Fix survival evaluation edge cases and estimator consistency#20
shi-ang merged 36 commits into
mainfrom
bug-fixes

Conversation

@shi-ang

@shi-ang shi-ang commented Jun 8, 2026

Copy link
Copy Markdown
Owner

Description

This pull request collects correctness, validation, and consistency fixes across survival evaluation metrics, evaluators, and single-event nonparametric estimators. It addresses probability and time-grid boundary cases, interval-censoring behavior, monotonicity handling, and estimator baselines while adding focused regression coverage for the corrected behavior.

Updates

If this PR adds a new feature, what is the use case, and how to use it?

  1. Add reusable curve/time-coordinate alignment for shared or per-sample grids, plus direction-aware monotonicity validation and correction, including isotonic regression.
  2. Expand regression coverage for evaluator inputs, calibration, concordance, curve conversion, AUPRC, COV, and nonparametric estimators.

Fixes

List the issue fixes that are covered in this pull request. If this PR fixes an issue, how to reproduce, expected vs. Incorrect results.

  1. Fix calibration boundary cases: predictions equal to 1 are retained in H-statistic bins, uncensored one-calibration uses the retained bin size, and interval-calibration calculations use each bin's own limits.
  2. Fix prediction-curve validation and alignment: shared/per-sample grids are broadcast consistently, duplicate or descending time coordinates are rejected where required, zero-padding avoids duplicate origins, and all-one scikit-survival curves are repaired correctly.
  3. Fix metric edge cases in concordance, RMST, COV, Brier score, and AUPRC, including directed interval comparability, normalized COV mass, missing-training-data defaults, exact intervals, and left-censored CDF extrapolation at time zero.
  4. Fix nonparametric estimator behavior before the first observation and at exact event times, including Kaplan-Meier, Nelson-Aalen, Copula Graphic, Turnbull exact observations, and infinite-tail support.
  5. Fix API, type-annotation, docstring, and event-indicator terminology inconsistencies. No GitHub issue numbers are linked to these fixes.

Mandatory Checklist

  • All new or modified features have corresponding test cases.

  • I have run all the tests, using pytest, and this is the log I get:

========================================================================= test session starts =========================================================================
platform linux -- Python 3.11.10, pytest-8.4.2, pluggy-1.6.0
rootdir: /home/shiang/Documents/GithubRepository/SurvivalEVAL
configfile: pyproject.toml
plugins: anyio-4.6.2
collected 96 items                                                                                                                                                    

tests/test_concordance.py ..                                                                                                                                    [  2%]
tests/test_evaluator.py ...................                                                                                                                     [ 21%]
tests/test_ibs.py ....                                                                                                                                          [ 26%]
tests/test_interval_cen_evaluator.py ......                                                                                                                     [ 32%]
tests/test_multiple_brier.py ...                                                                                                                                [ 35%]
tests/test_nonparametric_estimators.py ...............                                                                                                          [ 51%]
tests/test_other_metrics.py ....                                                                                                                                [ 55%]
tests/test_pycox.py ...                                                                                                                                         [ 58%]
tests/test_quantile_evaluator.py .......                                                                                                                        [ 65%]
tests/test_util.py .................................                                                                                                            [100%]

========================================================================== warnings summary ===========================================================================
../../../anaconda3/envs/SurvEVAL/lib/python3.11/site-packages/autograd/numpy/numpy_wrapper.py:7
  /home/shiang/anaconda3/envs/SurvEVAL/lib/python3.11/site-packages/autograd/numpy/numpy_wrapper.py:7: DeprecationWarning: numpy.core.einsumfunc is deprecated and has been renamed to numpy._core.einsumfunc. The numpy._core namespace contains private NumPy internals and its use is discouraged, as NumPy internals can change without warning in any release. In practice, most real-world usage of numpy.core is to access functionality in the public NumPy API. If that is the case, use the public NumPy API. If not, you are using NumPy internals. If you would still like to access an internal attribute, use numpy._core.einsumfunc._parse_einsum_input.
    from numpy.core.einsumfunc import _parse_einsum_input

tests/test_ici.py:48
  /home/shiang/Documents/GithubRepository/SurvivalEVAL/tests/test_ici.py:48: UserWarning: FigureCanvasAgg is non-interactive, and thus cannot be shown
    plt.show()

SurvivalEVAL/Evaluations/util.py:869
SurvivalEVAL/Evaluations/util.py:869
  /home/shiang/Documents/GithubRepository/SurvivalEVAL/SurvivalEVAL/Evaluations/util.py:869: UserWarning: The first time coordinate is not 0. An authentic survival curve should start from 0 with 100% survival probability. Adding 0 to the beginning of the time coordinates and 1 to the beginning of the predicted curves.
    warnings.warn(zero_pad_msg)

SurvivalEVAL/Evaluator.py:882
  /home/shiang/Documents/GithubRepository/SurvivalEVAL/SurvivalEVAL/Evaluator.py:882: UserWarning: FigureCanvasAgg is non-interactive, and thus cannot be shown
    plt.show()

tests/test_point_evaluator.py:65
  /home/shiang/Documents/GithubRepository/SurvivalEVAL/tests/test_point_evaluator.py:65: UserWarning: FigureCanvasAgg is non-interactive, and thus cannot be shown
    plt.show()

tests/test_single_event.py:89
  /home/shiang/Documents/GithubRepository/SurvivalEVAL/tests/test_single_event.py:89: UserWarning: FigureCanvasAgg is non-interactive, and thus cannot be shown
    plt.show()

tests/test_single_event.py:147
  /home/shiang/Documents/GithubRepository/SurvivalEVAL/tests/test_single_event.py:147: UserWarning: FigureCanvasAgg is non-interactive, and thus cannot be shown
    plt.show()

tests/test_pycox.py::test_pycox_concordance_and_brier
  /home/shiang/anaconda3/envs/SurvEVAL/lib/python3.11/site-packages/torch/autograd/graph.py:825: UserWarning: CUDA initialization: The NVIDIA driver on your system is too old (found version 11040). Please update your GPU driver by downloading and installing a new version from the URL: http://www.nvidia.com/Download/index.aspx Alternatively, go to: https://pytorch.org to install a PyTorch version that has been compiled with your version of the CUDA driver. (Triggered internally at ../c10/cuda/CUDAFunctions.cpp:108.)
    return Variable._execution_engine.run_backward(  # Calls into the C++ engine to run the backward pass

tests/test_quantile_evaluator.py::test_quantile_prediction_utilities
tests/test_quantile_evaluator.py::test_quantile_concordance_and_auc
tests/test_quantile_evaluator.py::test_quantile_brier_metrics
tests/test_quantile_evaluator.py::test_quantile_error_scores
tests/test_quantile_evaluator.py::test_quantile_calibration_tools
tests/test_quantile_evaluator.py::test_quantile_residuals_and_km_calibration
tests/test_quantile_evaluator.py::test_quantile_log_rank
  /home/shiang/Documents/GithubRepository/SurvivalEVAL/SurvivalEVAL/Evaluations/util.py:890: UserWarning: The first time coordinate is not 0. An authentic survival curve should start from 0 with 100% survival probability. Adding 0 to the beginning of the time coordinates and 1 to the beginning of the predicted curves.
    warnings.warn(zero_pad_msg)

tests/test_quantile_evaluator.py::test_quantile_error_scores
  /home/shiang/anaconda3/envs/SurvEVAL/lib/python3.11/site-packages/numpy/_core/fromnumeric.py:3904: RuntimeWarning: Mean of empty slice.
    return _methods._mean(a, axis=axis, dtype=dtype,

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=================================================================== 96 passed, 17 warnings in 4.91s ===================================================================
  • All new functions, classes, and modules contain clear docstrings and inline comments.

  • All jupyter notebooks are runnable with expected results.

N/A: this PR does not modify notebooks; notebook execution was not validated locally.

  • I have reformatted and ran isort . and black . (in this same order) on the codebase.

  • I have updated the README and added or edited any new scripts to the integration tests.

N/A: no README or integration-script changes are required; focused unit/regression tests were added instead.

  • I have ensured sufficient coverage on the newly implemented features.

  • I have made sure that both the requirements.txt and pyproject.toml files are updated according to the newly introduced dependencies. No new dependencies are introduced by this PR.

  • Paste the remaining code TODOs using the command grep -rI --color=auto --exclude-dir={.git,__pycache__,env_folder,.venv,venv,.cache,output,.github,} 'TODO' . here, and explain them if necessary:

./setup.py:56:TODO:
./SurvivalEVAL/Evaluations/MeanError.py:161:                # Numpy will throw a warning if afterward_event_times are all false. TODO: consider change the code.
./SurvivalEVAL/Evaluations/MeanError.py:465:    # TODO: We need to move the logarithm transformation later after we calculate a best-guess.

These TODOs predate or are outside the fixes completed in this PR and are left for follow-up work.

shi-ang added 30 commits June 6, 2026 21:06
…als) and add checks for valid interval-censored data.
…ent indicator" instead of "censoring indicator" to avoid confusion.
@shi-ang
shi-ang requested a review from Copilot June 8, 2026 02:38
@shi-ang
shi-ang marked this pull request as ready for review June 8, 2026 02:38
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR improves correctness and consistency across SurvivalEVAL’s survival-evaluation utilities, interval-censored evaluators, and single-event nonparametric estimators by tightening edge-case handling (boundary probabilities, time-grid alignment, interval semantics, and baseline behavior) and adding regression tests for the corrected behavior.

Changes:

  • Added reusable curve/time-grid broadcasting plus direction-aware monotonicity checking/correction (including isotonic regression) and expanded validation for curve/time inputs.
  • Fixed multiple metric/evaluator edge cases (e.g., calibration bin boundaries, interval comparability for concordance, COV normalization, AUPRC left-censor extrapolation defaults, exact-interval inclusion logic).
  • Updated single-event nonparametric estimators (KM/NA/CopulaGraphic/Turnbull) to include consistent pre-observation baselines and improved exact-observation / infinite-tail support handling, with new regression tests.

Reviewed changes

Copilot reviewed 27 out of 28 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
tests/test_util.py Adds regression tests for broadcasting/alignment, zero-padding on 2D grids, monotonicity direction, isotonic correction, and AUPRC validation.
tests/test_right2interval.py Updates monotonicity check call to explicitly use decreasing direction.
tests/test_other_metrics.py Adds regression tests for updated COV behavior and validation.
tests/test_nonparametric_estimators.py Adds regression tests for baseline-at-zero and exact-time handling across nonparametric estimators.
tests/test_interval_cen_evaluator.py Adds regression tests for interval one-calibration bins, concordance return types, exact-interval tolerance, and brier defaults without training data.
tests/test_evaluator.py Adds evaluator regression tests for predict_interval validation, scikit-survival curve repair, 2D grids, and calibration consistency.
tests/test_concordance.py Adds focused tests for directed comparability on interval-censored precedence.
SurvivalEVAL/NonparametricEstimator/SingleEvent/util.py Fixes survival inference for times before first observation by explicitly returning baseline survival=1.
SurvivalEVAL/NonparametricEstimator/SingleEvent/Turnbull.py Refactors Turnbull support to handle exact observations and preserve infinite-tail support while keeping step-function semantics.
SurvivalEVAL/NonparametricEstimator/SingleEvent/NelsonAalen.py Adds explicit baseline-at-zero alignment and improves prediction-time validation/shape handling.
SurvivalEVAL/NonparametricEstimator/SingleEvent/KaplanMeier.py Adds explicit baseline-at-zero alignment and adjusts KM-area baseline reuse and documentation.
SurvivalEVAL/NonparametricEstimator/SingleEvent/Fiducial.py Improves formatting, clarifies docs, and reuses shared monotonicity correction (make_monotonic) instead of a local isotonic implementation.
SurvivalEVAL/NonparametricEstimator/SingleEvent/CopulaGraphic.py Adds explicit baseline-at-zero alignment.
SurvivalEVAL/NonparametricEstimator/SingleEvent/init.py Minor formatting adjustment.
SurvivalEVAL/IntervalCenEvaluator.py Tightens validation for finite/nonnegative left limits, clarifies docs, and normalizes concordance API/returns.
SurvivalEVAL/Evaluator.py Improves API/docs consistency, adds shared curve/time alignment, fixes several boundary behaviors, and refines KM-calibration handling for per-sample grids.
SurvivalEVAL/Evaluations/util.py Introduces align_curve_and_time_coordinates, direction-aware monotonicity checks, isotonic option for monotonic repair, stricter validations, and improved RMST/mean/median helpers.
SurvivalEVAL/Evaluations/util_plots.py Adds future-annotations import for typing consistency.
SurvivalEVAL/Evaluations/SingleTimeCalibration.py Fixes H-statistic bin inclusivity at prediction=1 and corrects bin-size handling after filtering.
SurvivalEVAL/Evaluations/OtherMetrics.py Refactors cov to be a normalized event-time CoV with stricter validation and clearer semantics/docs.
SurvivalEVAL/Evaluations/MeanError.py Improves interval “inside” logic to treat exact intervals specially and updates method docs/logic.
SurvivalEVAL/Evaluations/DistributionCalibration.py Fixes D-calibration binning for prob==1 and improves event-indicator terminology/docs.
SurvivalEVAL/Evaluations/Concordance.py Clarifies event-indicator terminology, updates interval comparability to directed precedence, and tightens midpoint imputation validation.
SurvivalEVAL/Evaluations/BrierScore.py Improves event-indicator terminology and clarifies uncensored IC Brier behavior.
SurvivalEVAL/Evaluations/AreaUnderPRCurve.py Adds curve/time-grid alignment support, improves input checks, and refines left-censor extrapolation behavior.
setup.py Formatting/quoting cleanup and converts TODO block to a proper triple-quoted string.
pyproject.toml Configures pytest to ignore tests/private by default.
.github/pull_request_template.md Updates template pytest instructions and code-fence language tags.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread SurvivalEVAL/Evaluations/MeanError.py
Comment thread SurvivalEVAL/Evaluations/AreaUnderPRCurve.py Outdated
Comment thread SurvivalEVAL/Evaluations/AreaUnderPRCurve.py Outdated
Comment thread SurvivalEVAL/Evaluations/AreaUnderPRCurve.py Outdated
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 30 out of 31 changed files in this pull request and generated 1 comment.

Comment thread SurvivalEVAL/Evaluator.py
@shi-ang
shi-ang merged commit 177fe67 into main Jun 8, 2026
1 check passed
@shi-ang
shi-ang deleted the bug-fixes branch June 8, 2026 03:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants