Skill Tracer
Skills › Scientific Agent Skills › scikit-survival › evaluation-metrics.md

evaluation-metrics.md

407 lines · skills/scikit-survival/references/evaluation-metrics.md at 5f2bc03

Open on GitHub

Most marks come from matching words in the file, so treat them as pointers.

1# Censoring-aware evaluation, calibration, and model selection
2
3Verified for scikit-survival 0.28.0 on 2026-10-01. API statements below use
4official scikit-survival documentation; interpretation is anchored to the cited
5primary methodological literature.
6

Censoring-aware evaluation, calibration, and model selection

Verified for scikit-survival 0.28.0 on 2026-10-01. API statements below use official scikit-survival documentation; interpretation is anchored to the cited primary methodological literature.

Raw lines 1 to 6
7## Keep the targets distinct
8
9- **Discrimination:** can the score order subjects by event risk?
10 Harrell C, Uno C, and cumulative/dynamic AUC.
11- **Probability prediction error:** how close are predicted survival probabilities
12 to observed event-free status after censoring adjustment? Brier score and IBS.
13- **Calibration:** do predicted probabilities agree with observed probabilities at
14 a specified horizon and population? Requires horizon-specific assessment; Brier
15 score is not a pure calibration measure.
16- **Cause-specific cumulative incidence:** what is the absolute probability of a
17 particular competing cause by time \(t\)? Standard survival metrics are not
18 automatically cause-specific CIF metrics.
19- **Clinical/decision utility:** do decisions based on predictions improve outcomes
20 under defined consequences? None of the metrics above establishes this.
22Do not label one aggregate number "model accuracy" without its estimand, horizon,
23censoring estimator, and input type.

Keep the targets distinct

  • Discrimination: can the score order subjects by event risk? Harrell C, Uno C, and cumulative/dynamic AUC.
  • Probability prediction error: how close are predicted survival probabilities to observed event-free status after censoring adjustment? Brier score and IBS.
  • Calibration: do predicted probabilities agree with observed probabilities at a specified horizon and population? Requires horizon-specific assessment; Brier score is not a pure calibration measure.
  • Cause-specific cumulative incidence: what is the absolute probability of a particular competing cause by time \(t\)? Standard survival metrics are not automatically cause-specific CIF metrics.
  • Clinical/decision utility: do decisions based on predictions improve outcomes under defined consequences? None of the metrics above establishes this.

Do not label one aggregate number "model accuracy" without its estimand, horizon, censoring estimator, and input type.

Raw lines 7 to 24
25## Prediction contracts

Prediction contracts

Raw lines 25 to 26
27### Higher-is-riskier scalar
29Shape `(n_test,)`. Used by:
31- `concordance_index_censored`
32- `concordance_index_ipcw`
33- `cumulative_dynamic_auc` (same score at each requested time)
35Typical source:
37```python
38risk = estimator.predict(X_test)
39```
41Confirm direction. Cox and ranking-only SVM predictions are higher-is-riskier.
42Predicted survival/log-time outputs are the opposite direction and must not be
43silently treated as risk.

Higher-is-riskier scalar

Shape (n_test,). Used by:

  • concordance_index_censored
  • concordance_index_ipcw
  • cumulative_dynamic_auc (same score at each requested time)

Typical source:

risk = estimator.predict(X_test)

Confirm direction. Cox and ranking-only SVM predictions are higher-is-riskier. Predicted survival/log-time outputs are the opposite direction and must not be silently treated as risk.

Raw lines 27 to 44
45### Time-dependent risk
47Shape `(n_test, n_times)`. Accepted by `cumulative_dynamic_auc`, where column
48`j` is risk at `times[j]`. For a random survival forest:
50```python
51functions = estimator.predict_cumulative_hazard_function(X_test)
52risk_by_time = np.vstack([fn(times) for fn in functions])
53```
55Cumulative hazard is risk-oriented. Untransformed survival probabilities have the opposite direction and are not valid risk inputs to `cumulative_dynamic_auc`. Numeric shape validation does not detect that semantic error; check output direction explicitly before using a transformed probability or hazard score.

Time-dependent risk

Shape (n_test, n_times). Accepted by cumulative_dynamic_auc, where column j is risk at times[j]. For a random survival forest:

functions = estimator.predict_cumulative_hazard_function(X_test)
risk_by_time = np.vstack([fn(times) for fn in functions])

Cumulative hazard is risk-oriented. Untransformed survival probabilities have the opposite direction and are not valid risk inputs to cumulative_dynamic_auc. Numeric shape validation does not detect that semantic error; check output direction explicitly before using a transformed probability or hazard score.

Raw lines 45 to 56
57### Survival probability
59Shape `(n_test, n_times)`, values in `[0, 1]`, non-increasing across columns.
60Used by:
62- `brier_score`
63- `integrated_brier_score`
65```python
66functions = estimator.predict_survival_function(X_test)
67survival_probability = np.vstack([fn(times) for fn in functions])
68```
70Metric functions expect the numeric matrix, not a list of unevaluated
71`StepFunction` objects and not a 1D risk score.

Survival probability

Shape (n_test, n_times), values in [0, 1], non-increasing across columns. Used by:

  • brier_score
  • integrated_brier_score
functions = estimator.predict_survival_function(X_test)
survival_probability = np.vstack([fn(times) for fn in functions])

Metric functions expect the numeric matrix, not a list of unevaluated StepFunction objects and not a 1D risk score.

Raw lines 57 to 72
73## Harrell concordance
75```python
76from sksurv.metrics import concordance_index_censored
78harrell_c = concordance_index_censored(
79 y_test["event"],
80 y_test["time"],
81 risk,
82)[0]
83```
85Harrell C is the fraction of comparable pairs whose risk ordering is concordant,
86with handling for tied risk and event times. It measures rank discrimination over
87the observed follow-up mix.
89Important limitations:
91- It does not assess probability calibration.
92- It does not focus on a prespecified horizon.
93- The set of comparable pairs changes under censoring.
94- Uno et al. showed the conventional estimator's limiting value can depend on the
95 censoring distribution.
97There is no universal censoring-percentage cutoff at which Harrell C suddenly
98becomes invalid. Report censoring, compare sensitivity to IPCW concordance, and
99justify the estimand.

Harrell concordance

from sksurv.metrics import concordance_index_censored

harrell_c = concordance_index_censored(
    y_test["event"],
    y_test["time"],
    risk,
)[0]

Harrell C is the fraction of comparable pairs whose risk ordering is concordant, with handling for tied risk and event times. It measures rank discrimination over the observed follow-up mix.

Important limitations:

  • It does not assess probability calibration.
  • It does not focus on a prespecified horizon.
  • The set of comparable pairs changes under censoring.
  • Uno et al. showed the conventional estimator's limiting value can depend on the censoring distribution.

There is no universal censoring-percentage cutoff at which Harrell C suddenly becomes invalid. Report censoring, compare sensitivity to IPCW concordance, and justify the estimand.

Raw lines 73 to 100
101## Uno IPCW concordance
103```python
104from sksurv.metrics import concordance_index_ipcw
106uno_c = concordance_index_ipcw(
107 y_train,
108 y_test,
109 risk,
110 tau=tau,
111)[0]
112```
114`survival_train` estimates the censoring distribution. Never pass pooled
115train+test outcomes or `y_test` as the training distribution.
117`tau` truncates the concordance target. Choose it before seeing model performance
118and where the estimated training censoring survival is positive. In 0.28.0 only test event times strictly below `tau` enter its censoring-weight
119lookup; later records remain potential comparison partners with zero event weight.
120A valid `tau` can therefore avoid a late-event support error for Uno C. This does
121not make the same test outcomes valid for AUC or Brier APIs.
123The implementation uses Kaplan-Meier censoring weights and assumes censoring is
124random/independent of features. If censoring depends on covariates, this marginal
125weight model may be inadequate. IPCW is not a generic correction for informative
126censoring.

Uno IPCW concordance

from sksurv.metrics import concordance_index_ipcw

uno_c = concordance_index_ipcw(
    y_train,
    y_test,
    risk,
    tau=tau,
)[0]

survival_train estimates the censoring distribution. Never pass pooled train+test outcomes or y_test as the training distribution.

tau truncates the concordance target. Choose it before seeing model performance and where the estimated training censoring survival is positive. In 0.28.0 only test event times strictly below tau enter its censoring-weight lookup; later records remain potential comparison partners with zero event weight. A valid tau can therefore avoid a late-event support error for Uno C. This does not make the same test outcomes valid for AUC or Brier APIs.

The implementation uses Kaplan-Meier censoring weights and assumes censoring is random/independent of features. If censoring depends on covariates, this marginal weight model may be inadequate. IPCW is not a generic correction for informative censoring.

Raw lines 101 to 127
128## Cumulative/dynamic AUC
130```python
131from sksurv.metrics import cumulative_dynamic_auc
133auc, mean_auc = cumulative_dynamic_auc(
134 y_train,
135 y_test,
136 risk, # (n_test,) or (n_test, n_times)
137 times,
139```
141At each \(t\), cumulative cases have an observed event by \(t\), while dynamic
142controls remain event-free after \(t\). IPCW handles right censoring.
144Requirements:
146- `times` is one-dimensional, unique, and strictly increasing;
147- every value lies within test follow-up;
148- training follow-up supports test outcomes and the grid;
149- the training censoring survival is positive over the grid and at every test
150 event time used by the implementation (AUC weights all test events before
151 applying horizons);
152- each horizon has at least one observed case and a later control;
153- risk has shape `(n_test,)` or `(n_test, n_times)`;
154- higher values mean higher event risk.
156The returned `mean_auc` is not the arithmetic mean. It integrates
157\(\widehat{AUC}(t)\) over the time range, weighted by the estimated survival
158function.
160The cumulative/dynamic definition is one time-dependent ROC estimand. State it;
161other incident/dynamic or competing-risk definitions answer different questions.

Cumulative/dynamic AUC

from sksurv.metrics import cumulative_dynamic_auc

auc, mean_auc = cumulative_dynamic_auc(
    y_train,
    y_test,
    risk,   # (n_test,) or (n_test, n_times)
    times,
)

At each \(t\), cumulative cases have an observed event by \(t\), while dynamic controls remain event-free after \(t\). IPCW handles right censoring.

Requirements:

  • times is one-dimensional, unique, and strictly increasing;
  • every value lies within test follow-up;
  • training follow-up supports test outcomes and the grid;
  • the training censoring survival is positive over the grid and at every test event time used by the implementation (AUC weights all test events before applying horizons);
  • each horizon has at least one observed case and a later control;
  • risk has shape (n_test,) or (n_test, n_times);
  • higher values mean higher event risk.

The returned mean_auc is not the arithmetic mean. It integrates \(\widehat{AUC}(t)\) over the time range, weighted by the estimated survival function.

The cumulative/dynamic definition is one time-dependent ROC estimand. State it; other incident/dynamic or competing-risk definitions answer different questions.

Raw lines 128 to 162
163## Brier score
165```python
166from sksurv.metrics import brier_score, integrated_brier_score
168returned_times, brier = brier_score(
169 y_train,
170 y_test,
171 survival_probability,
172 times,
174ibs = integrated_brier_score(
175 y_train,
176 y_test,
177 survival_probability,
178 times,
180```
182The time-dependent Brier score is an IPC-weighted squared error between predicted
183survival probability and event-free status at \(t\). Lower is better.
185Requirements:
187- predictions are survival probabilities, not risk scores;
188- prediction shape is `(n_test, n_times)`;
189- time and training-support rules match the IPCW setting;
190- the marginal Kaplan-Meier censoring estimator's independence assumption is
191 plausible.
193IBS in 0.28.0 equals `np.trapezoid(brier, times) / (times[-1] - times[0])`.
194It is the normalized trapezoidal integral over the supplied interval. It depends on the chosen interval; IBS values from different
195time ranges are not directly comparable.
197Compare against useful reference predictions such as a training-derived
198Kaplan-Meier survival curve. Do not estimate the reference curve on test outcomes.

Brier score

from sksurv.metrics import brier_score, integrated_brier_score

returned_times, brier = brier_score(
    y_train,
    y_test,
    survival_probability,
    times,
)
ibs = integrated_brier_score(
    y_train,
    y_test,
    survival_probability,
    times,
)

The time-dependent Brier score is an IPC-weighted squared error between predicted survival probability and event-free status at \(t\). Lower is better.

Requirements:

  • predictions are survival probabilities, not risk scores;
  • prediction shape is (n_test, n_times);
  • time and training-support rules match the IPCW setting;
  • the marginal Kaplan-Meier censoring estimator's independence assumption is plausible.

IBS in 0.28.0 equals np.trapezoid(brier, times) / (times[-1] - times[0]). It is the normalized trapezoidal integral over the supplied interval. It depends on the chosen interval; IBS values from different time ranges are not directly comparable.

Compare against useful reference predictions such as a training-derived Kaplan-Meier survival curve. Do not estimate the reference curve on test outcomes.

Raw lines 163 to 199
200## Calibration
202Brier score responds to both discrimination and calibration. A good Brier score
203does not prove that predicted 20% risk corresponds to 20% observed risk in every
204horizon or subgroup.
206For a prespecified horizon:
2081. fit and tune the model without the calibration-evaluation rows;
2092. obtain event probability `1 - S(t | x)` on independent validation rows;
2103. compare predictions with a censoring-aware observed probability estimate;
2114. inspect calibration-in-the-large, slope/shape, uncertainty, and sample support;
2125. repeat only for prespecified horizons/subgroups or account for multiplicity.
214scikit-survival 0.28 does not expose a dedicated calibration-curve API. Do not use
215`sklearn.calibration.calibration_curve` naively on censored binary labels. If an
216external method is used, document its censoring assumptions and train/validation
217separation.
219Any recalibration layer is another learned model. Fit it on a calibration split or
220inner resampling, then assess on independent data.

Calibration

Brier score responds to both discrimination and calibration. A good Brier score does not prove that predicted 20% risk corresponds to 20% observed risk in every horizon or subgroup.

For a prespecified horizon:

  1. fit and tune the model without the calibration-evaluation rows;
  2. obtain event probability 1 - S(t | x) on independent validation rows;
  3. compare predictions with a censoring-aware observed probability estimate;
  4. inspect calibration-in-the-large, slope/shape, uncertainty, and sample support;
  5. repeat only for prespecified horizons/subgroups or account for multiplicity.

scikit-survival 0.28 does not expose a dedicated calibration-curve API. Do not use sklearn.calibration.calibration_curve naively on censored binary labels. If an external method is used, document its censoring assumptions and train/validation separation.

Any recalibration layer is another learned model. Fit it on a calibration split or inner resampling, then assess on independent data.

Raw lines 200 to 221
222## Safe time-grid construction
224A conservative grid for jointly computing AUC, Uno C, and Brier metrics:
226```python
227import numpy as np
228from sksurv.nonparametric import CensoringDistributionEstimator
230test_time = y_test["time"]
231train_time = y_train["time"]
233lower = np.quantile(test_time, 0.10)
234upper = min(
235 np.quantile(test_time, 0.80),
236 np.nextafter(train_time.max(), -np.inf),
238times = np.linspace(lower, upper, 50)
240if not (test_time.min() < times[0] < times[-1] < test_time.max()):
241 raise ValueError("grid is outside test follow-up")
242if not test_time.max() < train_time.max():
243 raise ValueError("test follow-up exceeds training support")
245censoring = CensoringDistributionEstimator().fit(y_train)
246if np.any(censoring.predict_proba(times) <= 0):
247 raise ValueError("training censoring survival reaches zero on grid")
248censoring.predict_ipcw(y_test) # AUC needs positive support at all test event times
249if not np.any(y_test["event"] & (test_time <= times[0])):
250 raise ValueError("AUC has no observed cases at the first horizon")
251```
253This strict maximum-follow-up check is a helper policy, not an exact universal API
254restriction. Native Brier metrics also query censoring survival at all test times;
255zero weights may be suppressed by the implementation, so a successful call alone
256is not evidence of valid support. Never silently drop long-followed test subjects
257to obtain a score: define administrative truncation and recode late events as
258censored under a prespecified estimand if that is scientifically intended.
260Quantiles are an operational example, not a scientific default. Prefer
261prespecified meaningful horizons, then verify fold support. Do not select a grid
262because it maximizes a metric.
264The bundled evaluator rejects unsupported grids and shape/type confusion:
266```bash
267python skills/scikit-survival/scripts/evaluate_survival_metrics.py \
268 --input predictions.npz \
269 --output metrics-summary.json
270```
272Its NPZ contract is:
274- `train_event`, `train_time`
275- `test_event`, `test_time`
276- `times`
277- `risk`
278- optional `survival`
280Archives are loaded with `allow_pickle=False`, with compressed-file and total
281expanded-member bounds. The evaluator requires at least two horizons for the
282combined workflow; native AUC and Brier permit a single horizon, whereas IBS does not.

Safe time-grid construction

A conservative grid for jointly computing AUC, Uno C, and Brier metrics:

import numpy as np
from sksurv.nonparametric import CensoringDistributionEstimator

test_time = y_test["time"]
train_time = y_train["time"]

lower = np.quantile(test_time, 0.10)
upper = min(
    np.quantile(test_time, 0.80),
    np.nextafter(train_time.max(), -np.inf),
)
times = np.linspace(lower, upper, 50)

if not (test_time.min() < times[0] < times[-1] < test_time.max()):
    raise ValueError("grid is outside test follow-up")
if not test_time.max() < train_time.max():
    raise ValueError("test follow-up exceeds training support")

censoring = CensoringDistributionEstimator().fit(y_train)
if np.any(censoring.predict_proba(times) <= 0):
    raise ValueError("training censoring survival reaches zero on grid")
censoring.predict_ipcw(y_test)  # AUC needs positive support at all test event times
if not np.any(y_test["event"] & (test_time <= times[0])):
    raise ValueError("AUC has no observed cases at the first horizon")

This strict maximum-follow-up check is a helper policy, not an exact universal API restriction. Native Brier metrics also query censoring survival at all test times; zero weights may be suppressed by the implementation, so a successful call alone is not evidence of valid support. Never silently drop long-followed test subjects to obtain a score: define administrative truncation and recode late events as censored under a prespecified estimand if that is scientifically intended.

Quantiles are an operational example, not a scientific default. Prefer prespecified meaningful horizons, then verify fold support. Do not select a grid because it maximizes a metric.

The bundled evaluator rejects unsupported grids and shape/type confusion:

python skills/scikit-survival/scripts/evaluate_survival_metrics.py \
  --input predictions.npz \
  --output metrics-summary.json

Its NPZ contract is:

  • train_event, train_time
  • test_event, test_time
  • times
  • risk
  • optional survival

Archives are loaded with allow_pickle=False, with compressed-file and total expanded-member bounds. The evaluator requires at least two horizons for the combined workflow; native AUC and Brier permit a single horizon, whereas IBS does not.

Raw lines 222 to 283
Runs code python skills/scikit-survival/scripts/evaluate_survival_metrics.py :267
284## Scorer wrappers and model selection
286Survival estimators' default `.score()` is Harrell concordance and handles their
287own prediction direction. Discrimination wrappers below call raw `.predict()`;
288they do not reverse time-oriented IPCRidge, SVM-regression, or AFT-boosting output. For other targets,
289scikit-survival provides estimator wrappers:
291- `as_concordance_index_ipcw_scorer(estimator, tau=None, tied_tol=...)`
292- `as_cumulative_dynamic_auc_scorer(estimator, times, tied_tol=...)`
293- `as_integrated_brier_score_scorer(estimator, times)`
295Correct pattern:
297```python
298from sklearn.model_selection import GridSearchCV
299from sksurv.metrics import as_integrated_brier_score_scorer
301wrapped = as_integrated_brier_score_scorer(
302 estimator,
303 times=inner_times,
305search = GridSearchCV(
306 wrapped,
307 {"estimator__model__max_depth": [1, 2, 4]},
308 cv=inner_splits,
310search.fit(X_outer_train, y_outer_train)
311```
313The wrapper:
315- is the estimator supplied to `GridSearchCV`;
316- stores its fitted estimator in `estimator_`;
317- exposes nested parameters under `estimator__...`;
318- fits metric state, including training survival information, from each fit fold;
319- negates IBS so larger wrapper score remains better.
321Do not write `scoring=as_integrated_brier_score_scorer(times)`; the constructor
322requires an estimator.

Scorer wrappers and model selection

Survival estimators' default .score() is Harrell concordance and handles their own prediction direction. Discrimination wrappers below call raw .predict(); they do not reverse time-oriented IPCRidge, SVM-regression, or AFT-boosting output. For other targets, scikit-survival provides estimator wrappers:

  • as_concordance_index_ipcw_scorer(estimator, tau=None, tied_tol=...)
  • as_cumulative_dynamic_auc_scorer(estimator, times, tied_tol=...)
  • as_integrated_brier_score_scorer(estimator, times)

Correct pattern:

from sklearn.model_selection import GridSearchCV
from sksurv.metrics import as_integrated_brier_score_scorer

wrapped = as_integrated_brier_score_scorer(
    estimator,
    times=inner_times,
)
search = GridSearchCV(
    wrapped,
    {"estimator__model__max_depth": [1, 2, 4]},
    cv=inner_splits,
)
search.fit(X_outer_train, y_outer_train)

The wrapper:

  • is the estimator supplied to GridSearchCV;
  • stores its fitted estimator in estimator_;
  • exposes nested parameters under estimator__...;
  • fits metric state, including training survival information, from each fit fold;
  • negates IBS so larger wrapper score remains better.

Do not write scoring=as_integrated_brier_score_scorer(times); the constructor requires an estimator.

Raw lines 284 to 323
324## Nested CV protocol
326For tuned performance:
328```text
329for each outer split:
330 outer_train, outer_valid
331 for each inner split within outer_train:
332 fit preprocessing + model + censoring-dependent scorer state
333 select hyperparameters
334 refit selected pipeline on all outer_train
335 evaluate once on outer_valid using outer_train censoring distribution
336aggregate outer scores and uncertainty
337```
339Every fold needs its own valid `tau`/time grid. A single global grid derived from
340all outcome times leaks outer-validation support information and may fail when an
341outer training fold has shorter follow-up.
343After protocol evaluation, tune on all development data and evaluate once on an
344untouched final test set. Do not report the best inner-CV score as generalization
345performance.

Nested CV protocol

For tuned performance:

for each outer split:
    outer_train, outer_valid
    for each inner split within outer_train:
        fit preprocessing + model + censoring-dependent scorer state
        select hyperparameters
    refit selected pipeline on all outer_train
    evaluate once on outer_valid using outer_train censoring distribution
aggregate outer scores and uncertainty

Every fold needs its own valid tau/time grid. A single global grid derived from all outcome times leaks outer-validation support information and may fail when an outer training fold has shorter follow-up.

After protocol evaluation, tune on all development data and evaluate once on an untouched final test set. Do not report the best inner-CV score as generalization performance.

Raw lines 324 to 346
347## Competing risks
349If events have causes:
351- all-event risk combines causes and is not cause-specific discrimination;
352- treating other causes as censored defines a cause-specific hazard analysis;
353- a cause-specific CIF is an absolute probability accounting for all causes;
354- standard Brier/AUC functions here are documented for right-censored
355 single-event outcomes, not a complete competing-risk prediction evaluation.
357State event coding and use methods designed for the cause-specific estimand. See
358`competing-risks.md`.

Competing risks

If events have causes:

  • all-event risk combines causes and is not cause-specific discrimination;
  • treating other causes as censored defines a cause-specific hazard analysis;
  • a cause-specific CIF is an absolute probability accounting for all causes;
  • standard Brier/AUC functions here are documented for right-censored single-event outcomes, not a complete competing-risk prediction evaluation.

State event coding and use methods designed for the cause-specific estimand. See competing-risks.md.

Raw lines 347 to 359
360## Reporting checklist
362- split and nesting protocol;
363- event/censoring counts per evaluation set;
364- metric definition and score direction;
365- `tau` and exact time grid/range;
366- source of censoring weights;
367- prediction shape and whether values are risks or survival probabilities;
368- uncertainty across independent outer folds or bootstrap resamples;
369- calibration assessment separate from discrimination;
370- handling of competing causes;
371- no claim of clinical utility from metrics alone.

Reporting checklist

  • split and nesting protocol;
  • event/censoring counts per evaluation set;
  • metric definition and score direction;
  • tau and exact time grid/range;
  • source of censoring weights;
  • prediction shape and whether values are risks or survival probabilities;
  • uncertainty across independent outer folds or bootstrap resamples;
  • calibration assessment separate from discrimination;
  • handling of competing causes;
  • no claim of clinical utility from metrics alone.
Raw lines 360 to 372
373## Primary methodological literature
375- Harrell FE Jr, Califf RM, Pryor DB, Lee KL, Rosati RA. "Evaluating the
376 yield of medical tests." *JAMA* (1982).
377 [doi:10.1001/jama.1982.03320430047030](https://doi.org/10.1001/jama.1982.03320430047030)
378- Uno H, Cai T, Pencina MJ, D'Agostino RB, Wei LJ. "On the C-statistics for
379 evaluating overall adequacy of risk prediction procedures with censored
380 survival data." *Statistics in Medicine* (2011).
381 [doi:10.1002/sim.4154](https://doi.org/10.1002/sim.4154)
382- Heagerty PJ, Lumley T, Pepe MS. "Time-dependent ROC curves for censored
383 survival data and a diagnostic marker." *Biometrics* (2000).
384 [doi:10.1111/j.0006-341X.2000.00337.x](https://doi.org/10.1111/j.0006-341X.2000.00337.x)
385- Heagerty PJ, Zheng Y. "Survival model predictive accuracy and ROC curves."
386 *Biometrics* (2005).
387 [doi:10.1111/j.0006-341X.2005.030814.x](https://doi.org/10.1111/j.0006-341X.2005.030814.x)
388- Graf E, Schmoor C, Sauerbrei W, Schumacher M. "Assessment and comparison
389 of prognostic classification schemes for survival data."
390 *Statistics in Medicine* (1999).
391 [doi:10.1002/(SICI)1097-0258(19990915/30)18:17/18%3C2529::AID-SIM274%3E3.0.CO;2-5](https://doi.org/10.1002/%28SICI%291097-0258%2819990915/30%2918%3A17/18%3C2529%3A%3AAID-SIM274%3E3.0.CO%3B2-5)
392- Gerds TA, Schumacher M. "Consistent estimation of the expected Brier score
393 in general survival models with right-censored event times."
394 *Biometrical Journal* (2006).
395 [doi:10.1002/bimj.200610301](https://doi.org/10.1002/bimj.200610301)

Primary methodological literature

Raw lines 373 to 396
397## Official API sources
399Checked 2026-10-01:
401- [Evaluation user guide](https://scikit-survival.readthedocs.io/en/stable/user_guide/evaluating-survival-models.html)
402- [Metrics API index](https://scikit-survival.readthedocs.io/en/stable/api/metrics.html)
403- [IPCW concordance API](https://scikit-survival.readthedocs.io/en/stable/api/generated/sksurv.metrics.concordance_index_ipcw.html)
404- [Cumulative/dynamic AUC API](https://scikit-survival.readthedocs.io/en/stable/api/generated/sksurv.metrics.cumulative_dynamic_auc.html)
405- [Brier score API](https://scikit-survival.readthedocs.io/en/stable/api/generated/sksurv.metrics.brier_score.html)
406- [Integrated Brier score API](https://scikit-survival.readthedocs.io/en/stable/api/generated/sksurv.metrics.integrated_brier_score.html)
407- [IPCW scorer wrapper API](https://scikit-survival.readthedocs.io/en/stable/api/generated/sksurv.metrics.as_concordance_index_ipcw_scorer.html)