SurvivalEVAL 0.2.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. SurvivalEVAL-0.2.2/LICENSE +21 -0
  2. SurvivalEVAL-0.2.2/MANIFEST.in +1 -0
  3. SurvivalEVAL-0.2.2/PKG-INFO +226 -0
  4. SurvivalEVAL-0.2.2/README.md +204 -0
  5. SurvivalEVAL-0.2.2/SurvivalEVAL/Evaluations/AreaUnderCurve.py +46 -0
  6. SurvivalEVAL-0.2.2/SurvivalEVAL/Evaluations/BrierScore.py +491 -0
  7. SurvivalEVAL-0.2.2/SurvivalEVAL/Evaluations/Concordance.py +275 -0
  8. SurvivalEVAL-0.2.2/SurvivalEVAL/Evaluations/D_Calibration.py +198 -0
  9. SurvivalEVAL-0.2.2/SurvivalEVAL/Evaluations/KM_Calibration.py +101 -0
  10. SurvivalEVAL-0.2.2/SurvivalEVAL/Evaluations/MeanError.py +409 -0
  11. SurvivalEVAL-0.2.2/SurvivalEVAL/Evaluations/OneCalibration.py +132 -0
  12. SurvivalEVAL-0.2.2/SurvivalEVAL/Evaluations/custom_types.py +8 -0
  13. SurvivalEVAL-0.2.2/SurvivalEVAL/Evaluations/util.py +631 -0
  14. SurvivalEVAL-0.2.2/SurvivalEVAL/Evaluator.py +1087 -0
  15. SurvivalEVAL-0.2.2/SurvivalEVAL/__init__.py +25 -0
  16. SurvivalEVAL-0.2.2/SurvivalEVAL/version.py +4 -0
  17. SurvivalEVAL-0.2.2/SurvivalEVAL.egg-info/PKG-INFO +226 -0
  18. SurvivalEVAL-0.2.2/SurvivalEVAL.egg-info/SOURCES.txt +31 -0
  19. SurvivalEVAL-0.2.2/SurvivalEVAL.egg-info/dependency_links.txt +1 -0
  20. SurvivalEVAL-0.2.2/SurvivalEVAL.egg-info/requires.txt +11 -0
  21. SurvivalEVAL-0.2.2/SurvivalEVAL.egg-info/top_level.txt +1 -0
  22. SurvivalEVAL-0.2.2/pyproject.toml +3 -0
  23. SurvivalEVAL-0.2.2/requirements.txt +11 -0
  24. SurvivalEVAL-0.2.2/setup.cfg +4 -0
  25. SurvivalEVAL-0.2.2/setup.py +55 -0
  26. SurvivalEVAL-0.2.2/test.py +49 -0
  27. SurvivalEVAL-0.2.2/test3.py +40 -0
  28. SurvivalEVAL-0.2.2/test4.py +128 -0
  29. SurvivalEVAL-0.2.2/test5.py +389 -0
  30. SurvivalEVAL-0.2.2/test6.py +211 -0
  31. SurvivalEVAL-0.2.2/test_fast_PO.py +392 -0
  32. SurvivalEVAL-0.2.2/tests/test_evaluator.py +51 -0
  33. SurvivalEVAL-0.2.2/tests/test_point_evaluator.py +40 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2021 shi-ang
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1 @@
1
+ global-include *.txt *.py
@@ -0,0 +1,226 @@
1
+ Metadata-Version: 2.1
2
+ Name: SurvivalEVAL
3
+ Version: 0.2.2
4
+ Summary: The most comprehensive Python package for evaluating survival analysis models.
5
+ Home-page: https://github.com/shi-ang/SurvivalEVAL
6
+ Author: Shi-ang Qi
7
+ Author-email: shiang@ualberta.ca
8
+ License: MIT
9
+ Keywords: survival analysis,evaluation,metrics,survivaleval
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Topic :: Scientific/Engineering
13
+ Classifier: Programming Language :: Python
14
+ Classifier: Programming Language :: Python :: 3.8
15
+ Classifier: Programming Language :: Python :: 3.9
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Requires-Python: >=3.8
20
+ Description-Content-Type: text/markdown
21
+ License-File: LICENSE
22
+
23
+ <h1 align="center">SurvivalEVAL</h1>
24
+
25
+ <p align="center">
26
+ <a href="https://github.com/shi-ang/SurvivalEVAL/">
27
+ <img alt="PyPI" src="https://github.com/shi-ang/SurvivalEVAL/blob/main/logo.png" width="300" height="300"></a>
28
+ </p>
29
+
30
+
31
+ -----------------
32
+
33
+ [//]: # ()
34
+ [//]: # ([![Python 3.8+]&#40;https://img.shields.io/badge/python-3.8+-blue.svg&#41;]&#40;https://www.python.org/downloads/release/python-380/&#41;)
35
+
36
+ [//]: # ([![License]&#40;https://img.shields.io/badge/license-MIT-yellow.svg&#41;]&#40;https://opensource.org/licenses/MIT&#41;)
37
+
38
+ [//]: # ([![Maintenance]&#40;https://img.shields.io/badge/Maintained%3F-yes-green.svg&#41;]&#40;https://github.com/shi-ang/SurvivalEVAL/issues&#41;)
39
+
40
+ [//]: # ([![HitCount]&#40;https://hits.dwyl.com/shi-ang/SurvivalEVAL.svg?style=flat&#41;]&#40;http://hits.dwyl.com/shi-ang/SurvivalEVAL&#41;)
41
+
42
+ [//]: # ()
43
+
44
+ <p align="center">
45
+ <a href="https://pypi.org/project/SurvivalEVAL/">
46
+ <img alt="PyPI" src="https://img.shields.io/pypi/v/SurvivalEVAL"></a>
47
+ <a href="https://pypi.org/project/SurvivalEVAL/">
48
+ <img alt="PyPI - Python Version" src="https://img.shields.io/badge/python-3.8+-blue.svg"></a>
49
+ <a href="https://opensource.org/licenses/MIT">
50
+ <img alt="License" src="https://img.shields.io/badge/license-MIT-yellow.svg"></a>
51
+ <a href="https://github.com/shi-ang/SurvivalEVAL/issues">
52
+ <img alt="Maintenance" src="https://img.shields.io/badge/Maintained%3F-yes-green.svg"></a>
53
+ <a href="http://hits.dwyl.com/shi-ang/SurvivalEVAL">
54
+ <img alt="HitCount" src="https://hits.dwyl.com/shi-ang/SurvivalEVAL.svg?style=flat"></a>
55
+ </p>
56
+
57
+
58
+ This python-based package contains the most completeness evaluation methods for Survival Algorithms (see [paper](https://ojs.aaai.org/index.php/AAAI-SS/article/view/27713)).
59
+ These evaluation metrics can be divided into 3 categories:
60
+ - For point prediction (first row in the figure below)
61
+ - [Concordance Index](#concordance-index)
62
+ - [MAE](#mean-absolute-error)
63
+ - [MSE](#mean-squared-error)
64
+ - For survival distribution prediction (second row in the figure below)
65
+ - [IBS](#integrated-brier-score-ibs)
66
+ - [D-Calibration](#distribution-calibration-d-calibration)
67
+ - For single time probability prediction (third row in the figure below)
68
+ - [AUROC](#area-under-the-receiver-operating-characteristic-auroc)
69
+ - [BS](#brier-score-bs)
70
+ - [1-Calibration](#one-time-calibration-1-calibration)
71
+
72
+ [//]: # (![Visualization of the evaluation metrics]&#40;all_metrics.png&#41;)
73
+
74
+ <p align="center">
75
+ <a href="https://github.com/shi-ang/SurvivalEVAL/blob/main/all_metrics.png">
76
+ <img alt="Visualization of the evaluation metrics" src="https://github.com/shi-ang/SurvivalEVAL/blob/main/all_metrics.png"></a>
77
+ </p>
78
+
79
+ ## Concordance index
80
+ Concordance index identifies the “comparable” pairs of patients and calculates the percentage of correctly ranked pairs to assess a survival model’s performance.
81
+ Given two predicted survival curves of a paired patients, it compares the predicted median/mean survival times and marks that pair as correct if the model's prediction about who died first matches with the reality.
82
+
83
+ ## Mean Absolute Error
84
+ One straightforward metric would be “MAE” – the absolute difference between the actual and predicted survival times (e.g. median of a curve).
85
+ This requires using the “actual survival time”, which is trivial for uncensored instances, but problematic for censored individuals.
86
+ This python package implemented MAE loss metrics using different ways of handling censored instances. Here we list three of them:
87
+ 1. `Uncensored` simply discards all the censored individuals and compute the MAE for all the uncensored instances.
88
+ 2. `Hinge` calculates the early prediction error. For a censored instance, if the predicted survival time is smaller than the censored time, then `MAE = censor_time - predict_time`. If the predicted survival time is equal or larger than the censored time, then `MAE = 0`. Note that the standard `Hinge` method requires the `Weighted` parameter to be set to `False`.
89
+ 3. `Pseudo_obs` “de-censors” the censored patients, using pseudo-observation method (by estimating the contribution of a censored subject to the whole Kaplan-Meier distribution). Then it calculates the MAE between de-censoring time and the predicted survival time, just like the normal way. Note that the standard `Pseudo_obs` method requires the `Weighted` parameter to be set to `True`.
90
+
91
+
92
+ ## Mean Squared Error and Root Mean Squared Error
93
+ Mean squared error (MSE) is another metric to measure the difference between the actual and predicted survival times.
94
+ Similar to MAE, mean squared error (MSE) also has multiple ways to handle censored instances, similar to MAE.
95
+ 1. `Uncensored`
96
+ 2. `Hinge`
97
+ 3. `Pseudo_obs`
98
+
99
+ We also have root mean squared error (RMSE) for each of the different ways.
100
+
101
+ ## Integrated Brier Score (IBS)
102
+ IBS measures the squared difference between the predicted survival curve with the Heaviside step function of the observed event.
103
+ IBS can be viewed as the integration of the (single-time) Brier score across all the time points.
104
+ A smaller IBS value is preferred over the larger value.
105
+ This python implementation uses IPCW weighting to handle the censored instances. Please refer to [Assessment and Comparison of Prognostic Classification Schemes for Survival Data](https://pubmed.ncbi.nlm.nih.gov/10474158/) for the detail of IPCW weighting.
106
+ Please also note that IBS is also similar to the [Continuous Ranked Probability Score (CRPS)](https://arxiv.org/abs/1806.08324), except (1) the IPCW weighting, and (2) squared error instead of absolute error.
107
+
108
+ ## Distribution Calibration (D-calibration)
109
+ [Haider et al.](https://jmlr.org/papers/volume21/18-772/18-772.pdf) proposed distribution calibration (D-calibration) test for determining if a model that produces ISDs is meaningful.
110
+ D-calibration splits the time-axis into a fixed number of intervals and compares the actual number of events with the predicted number of events within each interval.
111
+ A well D-calibrated model is the one where the predicted number of events within each time interval is statistically similar to the observed number.
112
+ Models with p-value higher than 0.05 can be considered as well-calibrated model across the survival distribution.
113
+
114
+ D-calibration quantifies this comparison of predicted and actual events within each time interval.
115
+ The details of D-calibration calculations and ways to incorporate censored instances into D-calibration computation appear in Appendix B and in [Effective Ways to Build and Evaluate Individual Survival Distributions](https://jmlr.org/papers/volume21/18-772/18-772.pdf).
116
+
117
+ ## Area Under the Receiver Operating Characteristic (AUROC)
118
+ AUROC is a metric to measure the performance of a single time probability prediction.
119
+ It is the area under the receiver operating characteristic curve, which is the plot of the true positive rate against the false positive rate at various threshold settings.
120
+ In the survival analysis, the single time probability prediction is the prediction of the survival probability at a specific time point.
121
+ And the true label is whether the patient died at that time point.
122
+ AUROC excludes the censored instances whose censoring time is earlier than the target time point.
123
+
124
+ ## Brier Score (BS)
125
+ The Brier score, at a specific time-point, is computed as the mean squared error between the observed event (binary indicator variable) and the predicted event probability at that time-point.
126
+ It is meaningful in the sense that the square root of the Brier score is the distance between the observed and predicted event on the probability scale.
127
+
128
+
129
+ ## One-time Calibration (1-calibration)
130
+ Calibration measures the confidence of the model.
131
+ The detailed explanation for the algorithm implementation can be found in [Effective Ways to Build and Evaluate Individual Survival Distributions](https://jmlr.org/papers/volume21/18-772/18-772.pdf) and [A tutorial on calibration measurements and calibration models for clinical prediction models](https://academic.oup.com/jamia/article/27/4/621/5762806).
132
+ The output is a p-value of Hosmer-Lemeshow goodness-of-fit test at a target time.
133
+ Models with p-value higher than 0.05 can be considered as well-calibrated model at that time.
134
+
135
+
136
+ ## Installation
137
+ You can install the package via pip.
138
+ ```bash
139
+ pip install SurvivalEVAL
140
+ ```
141
+
142
+ Or if you want to do some modification by yourself.
143
+ Clone the repo, cd into it and install it in editable mode (`-e` option).
144
+ That way, these are no more need to re-install the package after modification.
145
+ ```bash
146
+ git clone https://github.com/shi-ang/SurvivalEVAL.git
147
+ cd SurvivalEVAL
148
+ pip install -r requirements.txt
149
+ pip install -e .
150
+ ```
151
+
152
+ ## Quickstart Example
153
+
154
+ Install a survival analysis package, such as `lifelines`, and load the data.
155
+ Then, you can use the following code to evaluate the model.
156
+
157
+ ```python
158
+ from lifelines import CoxPHFitter
159
+ from lifelines.datasets import load_rossi
160
+
161
+ from SurvivalEVAL.Evaluator import LifelinesEvaluator
162
+
163
+ # Load the data
164
+ rossi = load_rossi()
165
+ rossi = rossi.sample(frac=1.0)
166
+
167
+ # Split train/test set
168
+ train = rossi.iloc[:300, :]
169
+ test = rossi.iloc[300:, :]
170
+ train_event_times = train.week.values
171
+ train_event_indicators = train.arrest.values
172
+ test_event_times = test.week.values
173
+ test_event_indicators = test.arrest.values
174
+
175
+ # Fit the model
176
+ cph = CoxPHFitter()
177
+ cph.fit(train, duration_col='week', event_col='arrest')
178
+
179
+ survival_curves = cph.predict_survival_function(test)
180
+
181
+ # Make the evaluation
182
+ eval = LifelinesEvaluator(survival_curves, test_event_times, test_event_indicators,
183
+ train_event_times, train_event_indicators)
184
+
185
+ cindex, _, _ = eval.concordance()
186
+
187
+ mae_score = eval.mae(method="Pseudo_obs")
188
+
189
+ mse_score = eval.mse(method="Hinge")
190
+
191
+ # The largest event time is 52. So we use 53 time points (0, 1, ..., 52) to calculate the IBS
192
+ ibs = eval.integrated_brier_score(num_points=53, draw_figure=True)
193
+
194
+ d_cal = eval.d_calibration()
195
+
196
+ # The target time for the single time probability prediction is set to 25
197
+ auc_score = eval.auc(target_time=25)
198
+ bs_score = eval.brier_score(target_time=25)
199
+ one_cal = eval.one_calibration(target_time=25)
200
+
201
+ ```
202
+ See the [Examples](examples) for more usage examples.
203
+
204
+
205
+ ## Expected Deliveries in the Future
206
+ 1. Time-dependent c-index (by Antolini)
207
+ 2. IPCW AUC
208
+
209
+ Please create an issue if you want me to implement any other evaluation metrics.
210
+
211
+ ## Citing this work
212
+
213
+ We recommend you use the following to cite `SurvivalEVAL` in your publications:
214
+
215
+ ```
216
+ @article{qi2024survivaleval,
217
+ year = {2024},
218
+ month = {01},
219
+ pages = {453-457},
220
+ title = {{SurvivalEVAL}: A Comprehensive Open-Source Python Package for Evaluating Individual Survival Distributions},
221
+ author={Qi, Shi-ang and Sun, Weijie and Greiner, Russell},
222
+ volume = {2},
223
+ journal = {Proceedings of the AAAI Symposium Series},
224
+ doi = {10.1609/aaaiss.v2i1.27713}
225
+ }
226
+ ```
@@ -0,0 +1,204 @@
1
+ <h1 align="center">SurvivalEVAL</h1>
2
+
3
+ <p align="center">
4
+ <a href="https://github.com/shi-ang/SurvivalEVAL/">
5
+ <img alt="PyPI" src="https://github.com/shi-ang/SurvivalEVAL/blob/main/logo.png" width="300" height="300"></a>
6
+ </p>
7
+
8
+
9
+ -----------------
10
+
11
+ [//]: # ()
12
+ [//]: # ([![Python 3.8+]&#40;https://img.shields.io/badge/python-3.8+-blue.svg&#41;]&#40;https://www.python.org/downloads/release/python-380/&#41;)
13
+
14
+ [//]: # ([![License]&#40;https://img.shields.io/badge/license-MIT-yellow.svg&#41;]&#40;https://opensource.org/licenses/MIT&#41;)
15
+
16
+ [//]: # ([![Maintenance]&#40;https://img.shields.io/badge/Maintained%3F-yes-green.svg&#41;]&#40;https://github.com/shi-ang/SurvivalEVAL/issues&#41;)
17
+
18
+ [//]: # ([![HitCount]&#40;https://hits.dwyl.com/shi-ang/SurvivalEVAL.svg?style=flat&#41;]&#40;http://hits.dwyl.com/shi-ang/SurvivalEVAL&#41;)
19
+
20
+ [//]: # ()
21
+
22
+ <p align="center">
23
+ <a href="https://pypi.org/project/SurvivalEVAL/">
24
+ <img alt="PyPI" src="https://img.shields.io/pypi/v/SurvivalEVAL"></a>
25
+ <a href="https://pypi.org/project/SurvivalEVAL/">
26
+ <img alt="PyPI - Python Version" src="https://img.shields.io/badge/python-3.8+-blue.svg"></a>
27
+ <a href="https://opensource.org/licenses/MIT">
28
+ <img alt="License" src="https://img.shields.io/badge/license-MIT-yellow.svg"></a>
29
+ <a href="https://github.com/shi-ang/SurvivalEVAL/issues">
30
+ <img alt="Maintenance" src="https://img.shields.io/badge/Maintained%3F-yes-green.svg"></a>
31
+ <a href="http://hits.dwyl.com/shi-ang/SurvivalEVAL">
32
+ <img alt="HitCount" src="https://hits.dwyl.com/shi-ang/SurvivalEVAL.svg?style=flat"></a>
33
+ </p>
34
+
35
+
36
+ This python-based package contains the most completeness evaluation methods for Survival Algorithms (see [paper](https://ojs.aaai.org/index.php/AAAI-SS/article/view/27713)).
37
+ These evaluation metrics can be divided into 3 categories:
38
+ - For point prediction (first row in the figure below)
39
+ - [Concordance Index](#concordance-index)
40
+ - [MAE](#mean-absolute-error)
41
+ - [MSE](#mean-squared-error)
42
+ - For survival distribution prediction (second row in the figure below)
43
+ - [IBS](#integrated-brier-score-ibs)
44
+ - [D-Calibration](#distribution-calibration-d-calibration)
45
+ - For single time probability prediction (third row in the figure below)
46
+ - [AUROC](#area-under-the-receiver-operating-characteristic-auroc)
47
+ - [BS](#brier-score-bs)
48
+ - [1-Calibration](#one-time-calibration-1-calibration)
49
+
50
+ [//]: # (![Visualization of the evaluation metrics]&#40;all_metrics.png&#41;)
51
+
52
+ <p align="center">
53
+ <a href="https://github.com/shi-ang/SurvivalEVAL/blob/main/all_metrics.png">
54
+ <img alt="Visualization of the evaluation metrics" src="https://github.com/shi-ang/SurvivalEVAL/blob/main/all_metrics.png"></a>
55
+ </p>
56
+
57
+ ## Concordance index
58
+ Concordance index identifies the “comparable” pairs of patients and calculates the percentage of correctly ranked pairs to assess a survival model’s performance.
59
+ Given two predicted survival curves of a paired patients, it compares the predicted median/mean survival times and marks that pair as correct if the model's prediction about who died first matches with the reality.
60
+
61
+ ## Mean Absolute Error
62
+ One straightforward metric would be “MAE” – the absolute difference between the actual and predicted survival times (e.g. median of a curve).
63
+ This requires using the “actual survival time”, which is trivial for uncensored instances, but problematic for censored individuals.
64
+ This python package implemented MAE loss metrics using different ways of handling censored instances. Here we list three of them:
65
+ 1. `Uncensored` simply discards all the censored individuals and compute the MAE for all the uncensored instances.
66
+ 2. `Hinge` calculates the early prediction error. For a censored instance, if the predicted survival time is smaller than the censored time, then `MAE = censor_time - predict_time`. If the predicted survival time is equal or larger than the censored time, then `MAE = 0`. Note that the standard `Hinge` method requires the `Weighted` parameter to be set to `False`.
67
+ 3. `Pseudo_obs` “de-censors” the censored patients, using pseudo-observation method (by estimating the contribution of a censored subject to the whole Kaplan-Meier distribution). Then it calculates the MAE between de-censoring time and the predicted survival time, just like the normal way. Note that the standard `Pseudo_obs` method requires the `Weighted` parameter to be set to `True`.
68
+
69
+
70
+ ## Mean Squared Error and Root Mean Squared Error
71
+ Mean squared error (MSE) is another metric to measure the difference between the actual and predicted survival times.
72
+ Similar to MAE, mean squared error (MSE) also has multiple ways to handle censored instances, similar to MAE.
73
+ 1. `Uncensored`
74
+ 2. `Hinge`
75
+ 3. `Pseudo_obs`
76
+
77
+ We also have root mean squared error (RMSE) for each of the different ways.
78
+
79
+ ## Integrated Brier Score (IBS)
80
+ IBS measures the squared difference between the predicted survival curve with the Heaviside step function of the observed event.
81
+ IBS can be viewed as the integration of the (single-time) Brier score across all the time points.
82
+ A smaller IBS value is preferred over the larger value.
83
+ This python implementation uses IPCW weighting to handle the censored instances. Please refer to [Assessment and Comparison of Prognostic Classification Schemes for Survival Data](https://pubmed.ncbi.nlm.nih.gov/10474158/) for the detail of IPCW weighting.
84
+ Please also note that IBS is also similar to the [Continuous Ranked Probability Score (CRPS)](https://arxiv.org/abs/1806.08324), except (1) the IPCW weighting, and (2) squared error instead of absolute error.
85
+
86
+ ## Distribution Calibration (D-calibration)
87
+ [Haider et al.](https://jmlr.org/papers/volume21/18-772/18-772.pdf) proposed distribution calibration (D-calibration) test for determining if a model that produces ISDs is meaningful.
88
+ D-calibration splits the time-axis into a fixed number of intervals and compares the actual number of events with the predicted number of events within each interval.
89
+ A well D-calibrated model is the one where the predicted number of events within each time interval is statistically similar to the observed number.
90
+ Models with p-value higher than 0.05 can be considered as well-calibrated model across the survival distribution.
91
+
92
+ D-calibration quantifies this comparison of predicted and actual events within each time interval.
93
+ The details of D-calibration calculations and ways to incorporate censored instances into D-calibration computation appear in Appendix B and in [Effective Ways to Build and Evaluate Individual Survival Distributions](https://jmlr.org/papers/volume21/18-772/18-772.pdf).
94
+
95
+ ## Area Under the Receiver Operating Characteristic (AUROC)
96
+ AUROC is a metric to measure the performance of a single time probability prediction.
97
+ It is the area under the receiver operating characteristic curve, which is the plot of the true positive rate against the false positive rate at various threshold settings.
98
+ In the survival analysis, the single time probability prediction is the prediction of the survival probability at a specific time point.
99
+ And the true label is whether the patient died at that time point.
100
+ AUROC excludes the censored instances whose censoring time is earlier than the target time point.
101
+
102
+ ## Brier Score (BS)
103
+ The Brier score, at a specific time-point, is computed as the mean squared error between the observed event (binary indicator variable) and the predicted event probability at that time-point.
104
+ It is meaningful in the sense that the square root of the Brier score is the distance between the observed and predicted event on the probability scale.
105
+
106
+
107
+ ## One-time Calibration (1-calibration)
108
+ Calibration measures the confidence of the model.
109
+ The detailed explanation for the algorithm implementation can be found in [Effective Ways to Build and Evaluate Individual Survival Distributions](https://jmlr.org/papers/volume21/18-772/18-772.pdf) and [A tutorial on calibration measurements and calibration models for clinical prediction models](https://academic.oup.com/jamia/article/27/4/621/5762806).
110
+ The output is a p-value of Hosmer-Lemeshow goodness-of-fit test at a target time.
111
+ Models with p-value higher than 0.05 can be considered as well-calibrated model at that time.
112
+
113
+
114
+ ## Installation
115
+ You can install the package via pip.
116
+ ```bash
117
+ pip install SurvivalEVAL
118
+ ```
119
+
120
+ Or if you want to do some modification by yourself.
121
+ Clone the repo, cd into it and install it in editable mode (`-e` option).
122
+ That way, these are no more need to re-install the package after modification.
123
+ ```bash
124
+ git clone https://github.com/shi-ang/SurvivalEVAL.git
125
+ cd SurvivalEVAL
126
+ pip install -r requirements.txt
127
+ pip install -e .
128
+ ```
129
+
130
+ ## Quickstart Example
131
+
132
+ Install a survival analysis package, such as `lifelines`, and load the data.
133
+ Then, you can use the following code to evaluate the model.
134
+
135
+ ```python
136
+ from lifelines import CoxPHFitter
137
+ from lifelines.datasets import load_rossi
138
+
139
+ from SurvivalEVAL.Evaluator import LifelinesEvaluator
140
+
141
+ # Load the data
142
+ rossi = load_rossi()
143
+ rossi = rossi.sample(frac=1.0)
144
+
145
+ # Split train/test set
146
+ train = rossi.iloc[:300, :]
147
+ test = rossi.iloc[300:, :]
148
+ train_event_times = train.week.values
149
+ train_event_indicators = train.arrest.values
150
+ test_event_times = test.week.values
151
+ test_event_indicators = test.arrest.values
152
+
153
+ # Fit the model
154
+ cph = CoxPHFitter()
155
+ cph.fit(train, duration_col='week', event_col='arrest')
156
+
157
+ survival_curves = cph.predict_survival_function(test)
158
+
159
+ # Make the evaluation
160
+ eval = LifelinesEvaluator(survival_curves, test_event_times, test_event_indicators,
161
+ train_event_times, train_event_indicators)
162
+
163
+ cindex, _, _ = eval.concordance()
164
+
165
+ mae_score = eval.mae(method="Pseudo_obs")
166
+
167
+ mse_score = eval.mse(method="Hinge")
168
+
169
+ # The largest event time is 52. So we use 53 time points (0, 1, ..., 52) to calculate the IBS
170
+ ibs = eval.integrated_brier_score(num_points=53, draw_figure=True)
171
+
172
+ d_cal = eval.d_calibration()
173
+
174
+ # The target time for the single time probability prediction is set to 25
175
+ auc_score = eval.auc(target_time=25)
176
+ bs_score = eval.brier_score(target_time=25)
177
+ one_cal = eval.one_calibration(target_time=25)
178
+
179
+ ```
180
+ See the [Examples](examples) for more usage examples.
181
+
182
+
183
+ ## Expected Deliveries in the Future
184
+ 1. Time-dependent c-index (by Antolini)
185
+ 2. IPCW AUC
186
+
187
+ Please create an issue if you want me to implement any other evaluation metrics.
188
+
189
+ ## Citing this work
190
+
191
+ We recommend you use the following to cite `SurvivalEVAL` in your publications:
192
+
193
+ ```
194
+ @article{qi2024survivaleval,
195
+ year = {2024},
196
+ month = {01},
197
+ pages = {453-457},
198
+ title = {{SurvivalEVAL}: A Comprehensive Open-Source Python Package for Evaluating Individual Survival Distributions},
199
+ author={Qi, Shi-ang and Sun, Weijie and Greiner, Russell},
200
+ volume = {2},
201
+ journal = {Proceedings of the AAAI Symposium Series},
202
+ doi = {10.1609/aaaiss.v2i1.27713}
203
+ }
204
+ ```
@@ -0,0 +1,46 @@
1
+ import numpy as np
2
+ from sklearn.metrics import roc_auc_score
3
+
4
+
5
+ def auc(
6
+ predict_probs: np.ndarray,
7
+ event_times: np.ndarray,
8
+ event_indicators: np.ndarray,
9
+ target_time: float = None
10
+ ) -> float:
11
+ """
12
+ Calculate the Area Under the Curve (AUC) for the survival model.
13
+
14
+ :param predict_probs: the predicted survival probabilities
15
+ :param event_times: the event times
16
+ :param event_indicators: the event indicators
17
+ :param target_time: the target time
18
+ :return: the AUC
19
+ """
20
+ # if the target time is not specified, then we use the median of the event times
21
+ if target_time is None:
22
+ target_time = np.median(event_times)
23
+
24
+ # for censored data, if the censor time is earlier than the target time,
25
+ # (since we cannot observe the real status at the target time)
26
+ # then we just exclude its prediction and observation from the calculation
27
+ exclude_indicators = np.logical_and(event_times < target_time, event_indicators == 0)
28
+ event_times = event_times[~exclude_indicators]
29
+ predict_probs = predict_probs[~exclude_indicators]
30
+
31
+ # get the binary status of the test data, given the target time
32
+ binary_status = (event_times <= target_time).astype(int)
33
+
34
+ # computing the AUC, given the predicted probabilities and the binary status
35
+ risks = - predict_probs
36
+ return roc_auc_score(binary_status, risks)
37
+
38
+
39
+ if __name__ == '__main__':
40
+ # test the AUC function
41
+ predict_probs = np.array([0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.2, 0.8, 0.9])
42
+ event_times = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9])
43
+ event_indicators = np.array([1, 1, 0, 1, 1, 1, 1, 1, 1])
44
+ target_time = 5
45
+
46
+ print(auc(predict_probs, event_times, event_indicators, target_time))