Survival performance - CyrilB1531/lodestar GitHub Wiki
Development build. This page describes
main, not a released package. The latest published Lodestar.Survival is 0.2.0 — read its documentation.
Performance — Lodestar.Survival
What Lodestar.Survival costs against the library a reader would otherwise reach for. How to read
a row, and what this page leaves out:
docs/guides/performance.md.
Aalen's additive model against lifelines (issue #1173)
Full method:
bench/README.md.
lifelines 0.30.3 on numpy 2.5.3 is the incumbent: no free .NET library fits the model. Machine: AMD
Ryzen 7 8700G w/ Radeon 780M Graphics, 1 CPU, 16 logical and 8 physical cores, .NET 10.0.12, under the
repository's machine lock on 2026-09-26: the C# side 16:22 to 16:23 UTC, the Python side at 16:23 UTC.
Milliseconds of processor time per call, best of five, four covariates.
| operation | 1,000 | 10,000 |
|---|---|---|
AalenAdditive.Fit |
5.02 / 278 (55.3) | 139 / 1,458 (10.5) |
Fit, weighted, both penalties |
5.00 / 280 (55.9) | 139 / 1,435 (10.3) |
PredictSurvivalFunction, 100 subjects |
0.577 / 0.931 (1.61) | 2.42 / 4.57 (1.89) |
Each cell is Lodestar / lifelines, and the ratio lifelines over Lodestar.
How it reads. Ahead on every row in processor time. lifelines spreads its products over BLAS threads, so on the elapsed clock its fit is 2.6× behind at 10,000 rather than 10×, and its prediction at 10,000 is ahead, 1.14 ms against 2.21: the prediction is a product and an exponential per subject and event time, which numpy vectorises and this computes one at a time. Both fits rebuild the product of the covariates over the subjects at risk at every event time, so the cost grows with events times subjects on both sides.
Parametric survival models against lifelines (issue #1172)
Full method:
bench/README.md.
lifelines 0.30.3 on numpy 2.5.3 is the incumbent: no free .NET library fits these models. Machine: AMD
Ryzen 7 8700G w/ Radeon 780M Graphics, 1 CPU, 16 logical and 8 physical cores, .NET 10.0.12, under the
repository's machine lock on 2026-09-26: the Python side 12:48 to 12:52 UTC, the C# side 12:57 to 12:59
UTC. Milliseconds of processor time per call, best of five, four covariates for the regressions, each
fit at lifelines' defaults as a caller runs it — which stop short of the maximum this reaches.
| operation | 1,000 | 10,000 |
|---|---|---|
ParametricSurvival.Fit, Weibull |
1.84 / 25.2 (13.7) | 18.4 / 30.0 (1.63) |
FitLeftCensored, log-logistic |
3.69 / 36.7 (9.95) | 40.9 / 69.4 (1.70) |
FitIntervalCensored, log-normal |
3.37 / 68.3 (20.3) | 34.7 / 142 (4.10) |
Fit, generalized gamma |
37.4 / 429 (11.5) | 481 / 1,130 (2.35) |
AcceleratedFailureTime.Fit, Weibull |
4.04 / 49.6 (12.3) | 40.4 / 58.3 (1.44) |
Fit, log-normal, ridge 0.1, robust variance |
6.70 / 1,897 (283) | 87.4 / 18,108 (207) |
FitIntervalCensored, log-logistic |
6.72 / 77.0 (11.5) | 62.5 / 113 (1.81) |
BreslowFlemingHarrington.Estimate |
0.087 / 2.81 (32.4) | 1.62 / 3.81 (2.36) |
KaplanMeier.EstimateLeftCensored |
0.054 / 3.38 (63.2) | 0.647 / 4.48 (6.92) |
Each cell is Lodestar / lifelines, and the ratio lifelines over Lodestar.
How it reads. Ahead on every row, by less at 10,000: lifelines' likelihoods are vectorised numpy whose cost barely grows from 1,000 to 10,000, while each Newton step here is a pass over the subjects. The regressions differentiate each subject in its two linear predictors alone and carry the result to the coefficients, so a step costs the square of the coefficients once per subject, not per operation. The robust variance is the outlier because lifelines differentiates each subject separately through autograd; the generalized gamma pays here for the incomplete gamma evaluated at five shapes per term.
The extended Cox model against lifelines (issue #1171)
Full method:
bench/README.md.
lifelines 0.30.3 on numpy 2.5.3 is the incumbent: no free .NET library fits a Cox model. Machine: AMD
Ryzen 7 8700G w/ Radeon 780M Graphics, 1 CPU, 16 logical and 8 physical cores, .NET 10.0.12, under the
repository's machine lock on 2026-09-26: the C# side 10:18 to 10:19 UTC, the Python side 10:19 to 10:21
UTC. Milliseconds of processor time per call, best of five, four covariates, each fit at lifelines'
defaults as a caller runs it.
| operation | 1,000 | 10,000 |
|---|---|---|
CoxProportionalHazards.Fit, three strata, weighted |
0.493 / 56.6 (115) | 5.74 / 316 (55.1) |
Fit, ridge 0.1, robust variance |
0.551 / 54.7 (99.3) | 6.79 / 568 (83.7) |
Fit, lasso 0.05 |
4.00 / 480 (120) | 36.8 / 3,155 (85.8) |
TestProportionalHazards, rank |
0.081 / 10.3 (126) | 1.43 / 98.5 (69.0) |
PredictSurvivalFunction, 100 subjects × 10 times |
0.020 / 0.790 (40.0) | 0.021 / 0.786 (37.6) |
CoxTimeVarying.Fit, two intervals per subject |
40.0 / 159 (3.98) | 1,563 / 2,802 (1.79) |
Each cell is Lodestar / lifelines, and the ratio lifelines over Lodestar.
How it reads. Ahead on every row. The time-varying fit is the close one: at each event time both sides rebuild the risk set from every interval, lifelines' algorithm and this one's, so the cost grows with events times intervals on both sides and the margin is only the per-interval arithmetic. The lasso is lifelines' own loop, reproduced step for step, so both sides take the same number of steps; the robust variance is linear here where lifelines' score residuals are quadratic in the subjects.
The log-rank family, the restricted mean and the concordance index against lifelines (issue #1170)
Full method:
bench/README.md.
No .NET library computes any of these, so lifelines 0.30.3 on numpy 2.5.3 is the incumbent. Machine:
AMD Ryzen 7 8700G w/ Radeon 780M Graphics, 1 CPU, 16 logical and 8 physical cores, .NET 10.0.12,
under the repository's machine lock on 2026-09-26: the Python side 08:05 to 08:07 UTC, the C# side
08:07 to 08:10 UTC. Milliseconds of processor time per call, best of five; each operation includes
the fit it reads.
| operation | 1,000 | 10,000 | 100,000 |
|---|---|---|---|
LogRank.Test, Wilcoxon, weighted |
0.014 / 5.87 (413) | 0.157 / 6.92 (44.1) | 2.76 / 12.9 (4.68) |
LogRank.Test, Fleming-Harrington |
0.020 / 9.05 (447) | 0.210 / 11.3 (54.0) | 2.68 / 20.8 (7.77) |
LogRank.MultiGroup, five groups |
0.067 / 11.9 (179) | 1.47 / 20.2 (13.8) | 6.86 / 32.0 (4.67) |
LogRank.Pairwise, ten pairs |
0.175 / 60.1 (343) | 2.94 / 71.8 (24.4) | 29.2 / 129 (4.42) |
KaplanMeier.RestrictedMean, with the fit |
0.054 / 470 (8,722) | 1.13 / 522 (464) | 5.95 / 193 (32.5) |
KaplanMeier.CompareAt, with two fits |
0.022 / 6.29 (284) | 0.215 / 7.87 (36.7) | 3.30 / 15.8 (4.79) |
Concordance.Index |
0.031 / 3.99 (130) | 1.45 / 47.9 (33.0) | 18.5 / 414 (22.3) |
Each cell is Lodestar / lifelines, and the ratio lifelines over Lodestar.
How it reads. Ahead on every row, on both clocks: lifelines runs single-threaded here, so its elapsed and processor times agree. The small sizes measure lifelines' pandas overhead more than any arithmetic. The restricted mean is the outlier because lifelines integrates the second moment by adaptive quadrature over a step function, which is both the cost and the 1.5 % divergence the reference page records; this sums the steps.