scm2cpp-lasso 0.14.0__tar.gz → 0.15.1__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.
- {scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/PKG-INFO +47 -7
- {scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/README.md +46 -6
- {scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/pyproject.toml +1 -1
- {scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/__init__.py +222 -13
- {scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/_compat.py +2 -1
- {scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/_generated/derived_blas/lasso_design.hpp +17 -14
- {scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/_generated/derived_cublas/lasso_design.hpp +18 -15
- {scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/_generated/derived_loops/lasso_design.hpp +29 -26
- {scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso.egg-info/PKG-INFO +47 -7
- {scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/setup.cfg +0 -0
- {scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/setup.py +0 -0
- {scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/_generated/__init__.py +0 -0
- {scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/_generated/_loader.py +0 -0
- {scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/_generated/_loader_accel_cublas.py +0 -0
- {scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/_generated/_loader_classifiers.py +0 -0
- {scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/_generated/_loader_derived_blas.py +0 -0
- {scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/_generated/_loader_derived_cublas.py +0 -0
- {scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/_generated/_loader_derived_loops.py +0 -0
- {scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/_generated/_loader_gpu_cuda.py +0 -0
- {scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/_generated/_loader_gramops_blas.py +0 -0
- {scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/_generated/_loader_gramops_loops.py +0 -0
- {scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/_generated/_loader_nmf_blas.py +0 -0
- {scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/_generated/_loader_nmf_cublas.py +0 -0
- {scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/_generated/_loader_nmf_loops.py +0 -0
- {scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/_generated/accel_cublas/accel.cpp +0 -0
- {scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/_generated/accel_cublas/accel.hpp +0 -0
- {scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/_generated/accel_cublas/accel_capi.cpp +0 -0
- {scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/_generated/classifiers.cpp +0 -0
- {scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/_generated/classifiers.hpp +0 -0
- {scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/_generated/classifiers_capi.cpp +0 -0
- {scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/_generated/derived_blas/lasso_design.cpp +0 -0
- {scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/_generated/derived_blas/lasso_design_capi.cpp +0 -0
- {scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/_generated/derived_cublas/lasso_design.cpp +0 -0
- {scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/_generated/derived_cublas/lasso_design_capi.cpp +0 -0
- {scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/_generated/derived_loops/lasso_design.cpp +0 -0
- {scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/_generated/derived_loops/lasso_design_capi.cpp +0 -0
- {scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/_generated/gpu_cuda/gpu.cpp +0 -0
- {scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/_generated/gpu_cuda/gpu.hpp +0 -0
- {scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/_generated/gpu_cuda/gpu_capi.cpp +0 -0
- {scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/_generated/gramops_blas/gramops.cpp +0 -0
- {scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/_generated/gramops_blas/gramops.hpp +0 -0
- {scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/_generated/gramops_blas/gramops_capi.cpp +0 -0
- {scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/_generated/gramops_loops/gramops.cpp +0 -0
- {scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/_generated/gramops_loops/gramops.hpp +0 -0
- {scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/_generated/gramops_loops/gramops_capi.cpp +0 -0
- {scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/_generated/lasso_cov.cpp +0 -0
- {scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/_generated/lasso_cov.hpp +0 -0
- {scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/_generated/lasso_cov_capi.cpp +0 -0
- {scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/_generated/nmf_blas/nmf_cd.cpp +0 -0
- {scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/_generated/nmf_blas/nmf_cd.hpp +0 -0
- {scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/_generated/nmf_blas/nmf_cd_capi.cpp +0 -0
- {scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/_generated/nmf_cublas/nmf_cd.cpp +0 -0
- {scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/_generated/nmf_cublas/nmf_cd.hpp +0 -0
- {scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/_generated/nmf_cublas/nmf_cd_capi.cpp +0 -0
- {scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/_generated/nmf_loops/nmf_cd.cpp +0 -0
- {scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/_generated/nmf_loops/nmf_cd.hpp +0 -0
- {scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/_generated/nmf_loops/nmf_cd_capi.cpp +0 -0
- {scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/_generated/scm2cpp-blas.hpp +0 -0
- {scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/_generated/scm2cpp-cublas.hpp +0 -0
- {scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/_generated/scm2cpp-cuda.hpp +0 -0
- {scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/_generated/scm2cpp.hpp +0 -0
- {scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/_libfind.py +0 -0
- {scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/batch_capi.cu +0 -0
- {scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso.egg-info/SOURCES.txt +0 -0
- {scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso.egg-info/dependency_links.txt +0 -0
- {scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso.egg-info/requires.txt +0 -0
- {scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: scm2cpp-lasso
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.15.1
|
|
4
4
|
Summary: scikit-learn estimators (lasso, elastic net, ridge, ARD, SVM, SVR, logistic regression, GLMs, Huber, Theil-Sen, F-score selection, RFE, NMF, Gaussian mixture, FastICA, PCA, graphical lasso, RANSAC, SGD, OMP, LARS) translated from Scheme to C++ by scm2cpp; GPU batch solver and CUDA kernels included
|
|
5
5
|
Author: Hirotaka Niitsuma
|
|
6
6
|
License: MIT
|
|
@@ -107,7 +107,7 @@ them first; this solver does not do it for you.
|
|
|
107
107
|
From 0.14.0 every estimator with a `fit(X, y)` (or `fit(X)`) derives
|
|
108
108
|
from scikit-learn's `BaseEstimator` and the matching mixin, so `clone`,
|
|
109
109
|
`get_params` / `set_params`, `GridSearchCV`, `Pipeline` and
|
|
110
|
-
`cross_val_score` take them, and all
|
|
110
|
+
`cross_val_score` take them, and all 44 pass
|
|
111
111
|
`sklearn.utils.estimator_checks.check_estimator` (`check-sklearn.py`
|
|
112
112
|
runs it; the one expected failure is `LBFGSLogisticRegressionCV`'s
|
|
113
113
|
`n_iter_` of 0 for a C whose warm start is already converged, which
|
|
@@ -122,11 +122,37 @@ from scm2cpp_lasso import GramLasso
|
|
|
122
122
|
GridSearchCV(GramLasso(), {"alpha": [0.01, 0.1, 1.0]}, cv=5).fit(X, y)
|
|
123
123
|
```
|
|
124
124
|
|
|
125
|
-
`
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
`
|
|
129
|
-
|
|
125
|
+
`CovLasso`, `CovRidge`, `DerivedLasso`, `CovLogistic`,
|
|
126
|
+
`CovGroupLasso` and `CovMultiTaskLasso` keep their
|
|
127
|
+
data-in-the-constructor interface, which solves a whole path at once;
|
|
128
|
+
each has a `fit(X, y)` form with the intercept beside it (0.15.0):
|
|
129
|
+
|
|
130
|
+
| data in the constructor | `fit(X, y)` | scikit-learn |
|
|
131
|
+
|---|---|---|
|
|
132
|
+
| `CovLasso` | `GramLasso`, `GramElasticNet` | Lasso, ElasticNet |
|
|
133
|
+
| `CovRidge` | `GramRidge` | Ridge |
|
|
134
|
+
| `DerivedLasso` | `DesignLasso` | Lasso |
|
|
135
|
+
| `CovLogistic` | `GramLogisticRegression` | LogisticRegression(l1_ratio=1, solver="liblinear") |
|
|
136
|
+
| `CovGroupLasso` | `GramGroupLasso` (`groups=None`: the lasso) | (none) |
|
|
137
|
+
| `CovMultiTaskLasso` | `GramMultiTaskLasso`, `GramMultiTaskElasticNet` | MultiTaskLasso, MultiTaskElasticNet |
|
|
138
|
+
|
|
139
|
+
Against scikit-learn on 400 x 30 with an intercept: `DesignLasso` and
|
|
140
|
+
`GramGroupLasso(groups=None)` agree with `Lasso` to 1.5e-10, the
|
|
141
|
+
multi-task pair with `MultiTaskLasso` / `MultiTaskElasticNet` to
|
|
142
|
+
5e-14, and `GramLogisticRegression` reaches liblinear's objective to
|
|
143
|
+
eight digits with the same predictions.
|
|
144
|
+
|
|
145
|
+
Against the class each one wraps (one alpha, one core), which fits no
|
|
146
|
+
intercept and is unchanged: with `fit_intercept=False` the input checks
|
|
147
|
+
add 15 to 30 us a call (up to +50% on a 0.06 ms fit) and the finiteness
|
|
148
|
+
sum 8 to 14% on 20000 x 200 (none under `assume_finite`); with the
|
|
149
|
+
intercept, the column means add 20 to 30% on 20000 x 200 for the
|
|
150
|
+
Gram-matrix ones, which correct X'X
|
|
151
|
+
for the means rather than copy X to centre it, and about 55% for
|
|
152
|
+
`DesignLasso`, whose kernel needs the centred X itself.
|
|
153
|
+
`GramLogisticRegression` is slower than liblinear by its algorithm, 2.5x
|
|
154
|
+
at 20000 x 200 and more on small problems; `L1LogisticRegression` is
|
|
155
|
+
the fast one for that problem.
|
|
130
156
|
|
|
131
157
|
What it costs is the input checks: X must be a finite 2-D float64
|
|
132
158
|
array with the feature count of the fit. A plain C-ordered float64
|
|
@@ -166,6 +192,11 @@ package picks the fastest one present.
|
|
|
166
192
|
| `GramLasso` | Lasso(precompute=True), fit(X, y) with the intercept | `lasso-cov.scm` | CPU | no |
|
|
167
193
|
| `GramElasticNet` | ElasticNet(precompute=True), fit(X, y) with the intercept | `lasso-cov.scm` | CPU | no |
|
|
168
194
|
| `GramRidge` | Ridge, fit(X, y) with the intercept, one or many targets | numpy (Cholesky) | CPU | Ridge |
|
|
195
|
+
| `GramMultiTaskLasso` | MultiTaskLasso, fit(X, Y) with the intercept | `lasso-cov.scm` | CPU | no |
|
|
196
|
+
| `GramMultiTaskElasticNet` | MultiTaskElasticNet, fit(X, Y) with the intercept | `lasso-cov.scm` | CPU | no |
|
|
197
|
+
| `GramGroupLasso` | (none; skglm GroupLasso), fit(X, y) with the intercept | `lasso-cov.scm` | CPU | - |
|
|
198
|
+
| `GramLogisticRegression` | LogisticRegression(l1_ratio=1, solver='liblinear'), by majorization | `lasso-cov.scm` | CPU | no |
|
|
199
|
+
| `DesignLasso` | Lasso, fit(X, y) with the intercept, from the design | `lasso-design.scm (--derive)` | loops / BLAS / cuBLAS | no |
|
|
169
200
|
| `CovLasso` | Lasso, ElasticNet, lasso_path(precompute=True) | `lasso-cov.scm` | CPU; GPU batch (fit_path_batch, bootstrap) | no |
|
|
170
201
|
| `CovLassoCV` | LassoCV, ElasticNetCV | `lasso-cov.scm` | CPU; GPU batch | no |
|
|
171
202
|
| `DerivedLasso` | lasso_path, from the design | `lasso-design.scm (--derive)` | loops / BLAS / cuBLAS | no |
|
|
@@ -612,6 +643,15 @@ matrix (`KernelSVM`) or transposing X into columns
|
|
|
612
643
|
| `L1LogisticRegression`, 20,000 x 500, C=0.05 | 1.20 s | 2.23 s | 1.9x | 106.77913 / 106.77915 | 100% |
|
|
613
644
|
| `L1LogisticRegression`, 100,000 x 200, C=0.05 | 9.06 s | 18.7 s | 2.1x | 349.61154 / 349.61216 | 100% |
|
|
614
645
|
|
|
646
|
+
On 2,000 x 20,000 neither side reaches the optimum at tol 1e-4 (the
|
|
647
|
+
objective at tol 1e-10 is 0.0519588), and where each stops depends on
|
|
648
|
+
the coordinate order: over eight seeds ours stops at 0.05240 to
|
|
649
|
+
0.05251 (0.9 to 1.1% above the optimum), `LinearSVC`, whose order is
|
|
650
|
+
random unless `random_state` is given, at 0.05242 to 0.05319 (0.9 to
|
|
651
|
+
2.4%). When `LinearSVC` draws one of its worse orders the gap passes
|
|
652
|
+
the script's 0.5% bound and the row prints `<-- disagrees`; ours is
|
|
653
|
+
then the better solution of the two, so the flag there is not a fault.
|
|
654
|
+
|
|
615
655
|
The regressors, from the same script (C = 1, epsilon 0.1):
|
|
616
656
|
|
|
617
657
|
| problem | ours | scikit-learn | ratio | agreement |
|
|
@@ -89,7 +89,7 @@ them first; this solver does not do it for you.
|
|
|
89
89
|
From 0.14.0 every estimator with a `fit(X, y)` (or `fit(X)`) derives
|
|
90
90
|
from scikit-learn's `BaseEstimator` and the matching mixin, so `clone`,
|
|
91
91
|
`get_params` / `set_params`, `GridSearchCV`, `Pipeline` and
|
|
92
|
-
`cross_val_score` take them, and all
|
|
92
|
+
`cross_val_score` take them, and all 44 pass
|
|
93
93
|
`sklearn.utils.estimator_checks.check_estimator` (`check-sklearn.py`
|
|
94
94
|
runs it; the one expected failure is `LBFGSLogisticRegressionCV`'s
|
|
95
95
|
`n_iter_` of 0 for a C whose warm start is already converged, which
|
|
@@ -104,11 +104,37 @@ from scm2cpp_lasso import GramLasso
|
|
|
104
104
|
GridSearchCV(GramLasso(), {"alpha": [0.01, 0.1, 1.0]}, cv=5).fit(X, y)
|
|
105
105
|
```
|
|
106
106
|
|
|
107
|
-
`
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
`
|
|
111
|
-
|
|
107
|
+
`CovLasso`, `CovRidge`, `DerivedLasso`, `CovLogistic`,
|
|
108
|
+
`CovGroupLasso` and `CovMultiTaskLasso` keep their
|
|
109
|
+
data-in-the-constructor interface, which solves a whole path at once;
|
|
110
|
+
each has a `fit(X, y)` form with the intercept beside it (0.15.0):
|
|
111
|
+
|
|
112
|
+
| data in the constructor | `fit(X, y)` | scikit-learn |
|
|
113
|
+
|---|---|---|
|
|
114
|
+
| `CovLasso` | `GramLasso`, `GramElasticNet` | Lasso, ElasticNet |
|
|
115
|
+
| `CovRidge` | `GramRidge` | Ridge |
|
|
116
|
+
| `DerivedLasso` | `DesignLasso` | Lasso |
|
|
117
|
+
| `CovLogistic` | `GramLogisticRegression` | LogisticRegression(l1_ratio=1, solver="liblinear") |
|
|
118
|
+
| `CovGroupLasso` | `GramGroupLasso` (`groups=None`: the lasso) | (none) |
|
|
119
|
+
| `CovMultiTaskLasso` | `GramMultiTaskLasso`, `GramMultiTaskElasticNet` | MultiTaskLasso, MultiTaskElasticNet |
|
|
120
|
+
|
|
121
|
+
Against scikit-learn on 400 x 30 with an intercept: `DesignLasso` and
|
|
122
|
+
`GramGroupLasso(groups=None)` agree with `Lasso` to 1.5e-10, the
|
|
123
|
+
multi-task pair with `MultiTaskLasso` / `MultiTaskElasticNet` to
|
|
124
|
+
5e-14, and `GramLogisticRegression` reaches liblinear's objective to
|
|
125
|
+
eight digits with the same predictions.
|
|
126
|
+
|
|
127
|
+
Against the class each one wraps (one alpha, one core), which fits no
|
|
128
|
+
intercept and is unchanged: with `fit_intercept=False` the input checks
|
|
129
|
+
add 15 to 30 us a call (up to +50% on a 0.06 ms fit) and the finiteness
|
|
130
|
+
sum 8 to 14% on 20000 x 200 (none under `assume_finite`); with the
|
|
131
|
+
intercept, the column means add 20 to 30% on 20000 x 200 for the
|
|
132
|
+
Gram-matrix ones, which correct X'X
|
|
133
|
+
for the means rather than copy X to centre it, and about 55% for
|
|
134
|
+
`DesignLasso`, whose kernel needs the centred X itself.
|
|
135
|
+
`GramLogisticRegression` is slower than liblinear by its algorithm, 2.5x
|
|
136
|
+
at 20000 x 200 and more on small problems; `L1LogisticRegression` is
|
|
137
|
+
the fast one for that problem.
|
|
112
138
|
|
|
113
139
|
What it costs is the input checks: X must be a finite 2-D float64
|
|
114
140
|
array with the feature count of the fit. A plain C-ordered float64
|
|
@@ -148,6 +174,11 @@ package picks the fastest one present.
|
|
|
148
174
|
| `GramLasso` | Lasso(precompute=True), fit(X, y) with the intercept | `lasso-cov.scm` | CPU | no |
|
|
149
175
|
| `GramElasticNet` | ElasticNet(precompute=True), fit(X, y) with the intercept | `lasso-cov.scm` | CPU | no |
|
|
150
176
|
| `GramRidge` | Ridge, fit(X, y) with the intercept, one or many targets | numpy (Cholesky) | CPU | Ridge |
|
|
177
|
+
| `GramMultiTaskLasso` | MultiTaskLasso, fit(X, Y) with the intercept | `lasso-cov.scm` | CPU | no |
|
|
178
|
+
| `GramMultiTaskElasticNet` | MultiTaskElasticNet, fit(X, Y) with the intercept | `lasso-cov.scm` | CPU | no |
|
|
179
|
+
| `GramGroupLasso` | (none; skglm GroupLasso), fit(X, y) with the intercept | `lasso-cov.scm` | CPU | - |
|
|
180
|
+
| `GramLogisticRegression` | LogisticRegression(l1_ratio=1, solver='liblinear'), by majorization | `lasso-cov.scm` | CPU | no |
|
|
181
|
+
| `DesignLasso` | Lasso, fit(X, y) with the intercept, from the design | `lasso-design.scm (--derive)` | loops / BLAS / cuBLAS | no |
|
|
151
182
|
| `CovLasso` | Lasso, ElasticNet, lasso_path(precompute=True) | `lasso-cov.scm` | CPU; GPU batch (fit_path_batch, bootstrap) | no |
|
|
152
183
|
| `CovLassoCV` | LassoCV, ElasticNetCV | `lasso-cov.scm` | CPU; GPU batch | no |
|
|
153
184
|
| `DerivedLasso` | lasso_path, from the design | `lasso-design.scm (--derive)` | loops / BLAS / cuBLAS | no |
|
|
@@ -594,6 +625,15 @@ matrix (`KernelSVM`) or transposing X into columns
|
|
|
594
625
|
| `L1LogisticRegression`, 20,000 x 500, C=0.05 | 1.20 s | 2.23 s | 1.9x | 106.77913 / 106.77915 | 100% |
|
|
595
626
|
| `L1LogisticRegression`, 100,000 x 200, C=0.05 | 9.06 s | 18.7 s | 2.1x | 349.61154 / 349.61216 | 100% |
|
|
596
627
|
|
|
628
|
+
On 2,000 x 20,000 neither side reaches the optimum at tol 1e-4 (the
|
|
629
|
+
objective at tol 1e-10 is 0.0519588), and where each stops depends on
|
|
630
|
+
the coordinate order: over eight seeds ours stops at 0.05240 to
|
|
631
|
+
0.05251 (0.9 to 1.1% above the optimum), `LinearSVC`, whose order is
|
|
632
|
+
random unless `random_state` is given, at 0.05242 to 0.05319 (0.9 to
|
|
633
|
+
2.4%). When `LinearSVC` draws one of its worse orders the gap passes
|
|
634
|
+
the script's 0.5% bound and the row prints `<-- disagrees`; ours is
|
|
635
|
+
then the better solution of the two, so the flag there is not a fault.
|
|
636
|
+
|
|
597
637
|
The regressors, from the same script (C = 1, epsilon 0.1):
|
|
598
638
|
|
|
599
639
|
| problem | ours | scikit-learn | ratio | agreement |
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "scm2cpp-lasso"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.15.1"
|
|
8
8
|
description = "scikit-learn estimators (lasso, elastic net, ridge, ARD, SVM, SVR, logistic regression, GLMs, Huber, Theil-Sen, F-score selection, RFE, NMF, Gaussian mixture, FastICA, PCA, graphical lasso, RANSAC, SGD, OMP, LARS) translated from Scheme to C++ by scm2cpp; GPU batch solver and CUDA kernels included"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.8"
|
|
@@ -53,8 +53,10 @@ __all__ = ["GramLasso", "GramElasticNet", "GramRidge", "CovLasso", "CovRidge", "
|
|
|
53
53
|
"L1LinearSVM", "WeiszfeldTheilSen", "f_regression", "f_classif", "SelectKBest",
|
|
54
54
|
"SelectPercentile", "GramRFE",
|
|
55
55
|
"CovMultiTaskLasso", "CovMultiTaskLassoCV", "DerivedLasso",
|
|
56
|
+
"GramLogisticRegression", "GramGroupLasso", "GramMultiTaskLasso",
|
|
57
|
+
"GramMultiTaskElasticNet", "DesignLasso",
|
|
56
58
|
"cuda_available", "derived_backend", "kernel"]
|
|
57
|
-
__version__ = "0.
|
|
59
|
+
__version__ = "0.15.1"
|
|
58
60
|
|
|
59
61
|
_BATCH = load_batch_lib()
|
|
60
62
|
_DP = ctypes.POINTER(ctypes.c_double)
|
|
@@ -361,19 +363,50 @@ class DerivedLasso:
|
|
|
361
363
|
the column norms (folded into the Gram's diagonal when p < n),
|
|
362
364
|
builds the Gram matrix, walks the penalties, and leaves the
|
|
363
365
|
coefficient at each in a row of the result. tol is the largest move of
|
|
364
|
-
one coefficient in a sweep below which that lambda is done.
|
|
366
|
+
one coefficient in a sweep below which that lambda is done. The
|
|
367
|
+
kernel's value, the sweeps run over the whole path, is kept as
|
|
368
|
+
n_iter_.
|
|
365
369
|
"""
|
|
366
370
|
lams = np.ascontiguousarray(lambdas, dtype=np.float64).ravel()
|
|
367
371
|
beta = np.zeros(self.p)
|
|
368
372
|
resid = np.empty(self.nobs) # filled by the kernel from y
|
|
369
373
|
xnorm = np.empty(self.p) # the column norms, taken inside
|
|
370
374
|
betas = np.zeros(lams.size * self.p)
|
|
371
|
-
self._kernel.lasso_design(
|
|
372
|
-
|
|
373
|
-
|
|
375
|
+
self.n_iter_ = int(self._kernel.lasso_design(
|
|
376
|
+
self.X, self.y, resid, xnorm, beta, lams, betas, int(max_sweeps), float(tol),
|
|
377
|
+
self.nobs, self.p, lams.size))
|
|
374
378
|
return betas.reshape(lams.size, self.p)
|
|
375
379
|
|
|
376
380
|
|
|
381
|
+
class DesignLasso(Tagged, RegressorMixin, BaseEstimator):
|
|
382
|
+
"""scikit-learn's ``Lasso`` interface over DerivedLasso: fit(X, y)
|
|
383
|
+
centres the data when ``fit_intercept`` and runs the derived kernel
|
|
384
|
+
at one penalty ``alpha``, same objective as GramLasso. ``tol`` is
|
|
385
|
+
the kernel's (the largest absolute move of one coefficient in a
|
|
386
|
+
sweep), ``max_iter`` its sweep cap and ``backend`` DerivedLasso's.
|
|
387
|
+
|
|
388
|
+
Attributes after fit: coef_, intercept_, n_iter_ (the sweeps the
|
|
389
|
+
kernel ran), n_features_in_.
|
|
390
|
+
"""
|
|
391
|
+
|
|
392
|
+
def __init__(self, alpha=1.0, *, fit_intercept=True, tol=1e-8, max_iter=100000,
|
|
393
|
+
backend=None):
|
|
394
|
+
self.alpha, self.fit_intercept, self.tol, self.max_iter = alpha, fit_intercept, tol, max_iter
|
|
395
|
+
self.backend = backend
|
|
396
|
+
|
|
397
|
+
def fit(self, X, y):
|
|
398
|
+
X, y = fit_xy(self, X, y)
|
|
399
|
+
Xc, yc, xm, ym = _centered(X, y, self.fit_intercept)
|
|
400
|
+
m = DerivedLasso(Xc, yc, backend=self.backend)
|
|
401
|
+
self.coef_ = m.fit(float(self.alpha), tol=float(self.tol), max_sweeps=int(self.max_iter))
|
|
402
|
+
self.n_iter_ = m.n_iter_
|
|
403
|
+
self.intercept_ = float(ym - xm @ self.coef_)
|
|
404
|
+
return self
|
|
405
|
+
|
|
406
|
+
def predict(self, X):
|
|
407
|
+
return pred_x(self, X) @ self.coef_ + self.intercept_
|
|
408
|
+
|
|
409
|
+
|
|
377
410
|
def derived_backend():
|
|
378
411
|
"""The derived kernel variant DerivedLasso takes by default: 'cublas'
|
|
379
412
|
when built and a device answers, else 'blas', else 'loops'; None
|
|
@@ -669,6 +702,28 @@ def _centered(X, y, fit_intercept):
|
|
|
669
702
|
return np.ascontiguousarray(X - xm), y - ym, xm, ym
|
|
670
703
|
|
|
671
704
|
|
|
705
|
+
def _centered_gram(X, y, fit_intercept):
|
|
706
|
+
"""(Xc'Xc, Xc'yc, xm, ym) for the centred data Xc, yc, without
|
|
707
|
+
forming Xc: X'X - n xm xm' and X'y - n xm ym, which saves the copy
|
|
708
|
+
of X (as long as the Gram product itself on 20000 x 200 rows, where
|
|
709
|
+
it took the intercept from free to twice the fit). The correction
|
|
710
|
+
cancels digits when a column's mean is large against its spread,
|
|
711
|
+
about (mean / sd)^2 ulps, so a column with mean over 100 sd (or no
|
|
712
|
+
spread at all) sends the whole fit through the centred copy."""
|
|
713
|
+
n = X.shape[0]
|
|
714
|
+
G, c = X.T @ X, X.T @ y
|
|
715
|
+
if not fit_intercept:
|
|
716
|
+
return G, c, np.zeros(X.shape[1]), np.zeros(y.shape[1:]) if y.ndim > 1 else 0.0
|
|
717
|
+
xm, ym = X.mean(axis=0), y.mean(axis=0)
|
|
718
|
+
nm2 = n * xm * xm
|
|
719
|
+
if np.all(np.diagonal(G) - nm2 > 1e-4 * nm2):
|
|
720
|
+
G -= np.outer(xm, n * xm)
|
|
721
|
+
c -= np.multiply.outer(n * xm, ym)
|
|
722
|
+
return G, c, xm, ym
|
|
723
|
+
Xc, yc = np.ascontiguousarray(X - xm), y - ym
|
|
724
|
+
return Xc.T @ Xc, Xc.T @ yc, xm, ym
|
|
725
|
+
|
|
726
|
+
|
|
672
727
|
class GramElasticNet(Tagged, RegressorMixin, BaseEstimator):
|
|
673
728
|
"""scikit-learn's ``ElasticNet(precompute=True)`` interface over
|
|
674
729
|
CovLasso: fit(X, y) centres the data when ``fit_intercept``, forms
|
|
@@ -692,10 +747,10 @@ class GramElasticNet(Tagged, RegressorMixin, BaseEstimator):
|
|
|
692
747
|
|
|
693
748
|
def fit(self, X, y):
|
|
694
749
|
X, y = fit_xy(self, X, y)
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
g = np.ascontiguousarray(
|
|
698
|
-
c = np.ascontiguousarray(
|
|
750
|
+
n, p = X.shape
|
|
751
|
+
G, c, xm, ym = _centered_gram(X, y, self.fit_intercept)
|
|
752
|
+
g = np.ascontiguousarray(G.ravel())
|
|
753
|
+
c = np.ascontiguousarray(c)
|
|
699
754
|
lam, r = float(self.alpha), float(self.l1_ratio)
|
|
700
755
|
tol, cap = float(self.tol), int(self.max_iter)
|
|
701
756
|
beta, prev = np.zeros(p), np.empty(p)
|
|
@@ -747,11 +802,9 @@ class GramRidge(Tagged, RegressorMixin, BaseEstimator):
|
|
|
747
802
|
|
|
748
803
|
def fit(self, X, y):
|
|
749
804
|
X, y = fit_xy(self, X, y, multi_output=True)
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
A = Xc.T @ Xc
|
|
805
|
+
p = X.shape[1]
|
|
806
|
+
A, b, xm, ym = _centered_gram(X, y, self.fit_intercept)
|
|
753
807
|
A.flat[::p + 1] += float(self.alpha)
|
|
754
|
-
b = Xc.T @ yc
|
|
755
808
|
try:
|
|
756
809
|
coef = np.linalg.solve(A, b)
|
|
757
810
|
except np.linalg.LinAlgError:
|
|
@@ -2686,7 +2739,9 @@ class CovLogistic:
|
|
|
2686
2739
|
|
|
2687
2740
|
def _fit_one(self, beta, lam, tol, inner_sweeps, max_rounds):
|
|
2688
2741
|
beta = beta.copy()
|
|
2742
|
+
self._rounds = 0
|
|
2689
2743
|
for _ in range(max_rounds):
|
|
2744
|
+
self._rounds += 1
|
|
2690
2745
|
prev = beta.copy()
|
|
2691
2746
|
# the majorizer at beta: quadratic G/4, working
|
|
2692
2747
|
# correlations exactly X'(y - mu)
|
|
@@ -2699,6 +2754,58 @@ class CovLogistic:
|
|
|
2699
2754
|
return beta
|
|
2700
2755
|
|
|
2701
2756
|
|
|
2757
|
+
class GramLogisticRegression(Tagged, ClassifierMixin, BaseEstimator):
|
|
2758
|
+
"""scikit-learn's ``LogisticRegression(l1_ratio=1, solver="liblinear")``
|
|
2759
|
+
interface over CovLogistic: the same problem,
|
|
2760
|
+
|
|
2761
|
+
min_w ||w||_1 + C sum_i log(1 + exp(-y_i (w.x_i + b))),
|
|
2762
|
+
|
|
2763
|
+
solved by majorization over the Gram matrix instead of liblinear's
|
|
2764
|
+
Newton steps. As in liblinear the intercept is the weight of a
|
|
2765
|
+
constant column of value ``intercept_scaling`` and is penalized
|
|
2766
|
+
with the rest. ``tol`` is CovLogistic's (the largest coefficient
|
|
2767
|
+
move in a round, relative to their size) and ``max_iter`` caps the
|
|
2768
|
+
rounds. Two classes.
|
|
2769
|
+
|
|
2770
|
+
Attributes after fit: classes_, coef_, intercept_, n_iter_.
|
|
2771
|
+
"""
|
|
2772
|
+
|
|
2773
|
+
_binary_only = True
|
|
2774
|
+
|
|
2775
|
+
def __init__(self, C=1.0, *, fit_intercept=True, intercept_scaling=1.0, tol=1e-7,
|
|
2776
|
+
max_iter=500):
|
|
2777
|
+
self.C, self.fit_intercept, self.intercept_scaling = C, fit_intercept, intercept_scaling
|
|
2778
|
+
self.tol, self.max_iter = tol, max_iter
|
|
2779
|
+
|
|
2780
|
+
def fit(self, X, y):
|
|
2781
|
+
X, y = fit_xy(self, X, y, classifier=True)
|
|
2782
|
+
n = X.shape[0]
|
|
2783
|
+
self.classes_, ys = _binary_labels(y)
|
|
2784
|
+
s = float(self.intercept_scaling)
|
|
2785
|
+
if self.fit_intercept:
|
|
2786
|
+
X = np.column_stack([X, np.full(n, s)])
|
|
2787
|
+
m = CovLogistic(X, (ys > 0).astype(np.float64))
|
|
2788
|
+
lam = 1.0 / (n * float(self.C))
|
|
2789
|
+
beta = m._fit_one(np.zeros(m.p), lam, float(self.tol), 200, int(self.max_iter))
|
|
2790
|
+
self.n_iter_ = m._rounds
|
|
2791
|
+
if self.fit_intercept:
|
|
2792
|
+
self.coef_, self.intercept_ = beta[:-1].copy(), float(beta[-1]) * s
|
|
2793
|
+
else:
|
|
2794
|
+
self.coef_, self.intercept_ = beta, 0.0
|
|
2795
|
+
return self
|
|
2796
|
+
|
|
2797
|
+
def decision_function(self, X):
|
|
2798
|
+
return pred_x(self, X) @ self.coef_ + self.intercept_
|
|
2799
|
+
|
|
2800
|
+
def predict_proba(self, X):
|
|
2801
|
+
p1 = 1.0 / (1.0 + np.exp(-self.decision_function(X)))
|
|
2802
|
+
return np.column_stack([1.0 - p1, p1])
|
|
2803
|
+
|
|
2804
|
+
def predict(self, X):
|
|
2805
|
+
z = self.decision_function(X)
|
|
2806
|
+
return self.classes_[(z > 0).astype(int)]
|
|
2807
|
+
|
|
2808
|
+
|
|
2702
2809
|
class CovGroupLasso:
|
|
2703
2810
|
"""Group lasso over a design given by its Gram matrix.
|
|
2704
2811
|
|
|
@@ -2778,9 +2885,13 @@ class CovGroupLasso:
|
|
|
2778
2885
|
|
|
2779
2886
|
def _fit_one(self, beta, c, lam, tol, max_sweeps):
|
|
2780
2887
|
thr = lam * self.nobs
|
|
2888
|
+
self._sweeps = 0
|
|
2781
2889
|
for _ in range(max_sweeps):
|
|
2890
|
+
self._sweeps += 1
|
|
2782
2891
|
moved = 0.0
|
|
2783
2892
|
for g, w, L in zip(self.groups, self.wg, self.Lg):
|
|
2893
|
+
if L <= 0.0: # all-zero columns: the group stays at zero
|
|
2894
|
+
continue
|
|
2784
2895
|
bg = beta[g]
|
|
2785
2896
|
z = bg + c[g] / L
|
|
2786
2897
|
nz = float(np.linalg.norm(z))
|
|
@@ -2809,6 +2920,41 @@ class CovGroupLasso:
|
|
|
2809
2920
|
return quad / self.nobs + lam * pen
|
|
2810
2921
|
|
|
2811
2922
|
|
|
2923
|
+
class GramGroupLasso(Tagged, RegressorMixin, BaseEstimator):
|
|
2924
|
+
"""A ``Lasso``-style interface over CovGroupLasso: fit(X, y) centres
|
|
2925
|
+
the data when ``fit_intercept`` and runs the block descent at
|
|
2926
|
+
``alpha``,
|
|
2927
|
+
|
|
2928
|
+
(1 / 2 n) ||y - X b - b0||^2 + alpha sum_g sqrt(|g|) ||b_g||_2.
|
|
2929
|
+
|
|
2930
|
+
``groups`` is a list of index arrays partitioning the columns, or
|
|
2931
|
+
None for one group per column (the lasso). ``tol`` is
|
|
2932
|
+
CovGroupLasso's and ``max_iter`` its sweep cap.
|
|
2933
|
+
|
|
2934
|
+
Attributes after fit: coef_, intercept_, n_iter_, n_features_in_.
|
|
2935
|
+
"""
|
|
2936
|
+
|
|
2937
|
+
def __init__(self, alpha=1.0, *, groups=None, fit_intercept=True, tol=1e-8,
|
|
2938
|
+
max_iter=10000):
|
|
2939
|
+
self.alpha, self.groups, self.fit_intercept = alpha, groups, fit_intercept
|
|
2940
|
+
self.tol, self.max_iter = tol, max_iter
|
|
2941
|
+
|
|
2942
|
+
def fit(self, X, y):
|
|
2943
|
+
X, y = fit_xy(self, X, y)
|
|
2944
|
+
n, p = X.shape
|
|
2945
|
+
G, c, xm, ym = _centered_gram(X, y, self.fit_intercept)
|
|
2946
|
+
groups = [[j] for j in range(p)] if self.groups is None else self.groups
|
|
2947
|
+
m = CovGroupLasso(gram=G, corr=c, nobs=n, groups=groups)
|
|
2948
|
+
beta, _ = m._fit_one(np.zeros(p), m.c0.copy(), float(self.alpha), float(self.tol),
|
|
2949
|
+
int(self.max_iter))
|
|
2950
|
+
self.coef_, self.n_iter_ = beta, m._sweeps
|
|
2951
|
+
self.intercept_ = float(ym - xm @ self.coef_)
|
|
2952
|
+
return self
|
|
2953
|
+
|
|
2954
|
+
def predict(self, X):
|
|
2955
|
+
return pred_x(self, X) @ self.coef_ + self.intercept_
|
|
2956
|
+
|
|
2957
|
+
|
|
2812
2958
|
class CovMultiTaskLasso:
|
|
2813
2959
|
"""Multi-task lasso and elastic net over a design's Gram matrix.
|
|
2814
2960
|
|
|
@@ -2929,6 +3075,69 @@ class CovMultiTaskLasso:
|
|
|
2929
3075
|
return out.reshape(lambdas.size, self.p, self.n_tasks)
|
|
2930
3076
|
|
|
2931
3077
|
|
|
3078
|
+
class GramMultiTaskElasticNet(Tagged, RegressorMixin, BaseEstimator):
|
|
3079
|
+
"""scikit-learn's ``MultiTaskElasticNet`` interface over
|
|
3080
|
+
CovMultiTaskLasso: fit(X, Y) centres the data when
|
|
3081
|
+
``fit_intercept``, forms the Gram matrix once and runs the row-block
|
|
3082
|
+
sweep at ``alpha``. Y is (n, n_tasks); coef_ is (n_tasks, p) as
|
|
3083
|
+
scikit-learn has it. ``tol`` is CovMultiTaskLasso's and
|
|
3084
|
+
``max_iter`` its sweep cap.
|
|
3085
|
+
|
|
3086
|
+
Attributes after fit: coef_, intercept_, n_iter_, n_features_in_.
|
|
3087
|
+
"""
|
|
3088
|
+
|
|
3089
|
+
_multi_output = "only"
|
|
3090
|
+
|
|
3091
|
+
def __init__(self, alpha=1.0, *, l1_ratio=0.5, fit_intercept=True, tol=1e-8,
|
|
3092
|
+
max_iter=100000):
|
|
3093
|
+
self.alpha, self.l1_ratio, self.fit_intercept = alpha, l1_ratio, fit_intercept
|
|
3094
|
+
self.tol, self.max_iter = tol, max_iter
|
|
3095
|
+
|
|
3096
|
+
def fit(self, X, y):
|
|
3097
|
+
X, y = fit_xy(self, X, y, multi_output=True)
|
|
3098
|
+
if y.ndim != 2:
|
|
3099
|
+
raise ValueError("For mono-task outputs, use GramElasticNet or GramLasso; "
|
|
3100
|
+
"y must be (n_samples, n_tasks)")
|
|
3101
|
+
n, p = X.shape
|
|
3102
|
+
t = y.shape[1]
|
|
3103
|
+
G, c, xm, ym = _centered_gram(X, y, self.fit_intercept)
|
|
3104
|
+
g = np.ascontiguousarray(G.ravel())
|
|
3105
|
+
c = np.ascontiguousarray(c.ravel())
|
|
3106
|
+
lam, r = float(self.alpha), float(self.l1_ratio)
|
|
3107
|
+
tol, cap = float(self.tol), int(self.max_iter)
|
|
3108
|
+
W, prev = np.zeros(p * t), np.empty(p * t)
|
|
3109
|
+
swept = 0
|
|
3110
|
+
while swept < cap:
|
|
3111
|
+
chunk = min(20, cap - swept)
|
|
3112
|
+
prev[:] = W
|
|
3113
|
+
kernel.mt_descend(g, c, W, lam * r, lam * (1.0 - r), chunk, float(n), p, t)
|
|
3114
|
+
swept += chunk
|
|
3115
|
+
if np.max(np.abs(W - prev)) < tol * _scale(W):
|
|
3116
|
+
break
|
|
3117
|
+
W = W.reshape(p, t)
|
|
3118
|
+
self.coef_, self.n_iter_ = np.ascontiguousarray(W.T), swept
|
|
3119
|
+
self.intercept_ = ym - xm @ W
|
|
3120
|
+
return self
|
|
3121
|
+
|
|
3122
|
+
def predict(self, X):
|
|
3123
|
+
return pred_x(self, X) @ self.coef_.T + self.intercept_
|
|
3124
|
+
|
|
3125
|
+
|
|
3126
|
+
class GramMultiTaskLasso(GramMultiTaskElasticNet):
|
|
3127
|
+
"""scikit-learn's ``MultiTaskLasso`` interface over CovMultiTaskLasso:
|
|
3128
|
+
GramMultiTaskElasticNet with l1_ratio 1.
|
|
3129
|
+
|
|
3130
|
+
Attributes after fit: coef_, intercept_, n_iter_, n_features_in_.
|
|
3131
|
+
"""
|
|
3132
|
+
|
|
3133
|
+
def __init__(self, alpha=1.0, *, fit_intercept=True, tol=1e-8, max_iter=100000):
|
|
3134
|
+
self.alpha, self.fit_intercept, self.tol, self.max_iter = alpha, fit_intercept, tol, max_iter
|
|
3135
|
+
|
|
3136
|
+
@property
|
|
3137
|
+
def l1_ratio(self):
|
|
3138
|
+
return 1.0
|
|
3139
|
+
|
|
3140
|
+
|
|
2932
3141
|
class CovMultiTaskLassoCV(Tagged, RegressorMixin, BaseEstimator):
|
|
2933
3142
|
"""scikit-learn's ``MultiTaskLassoCV`` (``MultiTaskElasticNetCV``
|
|
2934
3143
|
with ``l1_ratio``) over the covariance machinery.
|
|
@@ -191,7 +191,8 @@ def _reset_names(est):
|
|
|
191
191
|
|
|
192
192
|
def fit_xy(est, X, y, *, y_numeric=True, multi_output=False, classifier=False):
|
|
193
193
|
"""X as a float64 C-ordered 2-D array and y, validated, n_features_in_ set."""
|
|
194
|
-
if (_plain(X) and type(y) is np.ndarray and y.
|
|
194
|
+
if (_plain(X) and type(y) is np.ndarray and y.shape[0:1] == X.shape[0:1]
|
|
195
|
+
and (y.ndim == 1 or (multi_output and y.ndim == 2 and y.shape[1] > 1))
|
|
195
196
|
and _finite(X)):
|
|
196
197
|
if classifier:
|
|
197
198
|
ok = _labels_ok(y)
|
|
@@ -30,26 +30,28 @@ soft_threshold( double z, double g )
|
|
|
30
30
|
|
|
31
31
|
inline int
|
|
32
32
|
lasso_design( scm2cpp::cspan<double> x, scm2cpp::cspan<double> y, scm2cpp::span<double> resid, scm2cpp::span<double> xnorm, scm2cpp::span<double> beta, scm2cpp::cspan<double> lams, scm2cpp::span<double> betas, int iters, double tol, int n, int p, int nlam )
|
|
33
|
-
{
|
|
33
|
+
{ int swept = 0;
|
|
34
|
+
if( p < n ) {
|
|
34
35
|
for( int i = 0 ; !(i == n) ; i = (i+1) ) {
|
|
35
36
|
resid[ i ] = y[i] ;
|
|
36
37
|
} ;
|
|
37
38
|
0 ;
|
|
38
|
-
std::vector<double>
|
|
39
|
-
std::vector<double>
|
|
40
|
-
std::vector<double>
|
|
41
|
-
scm2cpp::blas_syrk(
|
|
42
|
-
scm2cpp::blas_gemv(
|
|
39
|
+
std::vector<double> b03446(p,0.0);
|
|
40
|
+
std::vector<double> g3445((p*p),0.0);
|
|
41
|
+
std::vector<double> c3444(p,0.0);
|
|
42
|
+
scm2cpp::blas_syrk(g3445, x, 1.0, 0.0, 1, p, n) ;
|
|
43
|
+
scm2cpp::blas_gemv(c3444, x, resid, 1.0, 0.0, 1, p, n) ;
|
|
43
44
|
for( int l = 0 ; !(l == nlam) ; l = (l+1) ) {
|
|
44
45
|
double lam = lams[l];
|
|
45
46
|
int stop = 0;
|
|
46
47
|
for( int sweep = 0 ; !((sweep == iters || stop == 1)) ; sweep = (sweep+1) ) {
|
|
48
|
+
swept = (swept+1) ;
|
|
47
49
|
double maxmove = 0.0;
|
|
48
50
|
for( int j = 0 ; !(j == p) ; j = (j+1) ) {
|
|
49
|
-
double rho =
|
|
51
|
+
double rho = c3444[j];
|
|
50
52
|
double old = beta[j];
|
|
51
|
-
rho = (rho+(old*
|
|
52
|
-
double bnew = (soft_threshold(rho,double((lam*(1.0*n))))/
|
|
53
|
+
rho = (rho+(old*g3445[((j*p)+j)])) ;
|
|
54
|
+
double bnew = (soft_threshold(rho,double((lam*(1.0*n))))/g3445[((j*p)+j)]);
|
|
53
55
|
beta[ j ] = bnew ;
|
|
54
56
|
if( !(bnew == old) ) {
|
|
55
57
|
if( (bnew-old) > maxmove ) {
|
|
@@ -62,9 +64,9 @@ lasso_design( scm2cpp::cspan<double> x, scm2cpp::cspan<double> y, scm2cpp::spa
|
|
|
62
64
|
} else {
|
|
63
65
|
0 ;
|
|
64
66
|
} ;
|
|
65
|
-
|
|
66
|
-
for( int
|
|
67
|
-
|
|
67
|
+
b03446[ j ] = (b03446[j]+(bnew-old)) ;
|
|
68
|
+
for( int k3448 = 0 ; !(k3448 == p) ; k3448 = (k3448+1) ) {
|
|
69
|
+
c3444[ k3448 ] = (c3444[k3448]-(g3445[((j*p)+k3448)]*(bnew-old))) ;
|
|
68
70
|
} ;
|
|
69
71
|
} else {
|
|
70
72
|
false ;
|
|
@@ -85,7 +87,7 @@ lasso_design( scm2cpp::cspan<double> x, scm2cpp::cspan<double> y, scm2cpp::spa
|
|
|
85
87
|
} ;
|
|
86
88
|
;
|
|
87
89
|
} ;
|
|
88
|
-
scm2cpp::blas_gemv(resid, x,
|
|
90
|
+
scm2cpp::blas_gemv(resid, x, b03446, -1.0, 1.0, 0, n, p) ;
|
|
89
91
|
0 ;
|
|
90
92
|
;
|
|
91
93
|
} else {
|
|
@@ -104,6 +106,7 @@ lasso_design( scm2cpp::cspan<double> x, scm2cpp::cspan<double> y, scm2cpp::spa
|
|
|
104
106
|
double lam = lams[l];
|
|
105
107
|
int stop = 0;
|
|
106
108
|
for( int sweep = 0 ; !((sweep == iters || stop == 1)) ; sweep = (sweep+1) ) {
|
|
109
|
+
swept = (swept+1) ;
|
|
107
110
|
double maxmove = 0.0;
|
|
108
111
|
for( int j = 0 ; !(j == p) ; j = (j+1) ) {
|
|
109
112
|
double rho = 0.0;
|
|
@@ -148,6 +151,6 @@ lasso_design( scm2cpp::cspan<double> x, scm2cpp::cspan<double> y, scm2cpp::spa
|
|
|
148
151
|
;
|
|
149
152
|
} ;
|
|
150
153
|
} ;
|
|
151
|
-
return
|
|
154
|
+
return swept ;
|
|
152
155
|
}
|
|
153
156
|
#endif // LASSO_DESIGN_HPP
|
|
@@ -30,27 +30,29 @@ soft_threshold( double z, double g )
|
|
|
30
30
|
|
|
31
31
|
inline int
|
|
32
32
|
lasso_design( scm2cpp::cspan<double> x, scm2cpp::cspan<double> y, scm2cpp::span<double> resid, scm2cpp::span<double> xnorm, scm2cpp::span<double> beta, scm2cpp::cspan<double> lams, scm2cpp::span<double> betas, int iters, double tol, int n, int p, int nlam )
|
|
33
|
-
{
|
|
33
|
+
{ int swept = 0;
|
|
34
|
+
if( p < n ) {
|
|
34
35
|
for( int i = 0 ; !(i == n) ; i = (i+1) ) {
|
|
35
36
|
resid[ i ] = y[i] ;
|
|
36
37
|
} ;
|
|
37
38
|
0 ;
|
|
38
|
-
std::vector<double>
|
|
39
|
-
std::vector<double>
|
|
40
|
-
std::vector<double>
|
|
41
|
-
scm2cpp::device_matrix
|
|
42
|
-
scm2cpp::blas_syrk(
|
|
43
|
-
scm2cpp::blas_gemv(
|
|
39
|
+
std::vector<double> b03446(p,0.0);
|
|
40
|
+
std::vector<double> g3445((p*p),0.0);
|
|
41
|
+
std::vector<double> c3444(p,0.0);
|
|
42
|
+
scm2cpp::device_matrix d3454 = scm2cpp::dmat_upload(x, (n*p), 1);
|
|
43
|
+
scm2cpp::blas_syrk(g3445, d3454, 1.0, 0.0, 1, p, n) ;
|
|
44
|
+
scm2cpp::blas_gemv(c3444, d3454, resid, 1.0, 0.0, 1, p, n) ;
|
|
44
45
|
for( int l = 0 ; !(l == nlam) ; l = (l+1) ) {
|
|
45
46
|
double lam = lams[l];
|
|
46
47
|
int stop = 0;
|
|
47
48
|
for( int sweep = 0 ; !((sweep == iters || stop == 1)) ; sweep = (sweep+1) ) {
|
|
49
|
+
swept = (swept+1) ;
|
|
48
50
|
double maxmove = 0.0;
|
|
49
51
|
for( int j = 0 ; !(j == p) ; j = (j+1) ) {
|
|
50
|
-
double rho =
|
|
52
|
+
double rho = c3444[j];
|
|
51
53
|
double old = beta[j];
|
|
52
|
-
rho = (rho+(old*
|
|
53
|
-
double bnew = (soft_threshold(rho,double((lam*(1.0*n))))/
|
|
54
|
+
rho = (rho+(old*g3445[((j*p)+j)])) ;
|
|
55
|
+
double bnew = (soft_threshold(rho,double((lam*(1.0*n))))/g3445[((j*p)+j)]);
|
|
54
56
|
beta[ j ] = bnew ;
|
|
55
57
|
if( !(bnew == old) ) {
|
|
56
58
|
if( (bnew-old) > maxmove ) {
|
|
@@ -63,9 +65,9 @@ lasso_design( scm2cpp::cspan<double> x, scm2cpp::cspan<double> y, scm2cpp::spa
|
|
|
63
65
|
} else {
|
|
64
66
|
0 ;
|
|
65
67
|
} ;
|
|
66
|
-
|
|
67
|
-
for( int
|
|
68
|
-
|
|
68
|
+
b03446[ j ] = (b03446[j]+(bnew-old)) ;
|
|
69
|
+
for( int k3448 = 0 ; !(k3448 == p) ; k3448 = (k3448+1) ) {
|
|
70
|
+
c3444[ k3448 ] = (c3444[k3448]-(g3445[((j*p)+k3448)]*(bnew-old))) ;
|
|
69
71
|
} ;
|
|
70
72
|
} else {
|
|
71
73
|
false ;
|
|
@@ -86,7 +88,7 @@ lasso_design( scm2cpp::cspan<double> x, scm2cpp::cspan<double> y, scm2cpp::spa
|
|
|
86
88
|
} ;
|
|
87
89
|
;
|
|
88
90
|
} ;
|
|
89
|
-
scm2cpp::blas_gemv(resid,
|
|
91
|
+
scm2cpp::blas_gemv(resid, d3454, b03446, -1.0, 1.0, 0, n, p) ;
|
|
90
92
|
0 ;
|
|
91
93
|
;
|
|
92
94
|
;
|
|
@@ -106,6 +108,7 @@ lasso_design( scm2cpp::cspan<double> x, scm2cpp::cspan<double> y, scm2cpp::spa
|
|
|
106
108
|
double lam = lams[l];
|
|
107
109
|
int stop = 0;
|
|
108
110
|
for( int sweep = 0 ; !((sweep == iters || stop == 1)) ; sweep = (sweep+1) ) {
|
|
111
|
+
swept = (swept+1) ;
|
|
109
112
|
double maxmove = 0.0;
|
|
110
113
|
for( int j = 0 ; !(j == p) ; j = (j+1) ) {
|
|
111
114
|
double rho = 0.0;
|
|
@@ -150,6 +153,6 @@ lasso_design( scm2cpp::cspan<double> x, scm2cpp::cspan<double> y, scm2cpp::spa
|
|
|
150
153
|
;
|
|
151
154
|
} ;
|
|
152
155
|
} ;
|
|
153
|
-
return
|
|
156
|
+
return swept ;
|
|
154
157
|
}
|
|
155
158
|
#endif // LASSO_DESIGN_HPP
|
|
@@ -29,43 +29,45 @@ soft_threshold( double z, double g )
|
|
|
29
29
|
|
|
30
30
|
inline int
|
|
31
31
|
lasso_design( scm2cpp::cspan<double> x, scm2cpp::cspan<double> y, scm2cpp::span<double> resid, scm2cpp::span<double> xnorm, scm2cpp::span<double> beta, scm2cpp::cspan<double> lams, scm2cpp::span<double> betas, int iters, double tol, int n, int p, int nlam )
|
|
32
|
-
{
|
|
32
|
+
{ int swept = 0;
|
|
33
|
+
if( p < n ) {
|
|
33
34
|
for( int i = 0 ; !(i == n) ; i = (i+1) ) {
|
|
34
35
|
resid[ i ] = y[i] ;
|
|
35
36
|
} ;
|
|
36
37
|
0 ;
|
|
37
|
-
std::vector<double>
|
|
38
|
-
std::vector<double>
|
|
39
|
-
std::vector<double>
|
|
38
|
+
std::vector<double> b03446(p,0.0);
|
|
39
|
+
std::vector<double> g3445((p*p),0.0);
|
|
40
|
+
std::vector<double> c3444(p,0.0);
|
|
40
41
|
for( int y2491 = 0 ; !(y2491 == p) ; y2491 = (y2491+1) ) {
|
|
41
42
|
for( int y2492 = y2491 ; !(y2492 == p) ; y2492 = (y2492+1) ) {
|
|
42
|
-
|
|
43
|
-
int
|
|
44
|
-
double
|
|
45
|
-
k2493 =
|
|
46
|
-
sum2498 =
|
|
43
|
+
g3445[ ((y2491*p)+y2492) ] = ([&]() -> double { int k2493 = 0; double sum2498 = 0.0; while (!(k2493 == n)) {
|
|
44
|
+
int k2493_next3454 = (k2493+1);
|
|
45
|
+
double sum2498_next3455 = (sum2498+(x[((k2493*p)+y2491)]*x[((k2493*p)+y2492)]));
|
|
46
|
+
k2493 = k2493_next3454;
|
|
47
|
+
sum2498 = sum2498_next3455;
|
|
47
48
|
} return sum2498; })() ;
|
|
48
|
-
|
|
49
|
+
g3445[ ((y2492*p)+y2491) ] = g3445[((y2491*p)+y2492)] ;
|
|
49
50
|
} ;
|
|
50
51
|
} ;
|
|
51
52
|
for( int y2494 = 0 ; !(y2494 == p) ; y2494 = (y2494+1) ) {
|
|
52
|
-
|
|
53
|
-
int
|
|
54
|
-
double
|
|
55
|
-
k2495 =
|
|
56
|
-
sum2500 =
|
|
53
|
+
c3444[ y2494 ] = ([&]() -> double { int k2495 = 0; double sum2500 = 0.0; while (!(k2495 == n)) {
|
|
54
|
+
int k2495_next3456 = (k2495+1);
|
|
55
|
+
double sum2500_next3457 = (sum2500+(x[((k2495*p)+y2494)]*resid[k2495]));
|
|
56
|
+
k2495 = k2495_next3456;
|
|
57
|
+
sum2500 = sum2500_next3457;
|
|
57
58
|
} return sum2500; })() ;
|
|
58
59
|
} ;
|
|
59
60
|
for( int l = 0 ; !(l == nlam) ; l = (l+1) ) {
|
|
60
61
|
double lam = lams[l];
|
|
61
62
|
int stop = 0;
|
|
62
63
|
for( int sweep = 0 ; !((sweep == iters || stop == 1)) ; sweep = (sweep+1) ) {
|
|
64
|
+
swept = (swept+1) ;
|
|
63
65
|
double maxmove = 0.0;
|
|
64
66
|
for( int j = 0 ; !(j == p) ; j = (j+1) ) {
|
|
65
|
-
double rho =
|
|
67
|
+
double rho = c3444[j];
|
|
66
68
|
double old = beta[j];
|
|
67
|
-
rho = (rho+(old*
|
|
68
|
-
double bnew = (soft_threshold(rho,double((lam*(1.0*n))))/
|
|
69
|
+
rho = (rho+(old*g3445[((j*p)+j)])) ;
|
|
70
|
+
double bnew = (soft_threshold(rho,double((lam*(1.0*n))))/g3445[((j*p)+j)]);
|
|
69
71
|
beta[ j ] = bnew ;
|
|
70
72
|
if( !(bnew == old) ) {
|
|
71
73
|
if( (bnew-old) > maxmove ) {
|
|
@@ -78,9 +80,9 @@ lasso_design( scm2cpp::cspan<double> x, scm2cpp::cspan<double> y, scm2cpp::spa
|
|
|
78
80
|
} else {
|
|
79
81
|
0 ;
|
|
80
82
|
} ;
|
|
81
|
-
|
|
82
|
-
for( int
|
|
83
|
-
|
|
83
|
+
b03446[ j ] = (b03446[j]+(bnew-old)) ;
|
|
84
|
+
for( int k3448 = 0 ; !(k3448 == p) ; k3448 = (k3448+1) ) {
|
|
85
|
+
c3444[ k3448 ] = (c3444[k3448]-(g3445[((j*p)+k3448)]*(bnew-old))) ;
|
|
84
86
|
} ;
|
|
85
87
|
} else {
|
|
86
88
|
false ;
|
|
@@ -103,10 +105,10 @@ lasso_design( scm2cpp::cspan<double> x, scm2cpp::cspan<double> y, scm2cpp::spa
|
|
|
103
105
|
} ;
|
|
104
106
|
for( int y2496 = 0 ; !(y2496 == n) ; y2496 = (y2496+1) ) {
|
|
105
107
|
resid[ y2496 ] = (resid[y2496]-([&]() -> double { int k2497 = 0; double sum2502 = 0.0; while (!(k2497 == p)) {
|
|
106
|
-
int
|
|
107
|
-
double
|
|
108
|
-
k2497 =
|
|
109
|
-
sum2502 =
|
|
108
|
+
int k2497_next3458 = (k2497+1);
|
|
109
|
+
double sum2502_next3459 = (sum2502+(b03446[k2497]*x[((y2496*p)+k2497)]));
|
|
110
|
+
k2497 = k2497_next3458;
|
|
111
|
+
sum2502 = sum2502_next3459;
|
|
110
112
|
} return sum2502; })()) ;
|
|
111
113
|
} ;
|
|
112
114
|
0 ;
|
|
@@ -127,6 +129,7 @@ lasso_design( scm2cpp::cspan<double> x, scm2cpp::cspan<double> y, scm2cpp::spa
|
|
|
127
129
|
double lam = lams[l];
|
|
128
130
|
int stop = 0;
|
|
129
131
|
for( int sweep = 0 ; !((sweep == iters || stop == 1)) ; sweep = (sweep+1) ) {
|
|
132
|
+
swept = (swept+1) ;
|
|
130
133
|
double maxmove = 0.0;
|
|
131
134
|
for( int j = 0 ; !(j == p) ; j = (j+1) ) {
|
|
132
135
|
double rho = 0.0;
|
|
@@ -171,6 +174,6 @@ lasso_design( scm2cpp::cspan<double> x, scm2cpp::cspan<double> y, scm2cpp::spa
|
|
|
171
174
|
;
|
|
172
175
|
} ;
|
|
173
176
|
} ;
|
|
174
|
-
return
|
|
177
|
+
return swept ;
|
|
175
178
|
}
|
|
176
179
|
#endif // LASSO_DESIGN_HPP
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: scm2cpp-lasso
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.15.1
|
|
4
4
|
Summary: scikit-learn estimators (lasso, elastic net, ridge, ARD, SVM, SVR, logistic regression, GLMs, Huber, Theil-Sen, F-score selection, RFE, NMF, Gaussian mixture, FastICA, PCA, graphical lasso, RANSAC, SGD, OMP, LARS) translated from Scheme to C++ by scm2cpp; GPU batch solver and CUDA kernels included
|
|
5
5
|
Author: Hirotaka Niitsuma
|
|
6
6
|
License: MIT
|
|
@@ -107,7 +107,7 @@ them first; this solver does not do it for you.
|
|
|
107
107
|
From 0.14.0 every estimator with a `fit(X, y)` (or `fit(X)`) derives
|
|
108
108
|
from scikit-learn's `BaseEstimator` and the matching mixin, so `clone`,
|
|
109
109
|
`get_params` / `set_params`, `GridSearchCV`, `Pipeline` and
|
|
110
|
-
`cross_val_score` take them, and all
|
|
110
|
+
`cross_val_score` take them, and all 44 pass
|
|
111
111
|
`sklearn.utils.estimator_checks.check_estimator` (`check-sklearn.py`
|
|
112
112
|
runs it; the one expected failure is `LBFGSLogisticRegressionCV`'s
|
|
113
113
|
`n_iter_` of 0 for a C whose warm start is already converged, which
|
|
@@ -122,11 +122,37 @@ from scm2cpp_lasso import GramLasso
|
|
|
122
122
|
GridSearchCV(GramLasso(), {"alpha": [0.01, 0.1, 1.0]}, cv=5).fit(X, y)
|
|
123
123
|
```
|
|
124
124
|
|
|
125
|
-
`
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
`
|
|
129
|
-
|
|
125
|
+
`CovLasso`, `CovRidge`, `DerivedLasso`, `CovLogistic`,
|
|
126
|
+
`CovGroupLasso` and `CovMultiTaskLasso` keep their
|
|
127
|
+
data-in-the-constructor interface, which solves a whole path at once;
|
|
128
|
+
each has a `fit(X, y)` form with the intercept beside it (0.15.0):
|
|
129
|
+
|
|
130
|
+
| data in the constructor | `fit(X, y)` | scikit-learn |
|
|
131
|
+
|---|---|---|
|
|
132
|
+
| `CovLasso` | `GramLasso`, `GramElasticNet` | Lasso, ElasticNet |
|
|
133
|
+
| `CovRidge` | `GramRidge` | Ridge |
|
|
134
|
+
| `DerivedLasso` | `DesignLasso` | Lasso |
|
|
135
|
+
| `CovLogistic` | `GramLogisticRegression` | LogisticRegression(l1_ratio=1, solver="liblinear") |
|
|
136
|
+
| `CovGroupLasso` | `GramGroupLasso` (`groups=None`: the lasso) | (none) |
|
|
137
|
+
| `CovMultiTaskLasso` | `GramMultiTaskLasso`, `GramMultiTaskElasticNet` | MultiTaskLasso, MultiTaskElasticNet |
|
|
138
|
+
|
|
139
|
+
Against scikit-learn on 400 x 30 with an intercept: `DesignLasso` and
|
|
140
|
+
`GramGroupLasso(groups=None)` agree with `Lasso` to 1.5e-10, the
|
|
141
|
+
multi-task pair with `MultiTaskLasso` / `MultiTaskElasticNet` to
|
|
142
|
+
5e-14, and `GramLogisticRegression` reaches liblinear's objective to
|
|
143
|
+
eight digits with the same predictions.
|
|
144
|
+
|
|
145
|
+
Against the class each one wraps (one alpha, one core), which fits no
|
|
146
|
+
intercept and is unchanged: with `fit_intercept=False` the input checks
|
|
147
|
+
add 15 to 30 us a call (up to +50% on a 0.06 ms fit) and the finiteness
|
|
148
|
+
sum 8 to 14% on 20000 x 200 (none under `assume_finite`); with the
|
|
149
|
+
intercept, the column means add 20 to 30% on 20000 x 200 for the
|
|
150
|
+
Gram-matrix ones, which correct X'X
|
|
151
|
+
for the means rather than copy X to centre it, and about 55% for
|
|
152
|
+
`DesignLasso`, whose kernel needs the centred X itself.
|
|
153
|
+
`GramLogisticRegression` is slower than liblinear by its algorithm, 2.5x
|
|
154
|
+
at 20000 x 200 and more on small problems; `L1LogisticRegression` is
|
|
155
|
+
the fast one for that problem.
|
|
130
156
|
|
|
131
157
|
What it costs is the input checks: X must be a finite 2-D float64
|
|
132
158
|
array with the feature count of the fit. A plain C-ordered float64
|
|
@@ -166,6 +192,11 @@ package picks the fastest one present.
|
|
|
166
192
|
| `GramLasso` | Lasso(precompute=True), fit(X, y) with the intercept | `lasso-cov.scm` | CPU | no |
|
|
167
193
|
| `GramElasticNet` | ElasticNet(precompute=True), fit(X, y) with the intercept | `lasso-cov.scm` | CPU | no |
|
|
168
194
|
| `GramRidge` | Ridge, fit(X, y) with the intercept, one or many targets | numpy (Cholesky) | CPU | Ridge |
|
|
195
|
+
| `GramMultiTaskLasso` | MultiTaskLasso, fit(X, Y) with the intercept | `lasso-cov.scm` | CPU | no |
|
|
196
|
+
| `GramMultiTaskElasticNet` | MultiTaskElasticNet, fit(X, Y) with the intercept | `lasso-cov.scm` | CPU | no |
|
|
197
|
+
| `GramGroupLasso` | (none; skglm GroupLasso), fit(X, y) with the intercept | `lasso-cov.scm` | CPU | - |
|
|
198
|
+
| `GramLogisticRegression` | LogisticRegression(l1_ratio=1, solver='liblinear'), by majorization | `lasso-cov.scm` | CPU | no |
|
|
199
|
+
| `DesignLasso` | Lasso, fit(X, y) with the intercept, from the design | `lasso-design.scm (--derive)` | loops / BLAS / cuBLAS | no |
|
|
169
200
|
| `CovLasso` | Lasso, ElasticNet, lasso_path(precompute=True) | `lasso-cov.scm` | CPU; GPU batch (fit_path_batch, bootstrap) | no |
|
|
170
201
|
| `CovLassoCV` | LassoCV, ElasticNetCV | `lasso-cov.scm` | CPU; GPU batch | no |
|
|
171
202
|
| `DerivedLasso` | lasso_path, from the design | `lasso-design.scm (--derive)` | loops / BLAS / cuBLAS | no |
|
|
@@ -612,6 +643,15 @@ matrix (`KernelSVM`) or transposing X into columns
|
|
|
612
643
|
| `L1LogisticRegression`, 20,000 x 500, C=0.05 | 1.20 s | 2.23 s | 1.9x | 106.77913 / 106.77915 | 100% |
|
|
613
644
|
| `L1LogisticRegression`, 100,000 x 200, C=0.05 | 9.06 s | 18.7 s | 2.1x | 349.61154 / 349.61216 | 100% |
|
|
614
645
|
|
|
646
|
+
On 2,000 x 20,000 neither side reaches the optimum at tol 1e-4 (the
|
|
647
|
+
objective at tol 1e-10 is 0.0519588), and where each stops depends on
|
|
648
|
+
the coordinate order: over eight seeds ours stops at 0.05240 to
|
|
649
|
+
0.05251 (0.9 to 1.1% above the optimum), `LinearSVC`, whose order is
|
|
650
|
+
random unless `random_state` is given, at 0.05242 to 0.05319 (0.9 to
|
|
651
|
+
2.4%). When `LinearSVC` draws one of its worse orders the gap passes
|
|
652
|
+
the script's 0.5% bound and the row prints `<-- disagrees`; ours is
|
|
653
|
+
then the better solution of the two, so the flag there is not a fault.
|
|
654
|
+
|
|
615
655
|
The regressors, from the same script (C = 1, epsilon 0.1):
|
|
616
656
|
|
|
617
657
|
| problem | ours | scikit-learn | ratio | agreement |
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/_generated/_loader_accel_cublas.py
RENAMED
|
File without changes
|
{scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/_generated/_loader_classifiers.py
RENAMED
|
File without changes
|
{scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/_generated/_loader_derived_blas.py
RENAMED
|
File without changes
|
{scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/_generated/_loader_derived_cublas.py
RENAMED
|
File without changes
|
{scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/_generated/_loader_derived_loops.py
RENAMED
|
File without changes
|
{scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/_generated/_loader_gpu_cuda.py
RENAMED
|
File without changes
|
{scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/_generated/_loader_gramops_blas.py
RENAMED
|
File without changes
|
{scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/_generated/_loader_gramops_loops.py
RENAMED
|
File without changes
|
{scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/_generated/_loader_nmf_blas.py
RENAMED
|
File without changes
|
{scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/_generated/_loader_nmf_cublas.py
RENAMED
|
File without changes
|
{scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/_generated/_loader_nmf_loops.py
RENAMED
|
File without changes
|
{scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/_generated/accel_cublas/accel.cpp
RENAMED
|
File without changes
|
{scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/_generated/accel_cublas/accel.hpp
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/_generated/classifiers_capi.cpp
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/_generated/gpu_cuda/gpu_capi.cpp
RENAMED
|
File without changes
|
{scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/_generated/gramops_blas/gramops.cpp
RENAMED
|
File without changes
|
{scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/_generated/gramops_blas/gramops.hpp
RENAMED
|
File without changes
|
|
File without changes
|
{scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/_generated/gramops_loops/gramops.cpp
RENAMED
|
File without changes
|
{scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/_generated/gramops_loops/gramops.hpp
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/_generated/lasso_cov_capi.cpp
RENAMED
|
File without changes
|
{scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/_generated/nmf_blas/nmf_cd.cpp
RENAMED
|
File without changes
|
{scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/_generated/nmf_blas/nmf_cd.hpp
RENAMED
|
File without changes
|
{scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/_generated/nmf_blas/nmf_cd_capi.cpp
RENAMED
|
File without changes
|
{scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/_generated/nmf_cublas/nmf_cd.cpp
RENAMED
|
File without changes
|
{scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/_generated/nmf_cublas/nmf_cd.hpp
RENAMED
|
File without changes
|
|
File without changes
|
{scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/_generated/nmf_loops/nmf_cd.cpp
RENAMED
|
File without changes
|
{scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/_generated/nmf_loops/nmf_cd.hpp
RENAMED
|
File without changes
|
{scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/_generated/nmf_loops/nmf_cd_capi.cpp
RENAMED
|
File without changes
|
|
File without changes
|
{scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso/_generated/scm2cpp-cublas.hpp
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{scm2cpp_lasso-0.14.0 → scm2cpp_lasso-0.15.1}/src/scm2cpp_lasso.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|