Benchmarks

February 20, 2026 ยท View on GitHub

Benchmarking of implementations of Firth-penalized logistic regression and Cox regression.

Environment

OSPop!_OS 24.04 LTS
CPUAMD Ryzen 5 5600X 6-Core Processor
Python3.12.12
NumPy2.3.5
SciPy1.16.3
Numba0.64.0
R4.5.2

Firth Logistic Regression

Comparison of firthmodels, R brglm2, and R logistf for Firth-penalized logistic regression.

Libraries Compared

LibraryVersionBLAS
firthmodels0.7.2/usr/lib/x86_64-linux-gnu/openblas-pthread/ (openblas 0.3.26)
brglm21.0.1/usr/lib/x86_64-linux-gnu/openblas-pthread/libblas.so.3
logistf1.26.1/usr/lib/x86_64-linux-gnu/openblas-pthread/libblas.so.3

Configuration

ParameterValue
Observations (n)1,000
Event rate20%
Features (k)5, 10, 15, 20, 25, 30, 35, 40, 45, 50
Runs per config20
Solver max_iter50
Solver tolerance1e-06

brglm2 runs with check_aliasing=FALSE since the benchmark data is guaranteed full rank.

All implementations agree within chosen tolerance (coefficients 1e-06, CIs 1e-06, p-values 1e-06).

Results

Logistic benchmark scaling plot

Fit Only

Time to fit the model and perform Wald inference. Values are minimum time across runs in milliseconds.

kfirthmodels
(numba)
firthmodels
(numpy)
brglm2
(AS-mean)
brglm2
(MPL_Jeffreys)
logistf
50.51.44.24.22.0
101.21.97.97.24.3
151.21.98.28.27.6
201.52.39.39.415.7
251.82.711.711.724.2
302.12.912.612.930.2
352.33.414.914.842.0
402.83.816.916.852.7
453.94.618.619.870.3
504.55.823.924.286.0

Full Workflow (Fit + LRT + Profile CI)

Time to fit the model, compute penalized likelihood ratio test p-values for all coefficients, and profile likelihood confidence intervals.

kfirthmodels
(numba)
firthmodels
(numpy)
logistf
54.910.613.6
1021.043.172.1
1532.668.1157.6
2059.6109.7452.6
2598.5175.4931.5
30131.6226.11350.4
35184.0312.72322.4
40237.0379.73334.4
45358.4519.74692.8
50490.5700.56501.0

Firth Cox Proportional Hazards

Comparison of firthmodels and coxphf for Firth-penalized Cox proportional hazards regression.

Libraries Compared

LibraryVersionBLAS
firthmodels0.7.2/usr/lib/x86_64-linux-gnu/openblas-pthread/ (openblas 0.3.26)
coxphf1.13.4/usr/lib/x86_64-linux-gnu/openblas-pthread/libblas.so.3

Configuration

ParameterValue
Observations (n)500
Event rate20%
Features (k)5, 10, 15, 20, 25, 30
Runs per config10
Solver max_iter50
Solver xtol1e-06
Solver gtol0.0001

All implementations agree within chosen tolerance (coefficients 1e-06, CIs 1e-06, p-values 1e-06).

Results

Cox benchmark scaling plot

Fit Only

Time to fit the model and perform Wald inference. Values are minimum time across runs in milliseconds.

kfirthmodels
(numba)
firthmodels
(numpy)
coxphf
51.84.33.5
101.85.522.2
152.27.149.9
204.514.7113.9
255.935.9225.5
308.469.4391.0

Full Workflow (Fit + LRT + Profile CI)

Time to fit the model, compute penalized likelihood ratio test p-values for all coefficients, and profile likelihood confidence intervals.

kfirthmodels
(numba)
firthmodels
(numpy)
coxphf
54.418.223.8
1011.858.9364.4
1532.9159.11693.6
20105.3473.25675.5
25173.42240.416062.0
30265.93846.834707.3

Reproducing These Results

# Run logistic regression benchmarks
python benchmarks/benchmark_logistic.py -o benchmarks/logistic_results.csv

# Run Cox PH benchmarks
python benchmarks/benchmark_cox.py -o benchmarks/cox_results.csv

# Generate plots and README
python benchmarks/generate_report.py