coxdev 0.1.2__tar.gz → 0.1.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- coxdev-0.1.4/PKG-INFO +251 -0
- coxdev-0.1.4/README.md +232 -0
- coxdev-0.1.4/coxdev/__init__.py +21 -0
- {coxdev-0.1.2 → coxdev-0.1.4}/coxdev/_version.py +3 -3
- coxdev-0.1.2/coxdev/__init__.py → coxdev-0.1.4/coxdev/base.py +30 -37
- {coxdev-0.1.2 → coxdev-0.1.4}/coxdev/info.py +3 -3
- coxdev-0.1.4/coxdev/stratified.py +288 -0
- coxdev-0.1.4/coxdev.egg-info/PKG-INFO +251 -0
- {coxdev-0.1.2 → coxdev-0.1.4}/coxdev.egg-info/SOURCES.txt +4 -5
- {coxdev-0.1.2 → coxdev-0.1.4}/coxdev.egg-info/requires.txt +0 -1
- {coxdev-0.1.2 → coxdev-0.1.4}/coxdev.egg-info/top_level.txt +0 -1
- {coxdev-0.1.2 → coxdev-0.1.4}/pyproject.toml +9 -6
- {coxdev-0.1.2 → coxdev-0.1.4}/setup.py +36 -43
- coxdev-0.1.4/tests/test_compareR.py +451 -0
- {coxdev-0.1.2 → coxdev-0.1.4}/tests/test_cumsums.py +1 -1
- coxdev-0.1.4/tests/test_stratified.py +633 -0
- coxdev-0.1.2/LICENSE +0 -24
- coxdev-0.1.2/MANIFEST.in +0 -1
- coxdev-0.1.2/PKG-INFO +0 -39
- coxdev-0.1.2/README.md +0 -8
- coxdev-0.1.2/coxdev/base.py +0 -419
- coxdev-0.1.2/coxdev.egg-info/PKG-INFO +0 -39
- coxdev-0.1.2/src/coxdev.cpp +0 -977
- coxdev-0.1.2/tests/test_compareR.py +0 -215
- {coxdev-0.1.2/src → coxdev-0.1.4/R_pkg/coxdev/inst/include}/coxdev.h +0 -0
- {coxdev-0.1.2 → coxdev-0.1.4}/R_pkg/coxdev/src/coxdev.cpp +0 -0
- {coxdev-0.1.2 → coxdev-0.1.4}/coxdev.egg-info/dependency_links.txt +0 -0
- {coxdev-0.1.2 → coxdev-0.1.4}/setup.cfg +0 -0
- {coxdev-0.1.2 → coxdev-0.1.4}/tests/test_bad.py +0 -0
coxdev-0.1.4/PKG-INFO
ADDED
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: coxdev
|
|
3
|
+
Version: 0.1.4
|
|
4
|
+
Summary: Library for computing Cox deviance
|
|
5
|
+
Author-email: Jonathan Taylor <jonathan.taylor@stanford.edu>, Trevor Hastie <hastie@stanford.edu>, Balasubramanian Narasimhan <naras@stanford.edu>
|
|
6
|
+
Maintainer-email: Jonathan Taylor <jonathan.taylor@stanford.edu>
|
|
7
|
+
License: BSD-3-Clause
|
|
8
|
+
Classifier: Development Status :: 3 - Alpha
|
|
9
|
+
Classifier: Environment :: Console
|
|
10
|
+
Classifier: Intended Audience :: Science/Research
|
|
11
|
+
Classifier: Operating System :: OS Independent
|
|
12
|
+
Classifier: Programming Language :: Python
|
|
13
|
+
Classifier: Topic :: Scientific/Engineering
|
|
14
|
+
Requires-Python: >=3.9
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
Requires-Dist: numpy>=1.7.1
|
|
17
|
+
Requires-Dist: joblib
|
|
18
|
+
Requires-Dist: scipy
|
|
19
|
+
|
|
20
|
+
# coxdev
|
|
21
|
+
|
|
22
|
+
A high-performance Python library for computing Cox proportional hazards model deviance, gradients, and Hessian information matrices. Built with C++ and Eigen for optimal performance, this library provides efficient survival analysis computations with support for different tie-breaking methods.
|
|
23
|
+
|
|
24
|
+
## Features
|
|
25
|
+
|
|
26
|
+
- **High Performance**: C++ implementation with Eigen linear algebra library
|
|
27
|
+
- **Comprehensive Support**: Handles both Efron and Breslow tie-breaking methods
|
|
28
|
+
- **Left-Truncated Data**: Support for left-truncated survival data
|
|
29
|
+
- **Efficient Computations**: Optimized algorithms for deviance, gradient, and Hessian calculations
|
|
30
|
+
- **Memory Efficient**: Uses linear operators for large-scale computations
|
|
31
|
+
- **Cross-Platform**: Works on Linux, macOS, and Windows
|
|
32
|
+
|
|
33
|
+
## Installation
|
|
34
|
+
|
|
35
|
+
### Prerequisites
|
|
36
|
+
|
|
37
|
+
This package requires the Eigen C++ library headers. The Eigen library is included as a git submodule.
|
|
38
|
+
|
|
39
|
+
1. **Initialize Eigen submodule**: The Eigen library is included as a git submodule. Make sure it's initialized:
|
|
40
|
+
```bash
|
|
41
|
+
git submodule update --init --recursive
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
2. **Check Eigen availability**: Run the check script to verify Eigen headers are available:
|
|
45
|
+
```bash
|
|
46
|
+
python check_eigen.py
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Standard Installation
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
pip install .
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### With Custom Eigen Path
|
|
56
|
+
|
|
57
|
+
If you have Eigen installed elsewhere, you can specify its location:
|
|
58
|
+
```bash
|
|
59
|
+
env EIGEN_LIBRARY_PATH=/path/to/eigen pip install .
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Development Installation
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
pip install -e .
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Quick Start
|
|
69
|
+
|
|
70
|
+
```python
|
|
71
|
+
import numpy as np
|
|
72
|
+
from coxdev import CoxDeviance
|
|
73
|
+
|
|
74
|
+
# Generate sample survival data
|
|
75
|
+
n_samples = 1000
|
|
76
|
+
event_times = np.random.exponential(1.0, n_samples)
|
|
77
|
+
status = np.random.binomial(1, 0.7, n_samples) # 70% events, 30% censored
|
|
78
|
+
linear_predictor = np.random.normal(0, 1, n_samples)
|
|
79
|
+
|
|
80
|
+
# Create CoxDeviance object
|
|
81
|
+
coxdev = CoxDeviance(event=event_times, status=status, tie_breaking='efron')
|
|
82
|
+
|
|
83
|
+
# Compute deviance and related quantities
|
|
84
|
+
result = coxdev(linear_predictor)
|
|
85
|
+
|
|
86
|
+
print(f"Deviance: {result.deviance:.4f}")
|
|
87
|
+
print(f"Saturated log-likelihood: {result.loglik_sat:.4f}")
|
|
88
|
+
print(f"Gradient norm: {np.linalg.norm(result.gradient):.4f}")
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Advanced Usage
|
|
92
|
+
|
|
93
|
+
### Left-Truncated Data
|
|
94
|
+
|
|
95
|
+
```python
|
|
96
|
+
# With start times (left-truncated data)
|
|
97
|
+
start_times = np.random.exponential(0.5, n_samples)
|
|
98
|
+
coxdev = CoxDeviance(
|
|
99
|
+
event=event_times,
|
|
100
|
+
status=status,
|
|
101
|
+
start=start_times,
|
|
102
|
+
tie_breaking='efron'
|
|
103
|
+
)
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Computing Information Matrix
|
|
107
|
+
|
|
108
|
+
```python
|
|
109
|
+
# Get information matrix as a linear operator
|
|
110
|
+
info_matrix = coxdev.information(linear_predictor)
|
|
111
|
+
|
|
112
|
+
# Matrix-vector multiplication
|
|
113
|
+
v = np.random.normal(0, 1, n_samples)
|
|
114
|
+
result_vector = info_matrix @ v
|
|
115
|
+
|
|
116
|
+
# For small problems, you can compute the full matrix
|
|
117
|
+
X = np.random.normal(0, 1, (n_samples, 10))
|
|
118
|
+
beta = np.random.normal(0, 1, 10)
|
|
119
|
+
eta = X @ beta
|
|
120
|
+
|
|
121
|
+
# Information matrix for coefficients: X^T @ I @ X
|
|
122
|
+
I = info_matrix @ X
|
|
123
|
+
information_matrix = X.T @ I
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Different Tie-Breaking Methods
|
|
127
|
+
|
|
128
|
+
```python
|
|
129
|
+
# Efron's method (default)
|
|
130
|
+
coxdev_efron = CoxDeviance(event=event_times, status=status, tie_breaking='efron')
|
|
131
|
+
|
|
132
|
+
# Breslow's method
|
|
133
|
+
coxdev_breslow = CoxDeviance(event=event_times, status=status, tie_breaking='breslow')
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## API Reference
|
|
137
|
+
|
|
138
|
+
### CoxDeviance
|
|
139
|
+
|
|
140
|
+
The main class for computing Cox model quantities.
|
|
141
|
+
|
|
142
|
+
#### Parameters
|
|
143
|
+
|
|
144
|
+
- **event**: Event times (failure times) for each observation
|
|
145
|
+
- **status**: Event indicators (1 for event occurred, 0 for censored)
|
|
146
|
+
- **start**: Start times for left-truncated data (optional)
|
|
147
|
+
- **tie_breaking**: Method for handling tied event times ('efron' or 'breslow')
|
|
148
|
+
|
|
149
|
+
#### Methods
|
|
150
|
+
|
|
151
|
+
- **`__call__(linear_predictor, sample_weight=None)`**: Compute deviance and related quantities
|
|
152
|
+
- **`information(linear_predictor, sample_weight=None)`**: Get information matrix as linear operator
|
|
153
|
+
|
|
154
|
+
### CoxDevianceResult
|
|
155
|
+
|
|
156
|
+
Result object containing computation results.
|
|
157
|
+
|
|
158
|
+
#### Attributes
|
|
159
|
+
|
|
160
|
+
- **linear_predictor**: The linear predictor values used
|
|
161
|
+
- **sample_weight**: Sample weights used
|
|
162
|
+
- **loglik_sat**: Saturated log-likelihood value
|
|
163
|
+
- **deviance**: Computed deviance value
|
|
164
|
+
- **gradient**: Gradient of deviance with respect to linear predictor
|
|
165
|
+
- **diag_hessian**: Diagonal of Hessian matrix
|
|
166
|
+
|
|
167
|
+
## Performance
|
|
168
|
+
|
|
169
|
+
The library is optimized for performance:
|
|
170
|
+
|
|
171
|
+
- **C++ Implementation**: Core computations in C++ with Eigen
|
|
172
|
+
- **Memory Efficient**: Reuses buffers and uses linear operators
|
|
173
|
+
- **Vectorized Operations**: Leverages Eigen's optimized linear algebra
|
|
174
|
+
- **Minimal Python Overhead**: Heavy computations done in C++
|
|
175
|
+
|
|
176
|
+
## Building from Source
|
|
177
|
+
|
|
178
|
+
### Prerequisites
|
|
179
|
+
|
|
180
|
+
- Python 3.9+
|
|
181
|
+
- C++ compiler with C++17 support
|
|
182
|
+
- Eigen library headers
|
|
183
|
+
- pybind11
|
|
184
|
+
|
|
185
|
+
### Build Steps
|
|
186
|
+
|
|
187
|
+
1. Clone the repository with submodules:
|
|
188
|
+
```bash
|
|
189
|
+
git clone --recursive https://github.com/jonathan-taylor/coxdev.git
|
|
190
|
+
cd coxdev
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
2. Install build dependencies:
|
|
194
|
+
```bash
|
|
195
|
+
pip install build wheel setuptools pybind11 numpy
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
3. Build the package:
|
|
199
|
+
```bash
|
|
200
|
+
python -m build
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
### Building Wheels
|
|
204
|
+
|
|
205
|
+
For wheel building:
|
|
206
|
+
```bash
|
|
207
|
+
# Standard wheel build
|
|
208
|
+
python -m build
|
|
209
|
+
|
|
210
|
+
# With custom Eigen path
|
|
211
|
+
env EIGEN_LIBRARY_PATH=/path/to/eigen python -m build
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
## Testing
|
|
215
|
+
|
|
216
|
+
Run the test suite:
|
|
217
|
+
```bash
|
|
218
|
+
python -m pytest tests/
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
## Contributing
|
|
222
|
+
|
|
223
|
+
1. Fork the repository
|
|
224
|
+
2. Create a feature branch
|
|
225
|
+
3. Make your changes
|
|
226
|
+
4. Add tests for new functionality
|
|
227
|
+
5. Ensure all tests pass
|
|
228
|
+
6. Submit a pull request
|
|
229
|
+
|
|
230
|
+
## License
|
|
231
|
+
|
|
232
|
+
This project is licensed under the BSD-3-Clause License - see the [LICENSE](LICENSE) file for details.
|
|
233
|
+
|
|
234
|
+
## Citation
|
|
235
|
+
|
|
236
|
+
If you use this library in your research, please cite:
|
|
237
|
+
|
|
238
|
+
```bibtex
|
|
239
|
+
@software{coxdev2024,
|
|
240
|
+
title={coxdev: High-performance Cox proportional hazards deviance computation},
|
|
241
|
+
author={Taylor, Jonathan and Hastie, Trevor and Narasimhan, Balasubramanian},
|
|
242
|
+
year={2024},
|
|
243
|
+
url={https://github.com/jonathan-taylor/coxdev}
|
|
244
|
+
}
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
## Acknowledgments
|
|
248
|
+
|
|
249
|
+
- Built with [Eigen](http://eigen.tuxfamily.org/) for efficient linear algebra
|
|
250
|
+
- Uses [pybind11](https://pybind11.readthedocs.io/) for Python bindings
|
|
251
|
+
- Inspired by the R `glmnet` package for survival analysis
|
coxdev-0.1.4/README.md
ADDED
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
# coxdev
|
|
2
|
+
|
|
3
|
+
A high-performance Python library for computing Cox proportional hazards model deviance, gradients, and Hessian information matrices. Built with C++ and Eigen for optimal performance, this library provides efficient survival analysis computations with support for different tie-breaking methods.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **High Performance**: C++ implementation with Eigen linear algebra library
|
|
8
|
+
- **Comprehensive Support**: Handles both Efron and Breslow tie-breaking methods
|
|
9
|
+
- **Left-Truncated Data**: Support for left-truncated survival data
|
|
10
|
+
- **Efficient Computations**: Optimized algorithms for deviance, gradient, and Hessian calculations
|
|
11
|
+
- **Memory Efficient**: Uses linear operators for large-scale computations
|
|
12
|
+
- **Cross-Platform**: Works on Linux, macOS, and Windows
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
### Prerequisites
|
|
17
|
+
|
|
18
|
+
This package requires the Eigen C++ library headers. The Eigen library is included as a git submodule.
|
|
19
|
+
|
|
20
|
+
1. **Initialize Eigen submodule**: The Eigen library is included as a git submodule. Make sure it's initialized:
|
|
21
|
+
```bash
|
|
22
|
+
git submodule update --init --recursive
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
2. **Check Eigen availability**: Run the check script to verify Eigen headers are available:
|
|
26
|
+
```bash
|
|
27
|
+
python check_eigen.py
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### Standard Installation
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
pip install .
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### With Custom Eigen Path
|
|
37
|
+
|
|
38
|
+
If you have Eigen installed elsewhere, you can specify its location:
|
|
39
|
+
```bash
|
|
40
|
+
env EIGEN_LIBRARY_PATH=/path/to/eigen pip install .
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Development Installation
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
pip install -e .
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Quick Start
|
|
50
|
+
|
|
51
|
+
```python
|
|
52
|
+
import numpy as np
|
|
53
|
+
from coxdev import CoxDeviance
|
|
54
|
+
|
|
55
|
+
# Generate sample survival data
|
|
56
|
+
n_samples = 1000
|
|
57
|
+
event_times = np.random.exponential(1.0, n_samples)
|
|
58
|
+
status = np.random.binomial(1, 0.7, n_samples) # 70% events, 30% censored
|
|
59
|
+
linear_predictor = np.random.normal(0, 1, n_samples)
|
|
60
|
+
|
|
61
|
+
# Create CoxDeviance object
|
|
62
|
+
coxdev = CoxDeviance(event=event_times, status=status, tie_breaking='efron')
|
|
63
|
+
|
|
64
|
+
# Compute deviance and related quantities
|
|
65
|
+
result = coxdev(linear_predictor)
|
|
66
|
+
|
|
67
|
+
print(f"Deviance: {result.deviance:.4f}")
|
|
68
|
+
print(f"Saturated log-likelihood: {result.loglik_sat:.4f}")
|
|
69
|
+
print(f"Gradient norm: {np.linalg.norm(result.gradient):.4f}")
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Advanced Usage
|
|
73
|
+
|
|
74
|
+
### Left-Truncated Data
|
|
75
|
+
|
|
76
|
+
```python
|
|
77
|
+
# With start times (left-truncated data)
|
|
78
|
+
start_times = np.random.exponential(0.5, n_samples)
|
|
79
|
+
coxdev = CoxDeviance(
|
|
80
|
+
event=event_times,
|
|
81
|
+
status=status,
|
|
82
|
+
start=start_times,
|
|
83
|
+
tie_breaking='efron'
|
|
84
|
+
)
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Computing Information Matrix
|
|
88
|
+
|
|
89
|
+
```python
|
|
90
|
+
# Get information matrix as a linear operator
|
|
91
|
+
info_matrix = coxdev.information(linear_predictor)
|
|
92
|
+
|
|
93
|
+
# Matrix-vector multiplication
|
|
94
|
+
v = np.random.normal(0, 1, n_samples)
|
|
95
|
+
result_vector = info_matrix @ v
|
|
96
|
+
|
|
97
|
+
# For small problems, you can compute the full matrix
|
|
98
|
+
X = np.random.normal(0, 1, (n_samples, 10))
|
|
99
|
+
beta = np.random.normal(0, 1, 10)
|
|
100
|
+
eta = X @ beta
|
|
101
|
+
|
|
102
|
+
# Information matrix for coefficients: X^T @ I @ X
|
|
103
|
+
I = info_matrix @ X
|
|
104
|
+
information_matrix = X.T @ I
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Different Tie-Breaking Methods
|
|
108
|
+
|
|
109
|
+
```python
|
|
110
|
+
# Efron's method (default)
|
|
111
|
+
coxdev_efron = CoxDeviance(event=event_times, status=status, tie_breaking='efron')
|
|
112
|
+
|
|
113
|
+
# Breslow's method
|
|
114
|
+
coxdev_breslow = CoxDeviance(event=event_times, status=status, tie_breaking='breslow')
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## API Reference
|
|
118
|
+
|
|
119
|
+
### CoxDeviance
|
|
120
|
+
|
|
121
|
+
The main class for computing Cox model quantities.
|
|
122
|
+
|
|
123
|
+
#### Parameters
|
|
124
|
+
|
|
125
|
+
- **event**: Event times (failure times) for each observation
|
|
126
|
+
- **status**: Event indicators (1 for event occurred, 0 for censored)
|
|
127
|
+
- **start**: Start times for left-truncated data (optional)
|
|
128
|
+
- **tie_breaking**: Method for handling tied event times ('efron' or 'breslow')
|
|
129
|
+
|
|
130
|
+
#### Methods
|
|
131
|
+
|
|
132
|
+
- **`__call__(linear_predictor, sample_weight=None)`**: Compute deviance and related quantities
|
|
133
|
+
- **`information(linear_predictor, sample_weight=None)`**: Get information matrix as linear operator
|
|
134
|
+
|
|
135
|
+
### CoxDevianceResult
|
|
136
|
+
|
|
137
|
+
Result object containing computation results.
|
|
138
|
+
|
|
139
|
+
#### Attributes
|
|
140
|
+
|
|
141
|
+
- **linear_predictor**: The linear predictor values used
|
|
142
|
+
- **sample_weight**: Sample weights used
|
|
143
|
+
- **loglik_sat**: Saturated log-likelihood value
|
|
144
|
+
- **deviance**: Computed deviance value
|
|
145
|
+
- **gradient**: Gradient of deviance with respect to linear predictor
|
|
146
|
+
- **diag_hessian**: Diagonal of Hessian matrix
|
|
147
|
+
|
|
148
|
+
## Performance
|
|
149
|
+
|
|
150
|
+
The library is optimized for performance:
|
|
151
|
+
|
|
152
|
+
- **C++ Implementation**: Core computations in C++ with Eigen
|
|
153
|
+
- **Memory Efficient**: Reuses buffers and uses linear operators
|
|
154
|
+
- **Vectorized Operations**: Leverages Eigen's optimized linear algebra
|
|
155
|
+
- **Minimal Python Overhead**: Heavy computations done in C++
|
|
156
|
+
|
|
157
|
+
## Building from Source
|
|
158
|
+
|
|
159
|
+
### Prerequisites
|
|
160
|
+
|
|
161
|
+
- Python 3.9+
|
|
162
|
+
- C++ compiler with C++17 support
|
|
163
|
+
- Eigen library headers
|
|
164
|
+
- pybind11
|
|
165
|
+
|
|
166
|
+
### Build Steps
|
|
167
|
+
|
|
168
|
+
1. Clone the repository with submodules:
|
|
169
|
+
```bash
|
|
170
|
+
git clone --recursive https://github.com/jonathan-taylor/coxdev.git
|
|
171
|
+
cd coxdev
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
2. Install build dependencies:
|
|
175
|
+
```bash
|
|
176
|
+
pip install build wheel setuptools pybind11 numpy
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
3. Build the package:
|
|
180
|
+
```bash
|
|
181
|
+
python -m build
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### Building Wheels
|
|
185
|
+
|
|
186
|
+
For wheel building:
|
|
187
|
+
```bash
|
|
188
|
+
# Standard wheel build
|
|
189
|
+
python -m build
|
|
190
|
+
|
|
191
|
+
# With custom Eigen path
|
|
192
|
+
env EIGEN_LIBRARY_PATH=/path/to/eigen python -m build
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
## Testing
|
|
196
|
+
|
|
197
|
+
Run the test suite:
|
|
198
|
+
```bash
|
|
199
|
+
python -m pytest tests/
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
## Contributing
|
|
203
|
+
|
|
204
|
+
1. Fork the repository
|
|
205
|
+
2. Create a feature branch
|
|
206
|
+
3. Make your changes
|
|
207
|
+
4. Add tests for new functionality
|
|
208
|
+
5. Ensure all tests pass
|
|
209
|
+
6. Submit a pull request
|
|
210
|
+
|
|
211
|
+
## License
|
|
212
|
+
|
|
213
|
+
This project is licensed under the BSD-3-Clause License - see the [LICENSE](LICENSE) file for details.
|
|
214
|
+
|
|
215
|
+
## Citation
|
|
216
|
+
|
|
217
|
+
If you use this library in your research, please cite:
|
|
218
|
+
|
|
219
|
+
```bibtex
|
|
220
|
+
@software{coxdev2024,
|
|
221
|
+
title={coxdev: High-performance Cox proportional hazards deviance computation},
|
|
222
|
+
author={Taylor, Jonathan and Hastie, Trevor and Narasimhan, Balasubramanian},
|
|
223
|
+
year={2024},
|
|
224
|
+
url={https://github.com/jonathan-taylor/coxdev}
|
|
225
|
+
}
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
## Acknowledgments
|
|
229
|
+
|
|
230
|
+
- Built with [Eigen](http://eigen.tuxfamily.org/) for efficient linear algebra
|
|
231
|
+
- Uses [pybind11](https://pybind11.readthedocs.io/) for Python bindings
|
|
232
|
+
- Inspired by the R `glmnet` package for survival analysis
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"""
|
|
2
|
+
coxdev: Efficient Cox Proportional Hazards Model Deviance and Information
|
|
3
|
+
|
|
4
|
+
This package provides efficient computation of Cox model deviance, gradients, and information matrices
|
|
5
|
+
for survival analysis, including support for stratified models and different tie-breaking methods.
|
|
6
|
+
|
|
7
|
+
Main Classes
|
|
8
|
+
------------
|
|
9
|
+
CoxDeviance
|
|
10
|
+
Standard Cox model deviance and information computation.
|
|
11
|
+
StratifiedCoxDeviance
|
|
12
|
+
Stratified Cox model deviance and information computation.
|
|
13
|
+
|
|
14
|
+
See Also
|
|
15
|
+
--------
|
|
16
|
+
coxdev.base : Core Cox model implementation.
|
|
17
|
+
coxdev.stratified : Stratified Cox model implementation.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from .base import CoxDeviance
|
|
21
|
+
from .stratified import StratifiedCoxDeviance
|
|
@@ -8,11 +8,11 @@ import json
|
|
|
8
8
|
|
|
9
9
|
version_json = '''
|
|
10
10
|
{
|
|
11
|
-
"date": "2025-
|
|
11
|
+
"date": "2025-07-11T13:26:28-0700",
|
|
12
12
|
"dirty": false,
|
|
13
13
|
"error": null,
|
|
14
|
-
"full-revisionid": "
|
|
15
|
-
"version": "0.1.
|
|
14
|
+
"full-revisionid": "0ccbd28a93a84afbc73f6f32f752b5f40c349d6d",
|
|
15
|
+
"version": "0.1.4"
|
|
16
16
|
}
|
|
17
17
|
''' # END VERSION_JSON
|
|
18
18
|
|
|
@@ -16,12 +16,12 @@ from . import _version
|
|
|
16
16
|
__version__ = _version.get_versions()['version']
|
|
17
17
|
|
|
18
18
|
import numpy as np
|
|
19
|
-
from joblib import hash
|
|
19
|
+
from joblib import hash as _hash
|
|
20
20
|
|
|
21
|
-
from coxc import (cox_dev as _cox_dev,
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
21
|
+
from .coxc import (cox_dev as _cox_dev,
|
|
22
|
+
hessian_matvec as _hessian_matvec,
|
|
23
|
+
compute_sat_loglik as _compute_sat_loglik,
|
|
24
|
+
c_preprocess)
|
|
25
25
|
|
|
26
26
|
|
|
27
27
|
@dataclass
|
|
@@ -84,6 +84,18 @@ class CoxDeviance(object):
|
|
|
84
84
|
Whether start times are provided.
|
|
85
85
|
_efron : bool
|
|
86
86
|
Whether Efron's method is being used for tie-breaking.
|
|
87
|
+
|
|
88
|
+
Examples
|
|
89
|
+
--------
|
|
90
|
+
>>> import numpy as np
|
|
91
|
+
>>> from coxdev import CoxDeviance
|
|
92
|
+
>>> event = np.array([3, 6, 8, 4, 6, 4, 3, 2, 2, 5, 3, 4])
|
|
93
|
+
>>> status = np.array([1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1])
|
|
94
|
+
>>> cox = CoxDeviance(event=event, status=status)
|
|
95
|
+
>>> eta = np.linspace(-1, 1, len(event))
|
|
96
|
+
>>> result = cox(eta)
|
|
97
|
+
>>> print(round(result.deviance, 4))
|
|
98
|
+
20.7998
|
|
87
99
|
"""
|
|
88
100
|
|
|
89
101
|
event: InitVar[np.ndarray]
|
|
@@ -107,8 +119,13 @@ class CoxDeviance(object):
|
|
|
107
119
|
start : np.ndarray, optional
|
|
108
120
|
Start times for left-truncated data.
|
|
109
121
|
"""
|
|
110
|
-
event = np.asarray(event)
|
|
111
|
-
|
|
122
|
+
event = np.asarray(event).astype(float)
|
|
123
|
+
|
|
124
|
+
status_arr = np.asarray(status)
|
|
125
|
+
if not set(np.unique(status_arr)).issubset(set([0,1])):
|
|
126
|
+
raise ValueError('status must be binary')
|
|
127
|
+
status = status_arr.astype(np.int32)
|
|
128
|
+
|
|
112
129
|
nevent = event.shape[0]
|
|
113
130
|
|
|
114
131
|
if start is None:
|
|
@@ -147,14 +164,10 @@ class CoxDeviance(object):
|
|
|
147
164
|
|
|
148
165
|
self._T_1_term = np.zeros(n)
|
|
149
166
|
self._T_2_term = np.zeros(n)
|
|
150
|
-
# self._event_reorder_buffers = np.zeros((3, n))
|
|
151
167
|
self._event_reorder_buffers = [np.zeros(n) for i in range(3)]
|
|
152
|
-
# self._forward_cumsum_buffers = np.zeros((5, n+1))
|
|
153
168
|
self._forward_cumsum_buffers = [np.zeros(n+1) for i in range(5)]
|
|
154
169
|
self._forward_scratch_buffer = np.zeros(n)
|
|
155
|
-
# self._reverse_cumsum_buffers = np.zeros((4, n+1))
|
|
156
170
|
self._reverse_cumsum_buffers = [np.zeros(n+1) for i in range(4)]
|
|
157
|
-
# self._risk_sum_buffers = np.zeros((2, n))
|
|
158
171
|
self._risk_sum_buffers = [np.zeros(n) for i in range(2)]
|
|
159
172
|
self._hess_matvec_buffer = np.zeros(n)
|
|
160
173
|
self._grad_buffer = np.zeros(n)
|
|
@@ -188,7 +201,7 @@ class CoxDeviance(object):
|
|
|
188
201
|
|
|
189
202
|
linear_predictor = np.asarray(linear_predictor)
|
|
190
203
|
|
|
191
|
-
cur_hash =
|
|
204
|
+
cur_hash = _hash([linear_predictor, sample_weight])
|
|
192
205
|
if not hasattr(self, "_result") or self._result.__hash_args__ != cur_hash:
|
|
193
206
|
|
|
194
207
|
loglik_sat = _compute_sat_loglik(self._first,
|
|
@@ -201,31 +214,11 @@ class CoxDeviance(object):
|
|
|
201
214
|
eta = np.asarray(linear_predictor)
|
|
202
215
|
sample_weight = np.asarray(sample_weight)
|
|
203
216
|
eta = eta - eta.mean()
|
|
204
|
-
self._exp_w_buffer[:] = sample_weight * np.exp(eta)
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
# print(f'self._event_order {self._event_order.dtype}')
|
|
210
|
-
# print(f'self._start_order {self._start_order.dtype}')
|
|
211
|
-
# print(f'self._status {self._status.dtype}')
|
|
212
|
-
# print(f'self._first {self._first.dtype}')
|
|
213
|
-
# print(f'self._last {self._last.dtype}')
|
|
214
|
-
# print(f'self._scaling {self._scaling.dtype}')
|
|
215
|
-
# print(f'self._event_map {self._event_map.dtype}')
|
|
216
|
-
# print(f'self._start_map {self._start_map.dtype}')
|
|
217
|
-
# print(f'self._T_1_term {self._T_1_term.dtype}')
|
|
218
|
-
# print(f'self._T_2_term {self._T_2_term.dtype}')
|
|
219
|
-
# print(f'self._grad_buffer {self._grad_buffer.dtype}')
|
|
220
|
-
# print(f'self._diag_hessian_buffer {self._diag_hessian_buffer.dtype}')
|
|
221
|
-
# print(f'self._diag_part_buffer {self._diag_part_buffer.dtype}')
|
|
222
|
-
# print(f'self._w_avg_buffer {self._w_avg_buffer.dtype}')
|
|
223
|
-
# #print(f'self._event_reorder_buffers {self._event_reorder_buffers.dtype}')
|
|
224
|
-
# #print(f'self._risk_sum_buffers {self._risk_sum_buffers.dtype}')
|
|
225
|
-
# #print(f'self._forward_cumsum_buffers {self._forward_cumsum_buffers.dtype}')
|
|
226
|
-
# print(f'self._forward_scratch_buffer {self._forward_scratch_buffer.dtype}')
|
|
227
|
-
# #print(f'self._reverse_cumsum_buffers {self._reverse_cumsum_buffers.dtype}')
|
|
228
|
-
|
|
217
|
+
self._exp_w_buffer[:] = sample_weight * np.exp(np.clip(eta, -np.inf, 30))
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
|
|
229
222
|
deviance = _cox_dev(eta,
|
|
230
223
|
sample_weight,
|
|
231
224
|
self._exp_w_buffer,
|
|
@@ -14,15 +14,15 @@ description = 'CoxDev (Python)'
|
|
|
14
14
|
|
|
15
15
|
NAME = 'coxdev'
|
|
16
16
|
MAINTAINER = "Naras Balasubrimanian, Trevor Hastie, Jonathan Taylor"
|
|
17
|
-
MAINTAINER_EMAIL = ""
|
|
17
|
+
MAINTAINER_EMAIL = "jonathan.taylor@stanford.edu"
|
|
18
18
|
DESCRIPTION = description
|
|
19
19
|
LONG_DESCRIPTION = description
|
|
20
20
|
URL = "https://github.org/jonathan-taylor/coxdev"
|
|
21
21
|
DOWNLOAD_URL = ""
|
|
22
|
-
LICENSE = "BSD
|
|
22
|
+
LICENSE = "BSD-3-Clause"
|
|
23
23
|
CLASSIFIERS = CLASSIFIERS
|
|
24
24
|
AUTHOR = "Naras Balasubrimanian, Trevor Hastie, Jonathan Taylor"
|
|
25
|
-
AUTHOR_EMAIL = ""
|
|
25
|
+
AUTHOR_EMAIL = "jonathan.taylor@stanford.edu"
|
|
26
26
|
PLATFORMS = "OS Independent"
|
|
27
27
|
STATUS = 'alpha'
|
|
28
28
|
|