How to Handle Censored Data with scikit-survival for Time-to-Event Modeling

scikit-survival extends scikit-learn with survival-analysis primitives that natively respect censoring through structured Surv arrays, IPCW-weighted metrics, and seamless cross-validation integration.

Time-to-event modeling requires specialized techniques when observations are incomplete—a scenario known as censoring. This guide demonstrates how to handle censored data with scikit-survival for time-to-event modeling using the complete workflow documented in the K-Dense-AI/scientific-agent-skills repository.

Representing Censored Outcomes with Surv Objects

The foundation of censor-aware modeling is proper data encoding. In scientific-skills/scikit-survival/references/data-handling.md, the repository specifies that survival outcomes must be stored as structured arrays created with sksurv.util.Sv. This object stores boolean event indicators alongside observed times, automatically flagging censored records where event=False.

Right-censored data—where the event has not occurred by the observation end time—represents the most common scenario. The Surv constructor handles right-, left-, and interval-censored observations uniformly, ensuring all downstream estimators receive properly formatted targets.

Fitting Censor-Aware Estimators

All scikit-survival estimators inherit from scikit-learn's BaseEstimator, enabling immediate compatibility with pipelines, GridSearchCV, and stratified cross-validation. As detailed in scientific-skills/scikit-survival/SKILL.md, the library provides multiple model families:

  • Cox Proportional Hazards (CoxPHSurvivalAnalysis) for semiparametric regression
  • Penalized Cox (CoxnetSurvivalAnalysis) for high-dimensional data
  • Random Survival Forests (RandomSurvivalForest) for non-linear relationships
  • Gradient Boosting and Survival SVM alternatives

Basic Cox Model with Right-Censored Data

The following pipeline demonstrates loading data, preserving censoring rates during splitting, and fitting a Cox model:

from sksurv.datasets import load_breast_cancer
from sksurv.util import Surv
from sksurv.linear_model import CoxPHSurvivalAnalysis
from sksurv.metrics import concordance_index_ipcw
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler

# Load built-in dataset (X=features, y=structured array with event/time)

X, y = load_breast_cancer()

# Stratify on event indicator to preserve censoring rates

X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42, stratify=y["event"]
)

# Standardize features (critical for Cox and SVM stability)

scaler = StandardScaler()
X_train_std = scaler.fit_transform(X_train)
X_test_std = scaler.transform(X_test)

# Fit Cox proportional-hazards model

cox = CoxPHSurvivalAnalysis()
cox.fit(X_train_std, y_train)

# Predict risk scores (higher values indicate higher hazard)

risk_scores = cox.predict(X_test_std)

# Evaluate with Uno's IPCW C-index (robust to censoring)

c_index = concordance_index_ipcw(y_train, y_test, risk_scores)[0]
print(f"Uno C-index: {c_index:.3f}")

Regularization for High-Dimensional Data

For datasets with many features, elastic-net regularization prevents overfitting while handling censored observations. The CoxnetSurvivalAnalysis class implements this via the alpha_min_ratio parameter, as referenced in scientific-skills/scikit-survival/references/cox-models.md:

import numpy as np
from sksurv.linear_model import CoxnetSurvivalAnalysis
from sksurv.metrics import as_concordance_index_ipcw_scorer
from sklearn.model_selection import GridSearchCV

# Configure penalized Cox with Lasso-like sparsity (l1_ratio=0.9)

coxnet = CoxnetSurvivalAnalysis(l1_ratio=0.9)

# Grid search over regularization path

param_grid = {"alpha_min_ratio": [0.01, 0.001, 0.0001]}
grid = GridSearchCV(
    coxnet,
    param_grid,
    scoring=as_concordance_index_ipcw_scorer(),
    cv=5,
    n_jobs=-1,
)
grid.fit(X, y)

# Extract non-zero coefficients

best_model = grid.best_estimator_
selected_features = np.where(best_model.coef_ != 0)[0]
print(f"Selected {len(selected_features)} features")

Tree-Based Survival Models

Random Survival Forests partition the data based on log-rank statistics that account for censoring, making them robust to non-linear relationships without proportional hazards assumptions.

from sksurv.ensemble import RandomSurvivalForest
from sksurv.metrics import as_concordance_index_ipcw_scorer
from sklearn.model_selection import cross_val_score

# Configure RSF with censor-aware splitting criteria

rsf = RandomSurvivalForest(
    n_estimators=200,
    min_samples_split=10,
    random_state=42,
)

# Cross-validated Uno C-index

scores = cross_val_score(
    rsf,
    X,
    y,
    cv=5,
    scoring=as_concordance_index_ipcw_scorer(),
)
print(f"Mean Uno C-index: {scores.mean():.3f}")

Evaluating Models with Censor-Aware Metrics

Traditional regression metrics like Mean Squared Error are inappropriate for censored targets because they ignore whether an observation is fully observed. According to scientific-skills/scikit-survival/references/evaluation-metrics.md, scikit-survival provides specific solutions:

Harrell's C-index vs. Uno's IPCW C-index

Harrell's C-index (concordance_index_censored) measures concordance between predicted risk scores and actual survival times but becomes optimistic when censoring exceeds 40%. Uno's IPCW C-index (concordance_index_ipcw) applies inverse probability of censoring weighting to correct this bias, making it the preferred choice for heavily censored datasets.

Integrated Brier Score and Time-Dependent AUC

The Integrated Brier Score combines discrimination and calibration assessment across all time points, while time-dependent AUC evaluates discrimination at specific prediction horizons. Both metrics properly handle censored test subjects through weighting schemes defined in the evaluation module.

Competing Risks Considerations

When multiple mutually exclusive event types exist—such as different causes of failure—standard survival analysis treats competing events as censored, biasing estimates. The repository's scientific-skills/scikit-survival/references/competing-risks.md documents cumulative_incidence_competing_risks, which provides cause-specific probability estimates rather than treating other events as censored.

Summary

  • Encode outcomes using sksurv.util.Surv to ensure censored observations are properly flagged with event=False.

  • Select metrics carefully: Use Uno's IPCW C-index instead of Harrell's when censoring exceeds 40%, and consider the Integrated Brier Score for comprehensive model assessment.

  • Leverage scikit-learn compatibility: All estimators work with GridSearchCV, pipelines, and cross-validation through standardized fit and predict interfaces.

  • Account for competing risks: Use cumulative incidence functions when multiple exclusive event types are present, as documented in the competing-risks reference.

Frequently Asked Questions

What is the difference between right-censored and left-censored data in scikit-survival?

Right-censored observations occur when the event happens after the observation period ends (the most common scenario), while left-censored observations occur when the event is known to have happened before the observation started. scikit-survival handles both through the Surv object's flexible encoding, though most clinical datasets use right-censoring exclusively.

Why can't I use standard ROC AUC for survival models?

Standard ROC AUC assumes fully observed binary outcomes, whereas survival data contains continuous time-to-event information mixed with censored observations. Time-dependent AUC metrics in scikit-survival extend ROC analysis to survival settings by evaluating discrimination at specific time horizons while properly weighting censored subjects through IPCW methods.

How does IPCW correct for bias in censored data evaluation?

Inverse Probability of Censoring Weighting (IPCW) assigns higher weights to observed events that had higher probability of being censored, effectively rebalancing the evaluation to represent what would have been observed without censoring. This prevents the optimistic bias that occurs when Harrell's C-index ignores censored subjects that might have had discordant rankings.

When should I use Random Survival Forests instead of Cox models?

Use Random Survival Forests when your data violates the proportional hazards assumption (where hazard ratios change over time) or contains complex non-linear interactions that parametric models cannot capture. Cox models provide interpretable hazard ratios and work well when proportional hazards hold, while RSFs require less assumptions but sacrifice some interpretability for predictive power.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →