Skill Tracer
Skills › Scientific Agent Skills › scikit-survival › svm-models.md

svm-models.md

291 lines · skills/scikit-survival/references/svm-models.md at 5f2bc03

Open on GitHub
1# Survival support vector machines
2
3Verified for scikit-survival 0.28.0 on 2026-10-01.
4

Survival support vector machines

Verified for scikit-survival 0.28.0 on 2026-10-01.

Raw lines 1 to 4
5## What survival SVMs predict
6
7Survival SVMs optimize ranking, regression, or a mixture. They generally return a
8scalar score, not a baseline survival function or cumulative hazard function.
9Therefore:
11- use concordance or cumulative/dynamic AUC only after confirming score direction;
12- do not pass SVM output to Brier metrics;
13- do not convert a margin to event probability without a separately validated
14 calibration model and protocol.

What survival SVMs predict

Survival SVMs optimize ranking, regression, or a mixture. They generally return a scalar score, not a baseline survival function or cumulative hazard function. Therefore:

  • use concordance or cumulative/dynamic AUC only after confirming score direction;
  • do not pass SVM output to Brier metrics;
  • do not convert a margin to event probability without a separately validated calibration model and protocol.
Raw lines 5 to 15
16## Fast linear survival SVM
18```python
19from sklearn.pipeline import make_pipeline
20from sklearn.preprocessing import StandardScaler
21from sksurv.svm import FastSurvivalSVM
23model = make_pipeline(
24 StandardScaler(),
25 FastSurvivalSVM(
26 alpha=1.0,
27 rank_ratio=1.0,
28 max_iter=1000,
29 tol=1e-5,
30 random_state=20260723,
31 ),
33model.fit(X_train, y_train)
34risk = model.predict(X_test)
35```
37Current signature:
39```text
40FastSurvivalSVM(
41 alpha=1, *,
42 rank_ratio=1.0,
43 fit_intercept=False,
44 max_iter=20,
45 verbose=False,
46 tol=None,
47 optimizer=None,
48 random_state=None,
49 timeit=False,
51```
53Key semantics:
55- `rank_ratio=1.0`: ranking-only objective; higher predictions indicate shorter
56 survival/higher event risk.
57- `0 < rank_ratio < 1`: mixed ranking and regression.
58- `rank_ratio=0.0`: regression-only objective.
59- When `rank_ratio < 1`, `predict()` exponentiates the log-time predictor and returns
60 original-time values: lower prediction means shorter survival. For a metric requiring
61 higher event risk, use `-prediction` and document the conversion.
62- `alpha` weights the data-fit/ranking objective relative to the penalty, so larger
63 values mean less regularization; tune it within inner CV.
65Do not use an arbitrary sign simply because a C-index improves. The sign follows
66the model objective and target interpretation.

Fast linear survival SVM

from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
from sksurv.svm import FastSurvivalSVM

model = make_pipeline(
    StandardScaler(),
    FastSurvivalSVM(
        alpha=1.0,
        rank_ratio=1.0,
        max_iter=1000,
        tol=1e-5,
        random_state=20260723,
    ),
)
model.fit(X_train, y_train)
risk = model.predict(X_test)

Current signature:

FastSurvivalSVM(
    alpha=1, *,
    rank_ratio=1.0,
    fit_intercept=False,
    max_iter=20,
    verbose=False,
    tol=None,
    optimizer=None,
    random_state=None,
    timeit=False,
)

Key semantics:

  • rank_ratio=1.0: ranking-only objective; higher predictions indicate shorter survival/higher event risk.
  • 0 < rank_ratio < 1: mixed ranking and regression.
  • rank_ratio=0.0: regression-only objective.
  • When rank_ratio < 1, predict() exponentiates the log-time predictor and returns original-time values: lower prediction means shorter survival. For a metric requiring higher event risk, use -prediction and document the conversion.
  • alpha weights the data-fit/ranking objective relative to the penalty, so larger values mean less regularization; tune it within inner CV.

Do not use an arbitrary sign simply because a C-index improves. The sign follows the model objective and target interpretation.

Raw lines 16 to 67
68## Fast kernel survival SVM
70```python
71from sksurv.svm import FastKernelSurvivalSVM
73model = FastKernelSurvivalSVM(
74 alpha=1.0,
75 rank_ratio=1.0,
76 kernel="rbf",
77 gamma=0.05,
78 max_iter=100,
79 tol=1e-5,
80 random_state=20260723,
82model.fit(X_train_scaled, y_train)
83risk = model.predict(X_test_scaled)
84```
86Current signature:
88```text
89FastKernelSurvivalSVM(
90 alpha=1, *,
91 rank_ratio=1.0,
92 fit_intercept=False,
93 kernel="rbf",
94 gamma=None,
95 degree=3,
96 coef0=1,
97 kernel_params=None,
98 max_iter=20,
99 verbose=False,
100 tol=None,
101 optimizer=None,
102 random_state=None,
103 timeit=False,
105```
107Kernel choices follow scikit-learn pairwise-kernel behavior, including `"linear"`,
108`"poly"`, `"rbf"`, `"sigmoid"`, callable kernels, and `"precomputed"` where
109supported. Do not copy older examples that use `gamma="scale"` without checking
110the current API; the current scikit-survival parameter default is `None`.
112Kernel fitting and prediction depend on training rows and can require
113quadratic-size kernel matrices. Enforce row/memory bounds before fitting.

Fast kernel survival SVM

from sksurv.svm import FastKernelSurvivalSVM

model = FastKernelSurvivalSVM(
    alpha=1.0,
    rank_ratio=1.0,
    kernel="rbf",
    gamma=0.05,
    max_iter=100,
    tol=1e-5,
    random_state=20260723,
)
model.fit(X_train_scaled, y_train)
risk = model.predict(X_test_scaled)

Current signature:

FastKernelSurvivalSVM(
    alpha=1, *,
    rank_ratio=1.0,
    fit_intercept=False,
    kernel="rbf",
    gamma=None,
    degree=3,
    coef0=1,
    kernel_params=None,
    max_iter=20,
    verbose=False,
    tol=None,
    optimizer=None,
    random_state=None,
    timeit=False,
)

Kernel choices follow scikit-learn pairwise-kernel behavior, including "linear", "poly", "rbf", "sigmoid", callable kernels, and "precomputed" where supported. Do not copy older examples that use gamma="scale" without checking the current API; the current scikit-survival parameter default is None.

Kernel fitting and prediction depend on training rows and can require quadratic-size kernel matrices. Enforce row/memory bounds before fitting.

Raw lines 68 to 114
115## Hinge, Minlip, and naive formulations
117Current additional estimators:
119- `HingeLossSurvivalSVM(alpha=1.0, solver="ecos", kernel="linear", pairs="all", ...)`
120- `MinlipSurvivalAnalysis(alpha=1.0, solver="ecos", kernel="linear",
121 pairs="nearest", ...)`
122- `NaiveSurvivalSVM(penalty="l2", loss="squared_hinge", dual=False,
123 alpha=1.0, ...)`
125Important current differences:
127- `HingeLossSurvivalSVM` and `MinlipSurvivalAnalysis` do not have a
128 `random_state` constructor parameter.
129- Their convex optimization defaults to the ECOS solver.
130- Pair construction and kernel matrices can become expensive.
131- `NaiveSurvivalSVM` uses a linear-SVM-style formulation and is mainly useful for
132 small comparisons; it is not the fast implementation.
134Use the exact current signature rather than transferring parameters across SVM
135classes.

Hinge, Minlip, and naive formulations

Current additional estimators:

  • HingeLossSurvivalSVM(alpha=1.0, solver="ecos", kernel="linear", pairs="all", ...)
  • MinlipSurvivalAnalysis(alpha=1.0, solver="ecos", kernel="linear", pairs="nearest", ...)
  • NaiveSurvivalSVM(penalty="l2", loss="squared_hinge", dual=False, alpha=1.0, ...)

Important current differences:

  • HingeLossSurvivalSVM and MinlipSurvivalAnalysis do not have a random_state constructor parameter.
  • Their convex optimization defaults to the ECOS solver.
  • Pair construction and kernel matrices can become expensive.
  • NaiveSurvivalSVM uses a linear-SVM-style formulation and is mainly useful for small comparisons; it is not the fast implementation.

Use the exact current signature rather than transferring parameters across SVM classes.

Raw lines 115 to 136
137## Scaling and explicit preprocessing
139Scale continuous features and fit scaling only on training folds:
141```python
142from sklearn.compose import ColumnTransformer
143from sklearn.impute import SimpleImputer
144from sklearn.pipeline import make_pipeline
145from sklearn.preprocessing import OneHotEncoder, StandardScaler
147preprocess = ColumnTransformer(
148 [
149 (
150 "num",
151 make_pipeline(SimpleImputer(strategy="median"), StandardScaler()),
152 numeric_columns,
153 ),
154 (
155 "cat",
156 make_pipeline(
157 SimpleImputer(strategy="most_frequent"),
158 OneHotEncoder(
159 drop="first",
160 handle_unknown="ignore",
161 sparse_output=False,
162 ),
163 ),
164 categorical_columns,
165 ),
166 ],
167 sparse_threshold=0.0,
169model = make_pipeline(
170 preprocess,
171 FastSurvivalSVM(rank_ratio=1.0, random_state=20260723),
173```
175Do not call `StandardScaler.fit_transform(X)` before cross-validation. Keeping it
176inside the pipeline makes every inner and outer fold independent.

Scaling and explicit preprocessing

Scale continuous features and fit scaling only on training folds:

from sklearn.compose import ColumnTransformer
from sklearn.impute import SimpleImputer
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import OneHotEncoder, StandardScaler

preprocess = ColumnTransformer(
    [
        (
            "num",
            make_pipeline(SimpleImputer(strategy="median"), StandardScaler()),
            numeric_columns,
        ),
        (
            "cat",
            make_pipeline(
                SimpleImputer(strategy="most_frequent"),
                OneHotEncoder(
                    drop="first",
                    handle_unknown="ignore",
                    sparse_output=False,
                ),
            ),
            categorical_columns,
        ),
    ],
    sparse_threshold=0.0,
)
model = make_pipeline(
    preprocess,
    FastSurvivalSVM(rank_ratio=1.0, random_state=20260723),
)

Do not call StandardScaler.fit_transform(X) before cross-validation. Keeping it inside the pipeline makes every inner and outer fold independent.

Raw lines 137 to 177
178## Kernel preprocessing
180For `"precomputed"`, training input must be a square
181`(n_train, n_train)` kernel matrix; test input must be
182`(n_test, n_train)` with columns in the identical training order.
184`sksurv.kernels.ClinicalKernelTransform` and `clinical_kernel()` support mixed
185continuous, ordinal, and nominal DataFrame columns, including pandas/Polars in
1860.28. They do not accept an ad hoc list of `(clinical, molecular)` tuples as a
187special API. Fit the transform on a clearly typed training DataFrame or explicitly
188precompute the kernel:
190```python
191from sksurv.kernels import ClinicalKernelTransform
192from sksurv.svm import FastKernelSurvivalSVM
194kernel = ClinicalKernelTransform()
195kernel_train = kernel.fit_transform(X_train_typed)
196kernel_test = kernel.transform(X_test_typed)
198model = FastKernelSurvivalSVM(
199 kernel="precomputed",
200 rank_ratio=1.0,
201 random_state=20260723,
203model.fit(kernel_train, y_train)
204risk = model.predict(kernel_test)
205```
207The one-shot `clinical_kernel(X_test, X_train)` infers numeric ranges from both
208arguments, changing normalization with the test cohort. Prefer the fitted transform
209above. The released one-shot Cython routine also allocates its range buffer by
210row count while writing one value per numeric feature: avoid that routine when
211numeric features outnumber rows (source finding; unsafe case not executed).
212Put `ClinicalKernelTransform()` inside the pipeline for CV so its ranges
213and reference rows are learned afresh in every fold. Out-of-training-range values
214can produce negative similarities in the native transform; inspect support and
215define any clipping/extrapolation policy before evaluating.
217Any data-dependent kernel typing, scaling, or parameter choice belongs inside the
218training/CV protocol.

Kernel preprocessing

For "precomputed", training input must be a square (n_train, n_train) kernel matrix; test input must be (n_test, n_train) with columns in the identical training order.

sksurv.kernels.ClinicalKernelTransform and clinical_kernel() support mixed continuous, ordinal, and nominal DataFrame columns, including pandas/Polars in 0.28. They do not accept an ad hoc list of (clinical, molecular) tuples as a special API. Fit the transform on a clearly typed training DataFrame or explicitly precompute the kernel:

from sksurv.kernels import ClinicalKernelTransform
from sksurv.svm import FastKernelSurvivalSVM

kernel = ClinicalKernelTransform()
kernel_train = kernel.fit_transform(X_train_typed)
kernel_test = kernel.transform(X_test_typed)

model = FastKernelSurvivalSVM(
    kernel="precomputed",
    rank_ratio=1.0,
    random_state=20260723,
)
model.fit(kernel_train, y_train)
risk = model.predict(kernel_test)

The one-shot clinical_kernel(X_test, X_train) infers numeric ranges from both arguments, changing normalization with the test cohort. Prefer the fitted transform above. The released one-shot Cython routine also allocates its range buffer by row count while writing one value per numeric feature: avoid that routine when numeric features outnumber rows (source finding; unsafe case not executed). Put ClinicalKernelTransform() inside the pipeline for CV so its ranges and reference rows are learned afresh in every fold. Out-of-training-range values can produce negative similarities in the native transform; inspect support and define any clipping/extrapolation policy before evaluating.

Any data-dependent kernel typing, scaling, or parameter choice belongs inside the training/CV protocol.

Raw lines 178 to 219
220## Nested tuning
222Tune at least `alpha`; for kernel models also tune kernel and its parameters.
223Keep the grid bounded:
225```python
226from sklearn.model_selection import GridSearchCV
228search = GridSearchCV(
229 pipeline,
230 {
231 "fastkernelsurvivalsvm__alpha": [0.1, 1.0, 10.0],
232 "fastkernelsurvivalsvm__gamma": [0.01, 0.05, 0.2],
233 },
234 cv=inner_splits,
235 error_score="raise",
236 n_jobs=1,
238search.fit(X_outer_train, y_outer_train)
239```
241The actual parameter prefix depends on pipeline step names. Run this search within
242each outer fold for a nested-CV performance estimate. Do not:
244- fit a scaler or kernel transform before the outer split;
245- select the sign, kernel, or horizon on outer-validation results;
246- reuse the final test set to choose `alpha`/`gamma`;
247- compare SVM Brier scores, because SVMs do not output survival probabilities.
249For IPCW metrics, fit the censoring distribution on the corresponding outer
250training outcomes and keep the time grid within that fold's support.

Nested tuning

Tune at least alpha; for kernel models also tune kernel and its parameters. Keep the grid bounded:

from sklearn.model_selection import GridSearchCV

search = GridSearchCV(
    pipeline,
    {
        "fastkernelsurvivalsvm__alpha": [0.1, 1.0, 10.0],
        "fastkernelsurvivalsvm__gamma": [0.01, 0.05, 0.2],
    },
    cv=inner_splits,
    error_score="raise",
    n_jobs=1,
)
search.fit(X_outer_train, y_outer_train)

The actual parameter prefix depends on pipeline step names. Run this search within each outer fold for a nested-CV performance estimate. Do not:

  • fit a scaler or kernel transform before the outer split;
  • select the sign, kernel, or horizon on outer-validation results;
  • reuse the final test set to choose alpha/gamma;
  • compare SVM Brier scores, because SVMs do not output survival probabilities.

For IPCW metrics, fit the censoring distribution on the corresponding outer training outcomes and keep the time grid within that fold's support.

Raw lines 220 to 251
252## Choosing an SVM candidate
254- Linear ranking objective: a scalable margin-based discrimination baseline.
255- Kernel ranking objective: nonlinear relationships when row count permits.
256- Mixed/regression objective: time-oriented score, with different sign semantics.
257- Need absolute survival probability: choose a model with
258 `predict_survival_function()` or add a separately validated calibration stage.
259- Need coefficient/hazard-ratio interpretation: use an appropriate Cox model,
260 not an SVM margin.
262These are capability distinctions, not guarantees of performance.

Choosing an SVM candidate

  • Linear ranking objective: a scalable margin-based discrimination baseline.
  • Kernel ranking objective: nonlinear relationships when row count permits.
  • Mixed/regression objective: time-oriented score, with different sign semantics.
  • Need absolute survival probability: choose a model with predict_survival_function() or add a separately validated calibration stage.
  • Need coefficient/hazard-ratio interpretation: use an appropriate Cox model, not an SVM margin.

These are capability distinctions, not guarantees of performance.

Raw lines 252 to 263
264## Interpretation
266SVM margins are arbitrary-scale predictions. A high C-index or dynamic AUC says
267that orderings discriminate under the chosen censoring estimator and horizon; it
268does not establish:
270- probability calibration;
271- causal or treatment effects;
272- transportability;
273- subgroup fairness;
274- clinical or decision utility.
276Report optimization convergence, score direction, kernel, preprocessing, tuning
277resamples, and censoring assumptions.

Interpretation

SVM margins are arbitrary-scale predictions. A high C-index or dynamic AUC says that orderings discriminate under the chosen censoring estimator and horizon; it does not establish:

  • probability calibration;
  • causal or treatment effects;
  • transportability;
  • subgroup fairness;
  • clinical or decision utility.

Report optimization convergence, score direction, kernel, preprocessing, tuning resamples, and censoring assumptions.

Raw lines 264 to 278
279## Sources
281Official sources checked 2026-10-01:
283- [Released clinical-kernel implementation](https://github.com/sebp/scikit-survival/blob/v0.28.0/sksurv/kernels/clinical.py) and [Cython ranges](https://github.com/sebp/scikit-survival/blob/v0.28.0/sksurv/kernels/_clinical_kernel.pyx).
285- [Survival SVM user guide](https://scikit-survival.readthedocs.io/en/stable/user_guide/survival-svm.html)
286- [FastSurvivalSVM API](https://scikit-survival.readthedocs.io/en/stable/api/generated/sksurv.svm.FastSurvivalSVM.html)
287- [FastKernelSurvivalSVM API](https://scikit-survival.readthedocs.io/en/stable/api/generated/sksurv.svm.FastKernelSurvivalSVM.html)
288- [HingeLossSurvivalSVM API](https://scikit-survival.readthedocs.io/en/stable/api/generated/sksurv.svm.HingeLossSurvivalSVM.html)
289- [MinlipSurvivalAnalysis API](https://scikit-survival.readthedocs.io/en/stable/api/generated/sksurv.svm.MinlipSurvivalAnalysis.html)
290- [NaiveSurvivalSVM API](https://scikit-survival.readthedocs.io/en/stable/api/generated/sksurv.svm.NaiveSurvivalSVM.html)
291- [Clinical kernels API](https://scikit-survival.readthedocs.io/en/stable/api/kernels.html)