scm2cpp-learn 0.18.0__tar.gz → 0.19.0__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_learn-0.18.0/src/scm2cpp_learn.egg-info → scm2cpp_learn-0.19.0}/PKG-INFO +45 -2
- scm2cpp_learn-0.18.0/PKG-INFO → scm2cpp_learn-0.19.0/README.md +43 -18
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.19.0}/pyproject.toml +2 -2
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.19.0}/src/scm2cpp_learn/__init__.py +257 -11
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.19.0}/src/scm2cpp_learn/_generated/_loader_gramops_blas.py +84 -4
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.19.0}/src/scm2cpp_learn/_generated/_loader_gramops_loops.py +84 -4
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.19.0}/src/scm2cpp_learn/_generated/derived_blas/lasso_design.hpp +12 -12
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.19.0}/src/scm2cpp_learn/_generated/derived_cublas/lasso_design.hpp +13 -13
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.19.0}/src/scm2cpp_learn/_generated/derived_loops/lasso_design.hpp +24 -24
- {scm2cpp_learn-0.18.0/src/scm2cpp_learn/_generated/gramops_loops → scm2cpp_learn-0.19.0/src/scm2cpp_learn/_generated/gramops_blas}/gramops.cpp +9 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.19.0}/src/scm2cpp_learn/_generated/gramops_blas/gramops.hpp +841 -29
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.19.0}/src/scm2cpp_learn/_generated/gramops_blas/gramops_capi.cpp +29 -2
- {scm2cpp_learn-0.18.0/src/scm2cpp_learn/_generated/gramops_blas → scm2cpp_learn-0.19.0/src/scm2cpp_learn/_generated/gramops_loops}/gramops.cpp +9 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.19.0}/src/scm2cpp_learn/_generated/gramops_loops/gramops.hpp +1108 -224
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.19.0}/src/scm2cpp_learn/_generated/gramops_loops/gramops_capi.cpp +29 -2
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.19.0}/src/scm2cpp_learn/_generated/nmf_blas/nmf_cd.hpp +13 -13
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.19.0}/src/scm2cpp_learn/_generated/nmf_cublas/nmf_cd.hpp +17 -17
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.19.0}/src/scm2cpp_learn/_generated/nmf_loops/nmf_cd.hpp +29 -29
- scm2cpp_learn-0.18.0/README.md → scm2cpp_learn-0.19.0/src/scm2cpp_learn.egg-info/PKG-INFO +61 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.19.0}/setup.cfg +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.19.0}/setup.py +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.19.0}/src/scm2cpp_learn/_compat.py +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.19.0}/src/scm2cpp_learn/_generated/__init__.py +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.19.0}/src/scm2cpp_learn/_generated/_loader.py +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.19.0}/src/scm2cpp_learn/_generated/_loader_accel_cublas.py +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.19.0}/src/scm2cpp_learn/_generated/_loader_classifiers.py +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.19.0}/src/scm2cpp_learn/_generated/_loader_derived_blas.py +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.19.0}/src/scm2cpp_learn/_generated/_loader_derived_cublas.py +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.19.0}/src/scm2cpp_learn/_generated/_loader_derived_loops.py +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.19.0}/src/scm2cpp_learn/_generated/_loader_gpu_cuda.py +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.19.0}/src/scm2cpp_learn/_generated/_loader_nmf_blas.py +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.19.0}/src/scm2cpp_learn/_generated/_loader_nmf_cublas.py +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.19.0}/src/scm2cpp_learn/_generated/_loader_nmf_loops.py +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.19.0}/src/scm2cpp_learn/_generated/accel_cublas/accel.cpp +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.19.0}/src/scm2cpp_learn/_generated/accel_cublas/accel.hpp +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.19.0}/src/scm2cpp_learn/_generated/accel_cublas/accel_capi.cpp +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.19.0}/src/scm2cpp_learn/_generated/classifiers.cpp +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.19.0}/src/scm2cpp_learn/_generated/classifiers.hpp +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.19.0}/src/scm2cpp_learn/_generated/classifiers_capi.cpp +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.19.0}/src/scm2cpp_learn/_generated/derived_blas/lasso_design.cpp +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.19.0}/src/scm2cpp_learn/_generated/derived_blas/lasso_design_capi.cpp +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.19.0}/src/scm2cpp_learn/_generated/derived_cublas/lasso_design.cpp +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.19.0}/src/scm2cpp_learn/_generated/derived_cublas/lasso_design_capi.cpp +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.19.0}/src/scm2cpp_learn/_generated/derived_loops/lasso_design.cpp +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.19.0}/src/scm2cpp_learn/_generated/derived_loops/lasso_design_capi.cpp +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.19.0}/src/scm2cpp_learn/_generated/gpu_cuda/gpu.cpp +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.19.0}/src/scm2cpp_learn/_generated/gpu_cuda/gpu.hpp +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.19.0}/src/scm2cpp_learn/_generated/gpu_cuda/gpu_capi.cpp +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.19.0}/src/scm2cpp_learn/_generated/lasso_cov.cpp +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.19.0}/src/scm2cpp_learn/_generated/lasso_cov.hpp +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.19.0}/src/scm2cpp_learn/_generated/lasso_cov_capi.cpp +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.19.0}/src/scm2cpp_learn/_generated/nmf_blas/nmf_cd.cpp +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.19.0}/src/scm2cpp_learn/_generated/nmf_blas/nmf_cd_capi.cpp +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.19.0}/src/scm2cpp_learn/_generated/nmf_cublas/nmf_cd.cpp +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.19.0}/src/scm2cpp_learn/_generated/nmf_cublas/nmf_cd_capi.cpp +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.19.0}/src/scm2cpp_learn/_generated/nmf_loops/nmf_cd.cpp +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.19.0}/src/scm2cpp_learn/_generated/nmf_loops/nmf_cd_capi.cpp +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.19.0}/src/scm2cpp_learn/_generated/scm2cpp-blas.hpp +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.19.0}/src/scm2cpp_learn/_generated/scm2cpp-cublas.hpp +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.19.0}/src/scm2cpp_learn/_generated/scm2cpp-cuda.hpp +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.19.0}/src/scm2cpp_learn/_generated/scm2cpp.hpp +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.19.0}/src/scm2cpp_learn/_libfind.py +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.19.0}/src/scm2cpp_learn/batch_capi.cu +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.19.0}/src/scm2cpp_learn.egg-info/SOURCES.txt +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.19.0}/src/scm2cpp_learn.egg-info/dependency_links.txt +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.19.0}/src/scm2cpp_learn.egg-info/requires.txt +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.19.0}/src/scm2cpp_learn.egg-info/top_level.txt +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: scm2cpp-learn
|
|
3
|
-
Version: 0.
|
|
4
|
-
Summary: scikit-learn estimators (lasso, elastic net, ridge, RidgeCV, ARD, SVM, SVR, logistic regression, GLMs, Huber, Theil-Sen, F-score selection, RFE, NMF, Gaussian mixture, FastICA, PCA, KernelPCA, LDA, TruncatedSVD, graphical lasso, RANSAC, SGD, OMP, LARS) translated from Scheme to C++ by scm2cpp; GPU batch solver and CUDA kernels included
|
|
3
|
+
Version: 0.19.0
|
|
4
|
+
Summary: scikit-learn estimators (lasso, elastic net, ridge, RidgeCV, ARD, SVM, SVR, logistic regression, GLMs, Huber, Theil-Sen, F-score selection, RFE, NMF, Gaussian mixture, FastICA, PCA, KernelPCA, LDA, TruncatedSVD, PLS, CCA, 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
|
|
7
7
|
Project-URL: Homepage, https://github.com/niitsuma/scm2cpp
|
|
@@ -257,6 +257,7 @@ package picks the fastest one present.
|
|
|
257
257
|
| `GramKernelPCA` | KernelPCA (no inverse_transform) | `kernel-pca.scm` | loops / BLAS | no |
|
|
258
258
|
| `GramLDA` | LinearDiscriminantAnalysis (svd, lsqr, eigen) | `lda.scm` | loops / BLAS | no |
|
|
259
259
|
| `GramTruncatedSVD` | TruncatedSVD on dense X (exact, as arpack) | `truncated-svd.scm` | loops / BLAS | no |
|
|
260
|
+
| `GramPLSRegression`, `GramPLSCanonical`, `GramCCA`, `GramPLSSVD` | PLSRegression, PLSCanonical, CCA, PLSSVD | `pls.scm` | loops / BLAS | no |
|
|
260
261
|
| `f_regression, f_classif` | f_regression, f_classif | `fscore.scm` | loops / BLAS / cuBLAS | no |
|
|
261
262
|
| `SelectKBest, SelectPercentile` | SelectKBest, SelectPercentile | `fscore.scm` | loops / BLAS / cuBLAS | no |
|
|
262
263
|
| `GramRFE` | RFE(Ridge), RFE(LinearRegression) | `rfe.scm` | loops / BLAS / cuBLAS | inside: Ridge |
|
|
@@ -714,6 +715,48 @@ The exact route costs O(n p^2 + p^3); with few components of many
|
|
|
714
715
|
features (2,000 here) the randomized one does less work, and on one core
|
|
715
716
|
it is faster, at its accuracy. Sparse X is not taken yet.
|
|
716
717
|
|
|
718
|
+
## PLS and CCA: `GramPLSRegression`, `GramPLSCanonical`, `GramCCA`, `GramPLSSVD`
|
|
719
|
+
|
|
720
|
+
scikit-learn's `cross_decomposition` estimators over the cross products
|
|
721
|
+
(`examples/kernel-only/pls.scm`). NIPALS multiplies the blocks only by
|
|
722
|
+
weight vectors, and each such product is one of Cxx = X'X, Cxy = X'Y,
|
|
723
|
+
Cyy = Y'Y times a vector: the Y score is Y c for a coefficient vector c,
|
|
724
|
+
so X'(Y c) = Cxy c. The deflations are rank-one updates of the three
|
|
725
|
+
matrices (with a = Cxx w, b = Cxy'w and s2 = w'Cxx w, regression mode is
|
|
726
|
+
Cxx -= a a'/s2, Cxy -= a b'/s2, Cyy -= b b'/s2). So X and Y are read
|
|
727
|
+
once, for the three products (dsyrk and dgemm), and every power
|
|
728
|
+
iteration after that costs O(p^2 + pq + q^2) where scikit-learn's costs
|
|
729
|
+
O(n(p + q)). CCA's mode B takes pinv(X) y = Cxx^+ X'y, Cxx^+ from its
|
|
730
|
+
eigenproblem; PLSSVD is the SVD of Cxy.
|
|
731
|
+
|
|
732
|
+
```python
|
|
733
|
+
from scm2cpp_learn import GramPLSRegression, GramCCA
|
|
734
|
+
pls = GramPLSRegression(n_components=5).fit(X, Y)
|
|
735
|
+
pls.predict(X), pls.transform(X), pls.x_scores_
|
|
736
|
+
```
|
|
737
|
+
|
|
738
|
+
Weights, loadings, rotations, coefficients, scores and transforms agree
|
|
739
|
+
with scikit-learn's to 1e-13, with the same iteration counts. One cut
|
|
740
|
+
differs: a deflated block loses a rank exactly, which its SVD shows as a
|
|
741
|
+
singular value near eps but its Gram as an eigenvalue near eps
|
|
742
|
+
lam_max, so mode B's pinv also drops eigenvalues under 1e3 eps lam_max
|
|
743
|
+
(singular values under about 5e-7 of the largest, where scikit-learn's
|
|
744
|
+
cut is 2.2e-10). Measured (`bench/eigen-compare.py`, the MKL build, best
|
|
745
|
+
of three):
|
|
746
|
+
|
|
747
|
+
| case | scikit-learn | package | ratio, one core | ratio, 20 cores |
|
|
748
|
+
|---|---|---|---|---|
|
|
749
|
+
| PLSRegression, 200,000 x 100 -> 5, 5 components | 5.64 s | 0.26 s | 21x | 19x |
|
|
750
|
+
| PLSCanonical, 200,000 x 100 -> 5, 5 components | 5.63 s | 0.14 s | 40x | 59x |
|
|
751
|
+
| CCA, 200,000 x 100 -> 5, 5 components | 31.9 s | 0.14 s | 220x | 190x |
|
|
752
|
+
| PLSSVD, 200,000 x 100 -> 5, 5 components | 0.28 s | 0.14 s | 2.0x | 4.0x |
|
|
753
|
+
| PLSRegression, 50,000 x 500 -> 10, 10 components | 45.5 s | 0.75 s | 61x | 57x |
|
|
754
|
+
| PLSCanonical, 50,000 x 500 -> 10, 10 components | 45.3 s | 0.60 s | 76x | 100x |
|
|
755
|
+
| CCA, 50,000 x 500 -> 10, 10 components | 132 s | 1.21 s | 109x | 151x |
|
|
756
|
+
| PLSSVD, 50,000 x 500 -> 10, 10 components | 0.34 s | 0.34 s | 1.0x | 3.4x |
|
|
757
|
+
|
|
758
|
+
PLSSVD is one SVD of X'Y on both sides, so only the product differs.
|
|
759
|
+
|
|
717
760
|
## Bayesian ridge
|
|
718
761
|
|
|
719
762
|
`CovBayesianRidge` is scikit-learn's `BayesianRidge` -- the same model,
|
|
@@ -1,21 +1,3 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: scm2cpp-learn
|
|
3
|
-
Version: 0.18.0
|
|
4
|
-
Summary: scikit-learn estimators (lasso, elastic net, ridge, RidgeCV, ARD, SVM, SVR, logistic regression, GLMs, Huber, Theil-Sen, F-score selection, RFE, NMF, Gaussian mixture, FastICA, PCA, KernelPCA, LDA, TruncatedSVD, graphical lasso, RANSAC, SGD, OMP, LARS) translated from Scheme to C++ by scm2cpp; GPU batch solver and CUDA kernels included
|
|
5
|
-
Author: Hirotaka Niitsuma
|
|
6
|
-
License: MIT
|
|
7
|
-
Project-URL: Homepage, https://github.com/niitsuma/scm2cpp
|
|
8
|
-
Project-URL: Source, https://github.com/niitsuma/scm2cpp/tree/master/python/scm2cpp-learn
|
|
9
|
-
Keywords: scikit-learn,lasso,elastic-net,ridge,svm,logistic-regression,pca,lda,coordinate-descent,lapack,cuda,compiler
|
|
10
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
-
Classifier: Programming Language :: Python :: 3
|
|
12
|
-
Classifier: Programming Language :: C++
|
|
13
|
-
Classifier: Topic :: Scientific/Engineering :: Mathematics
|
|
14
|
-
Classifier: Intended Audience :: Science/Research
|
|
15
|
-
Requires-Python: >=3.8
|
|
16
|
-
Description-Content-Type: text/markdown
|
|
17
|
-
Requires-Dist: numpy>=1.17
|
|
18
|
-
|
|
19
1
|
# scm2cpp-learn
|
|
20
2
|
|
|
21
3
|
[](https://colab.research.google.com/github/niitsuma/scm2cpp/blob/master/notebooks/compare-sklearn.ipynb)
|
|
@@ -257,6 +239,7 @@ package picks the fastest one present.
|
|
|
257
239
|
| `GramKernelPCA` | KernelPCA (no inverse_transform) | `kernel-pca.scm` | loops / BLAS | no |
|
|
258
240
|
| `GramLDA` | LinearDiscriminantAnalysis (svd, lsqr, eigen) | `lda.scm` | loops / BLAS | no |
|
|
259
241
|
| `GramTruncatedSVD` | TruncatedSVD on dense X (exact, as arpack) | `truncated-svd.scm` | loops / BLAS | no |
|
|
242
|
+
| `GramPLSRegression`, `GramPLSCanonical`, `GramCCA`, `GramPLSSVD` | PLSRegression, PLSCanonical, CCA, PLSSVD | `pls.scm` | loops / BLAS | no |
|
|
260
243
|
| `f_regression, f_classif` | f_regression, f_classif | `fscore.scm` | loops / BLAS / cuBLAS | no |
|
|
261
244
|
| `SelectKBest, SelectPercentile` | SelectKBest, SelectPercentile | `fscore.scm` | loops / BLAS / cuBLAS | no |
|
|
262
245
|
| `GramRFE` | RFE(Ridge), RFE(LinearRegression) | `rfe.scm` | loops / BLAS / cuBLAS | inside: Ridge |
|
|
@@ -714,6 +697,48 @@ The exact route costs O(n p^2 + p^3); with few components of many
|
|
|
714
697
|
features (2,000 here) the randomized one does less work, and on one core
|
|
715
698
|
it is faster, at its accuracy. Sparse X is not taken yet.
|
|
716
699
|
|
|
700
|
+
## PLS and CCA: `GramPLSRegression`, `GramPLSCanonical`, `GramCCA`, `GramPLSSVD`
|
|
701
|
+
|
|
702
|
+
scikit-learn's `cross_decomposition` estimators over the cross products
|
|
703
|
+
(`examples/kernel-only/pls.scm`). NIPALS multiplies the blocks only by
|
|
704
|
+
weight vectors, and each such product is one of Cxx = X'X, Cxy = X'Y,
|
|
705
|
+
Cyy = Y'Y times a vector: the Y score is Y c for a coefficient vector c,
|
|
706
|
+
so X'(Y c) = Cxy c. The deflations are rank-one updates of the three
|
|
707
|
+
matrices (with a = Cxx w, b = Cxy'w and s2 = w'Cxx w, regression mode is
|
|
708
|
+
Cxx -= a a'/s2, Cxy -= a b'/s2, Cyy -= b b'/s2). So X and Y are read
|
|
709
|
+
once, for the three products (dsyrk and dgemm), and every power
|
|
710
|
+
iteration after that costs O(p^2 + pq + q^2) where scikit-learn's costs
|
|
711
|
+
O(n(p + q)). CCA's mode B takes pinv(X) y = Cxx^+ X'y, Cxx^+ from its
|
|
712
|
+
eigenproblem; PLSSVD is the SVD of Cxy.
|
|
713
|
+
|
|
714
|
+
```python
|
|
715
|
+
from scm2cpp_learn import GramPLSRegression, GramCCA
|
|
716
|
+
pls = GramPLSRegression(n_components=5).fit(X, Y)
|
|
717
|
+
pls.predict(X), pls.transform(X), pls.x_scores_
|
|
718
|
+
```
|
|
719
|
+
|
|
720
|
+
Weights, loadings, rotations, coefficients, scores and transforms agree
|
|
721
|
+
with scikit-learn's to 1e-13, with the same iteration counts. One cut
|
|
722
|
+
differs: a deflated block loses a rank exactly, which its SVD shows as a
|
|
723
|
+
singular value near eps but its Gram as an eigenvalue near eps
|
|
724
|
+
lam_max, so mode B's pinv also drops eigenvalues under 1e3 eps lam_max
|
|
725
|
+
(singular values under about 5e-7 of the largest, where scikit-learn's
|
|
726
|
+
cut is 2.2e-10). Measured (`bench/eigen-compare.py`, the MKL build, best
|
|
727
|
+
of three):
|
|
728
|
+
|
|
729
|
+
| case | scikit-learn | package | ratio, one core | ratio, 20 cores |
|
|
730
|
+
|---|---|---|---|---|
|
|
731
|
+
| PLSRegression, 200,000 x 100 -> 5, 5 components | 5.64 s | 0.26 s | 21x | 19x |
|
|
732
|
+
| PLSCanonical, 200,000 x 100 -> 5, 5 components | 5.63 s | 0.14 s | 40x | 59x |
|
|
733
|
+
| CCA, 200,000 x 100 -> 5, 5 components | 31.9 s | 0.14 s | 220x | 190x |
|
|
734
|
+
| PLSSVD, 200,000 x 100 -> 5, 5 components | 0.28 s | 0.14 s | 2.0x | 4.0x |
|
|
735
|
+
| PLSRegression, 50,000 x 500 -> 10, 10 components | 45.5 s | 0.75 s | 61x | 57x |
|
|
736
|
+
| PLSCanonical, 50,000 x 500 -> 10, 10 components | 45.3 s | 0.60 s | 76x | 100x |
|
|
737
|
+
| CCA, 50,000 x 500 -> 10, 10 components | 132 s | 1.21 s | 109x | 151x |
|
|
738
|
+
| PLSSVD, 50,000 x 500 -> 10, 10 components | 0.34 s | 0.34 s | 1.0x | 3.4x |
|
|
739
|
+
|
|
740
|
+
PLSSVD is one SVD of X'Y on both sides, so only the product differs.
|
|
741
|
+
|
|
717
742
|
## Bayesian ridge
|
|
718
743
|
|
|
719
744
|
`CovBayesianRidge` is scikit-learn's `BayesianRidge` -- the same model,
|
|
@@ -4,8 +4,8 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "scm2cpp-learn"
|
|
7
|
-
version = "0.
|
|
8
|
-
description = "scikit-learn estimators (lasso, elastic net, ridge, RidgeCV, ARD, SVM, SVR, logistic regression, GLMs, Huber, Theil-Sen, F-score selection, RFE, NMF, Gaussian mixture, FastICA, PCA, KernelPCA, LDA, TruncatedSVD, graphical lasso, RANSAC, SGD, OMP, LARS) translated from Scheme to C++ by scm2cpp; GPU batch solver and CUDA kernels included"
|
|
7
|
+
version = "0.19.0"
|
|
8
|
+
description = "scikit-learn estimators (lasso, elastic net, ridge, RidgeCV, ARD, SVM, SVR, logistic regression, GLMs, Huber, Theil-Sen, F-score selection, RFE, NMF, Gaussian mixture, FastICA, PCA, KernelPCA, LDA, TruncatedSVD, PLS, CCA, 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"
|
|
11
11
|
license = {text = "MIT"}
|
|
@@ -50,14 +50,14 @@ __all__ = ["GramLasso", "GramElasticNet", "GramRidge", "GramRidgeCV", "CovLasso"
|
|
|
50
50
|
"LBFGSLogisticRegression", "LBFGSHuberRegressor", "LBFGSLogisticRegressionCV",
|
|
51
51
|
"LBFGSPoissonRegressor", "LBFGSGammaRegressor", "LBFGSTweedieRegressor",
|
|
52
52
|
"GramLarsCV", "GramLassoLarsCV", "GramOMPCV",
|
|
53
|
-
"EMGaussianMixture", "CovPCA", "GramKernelPCA", "GramLDA", "GramTruncatedSVD", "ParallelFastICA", "CovARDRegression",
|
|
53
|
+
"EMGaussianMixture", "CovPCA", "GramKernelPCA", "GramLDA", "GramTruncatedSVD", "GramPLSRegression", "GramPLSCanonical", "GramCCA", "GramPLSSVD", "ParallelFastICA", "CovARDRegression",
|
|
54
54
|
"L1LinearSVM", "WeiszfeldTheilSen", "f_regression", "f_classif", "SelectKBest",
|
|
55
55
|
"SelectPercentile", "GramRFE",
|
|
56
56
|
"CovMultiTaskLasso", "CovMultiTaskLassoCV", "DerivedLasso",
|
|
57
57
|
"GramLogisticRegression", "GramGroupLasso", "GramMultiTaskLasso",
|
|
58
58
|
"GramMultiTaskElasticNet", "DesignLasso",
|
|
59
59
|
"cuda_available", "derived_backend", "kernel"]
|
|
60
|
-
__version__ = "0.
|
|
60
|
+
__version__ = "0.19.0"
|
|
61
61
|
|
|
62
62
|
_BATCH = load_batch_lib()
|
|
63
63
|
_DP = ctypes.POINTER(ctypes.c_double)
|
|
@@ -837,7 +837,10 @@ class GramRidgeCV(Tagged, RegressorMixin, BaseEstimator):
|
|
|
837
837
|
and diag H and yhat at every alpha are two products. Z comes from
|
|
838
838
|
the eigenvectors of Xc'Xc (``gcv_mode="svd"``, the default when
|
|
839
839
|
n > p, X'X by dsyrk) or of Xc Xc' (``"eigen"``, the default
|
|
840
|
-
otherwise
|
|
840
|
+
otherwise; as scikit-learn's, it takes e = c / diag G^-1 for
|
|
841
|
+
c = G^-1 y, G = Xc Xc' + 11' + alpha I with the intercept's
|
|
842
|
+
eigenvalue unpenalised, so that a small alpha, where H tends to I,
|
|
843
|
+
loses no digits to 1 - diag H); the eigenproblem is LAPACK's dsyevd where the BLAS
|
|
841
844
|
build is here. Only ``cv=None`` and ``scoring=None`` are taken.
|
|
842
845
|
|
|
843
846
|
Attributes after fit: alpha_, best_score_ (minus the mean squared
|
|
@@ -890,14 +893,19 @@ class GramRidgeCV(Tagged, RegressorMixin, BaseEstimator):
|
|
|
890
893
|
else:
|
|
891
894
|
Xc = np.ascontiguousarray(X - xm)
|
|
892
895
|
K = _gram(np.ascontiguousarray(Xc.T))
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
+
if self.fit_intercept:
|
|
897
|
+
K += 1.0
|
|
898
|
+
V, lam, R = np.zeros((n, n)), np.zeros(n), np.zeros((n, t))
|
|
899
|
+
drop = k.ridge_gcv_dual(K, V, lam, yc, R, n, t, int(bool(self.fit_intercept)))
|
|
896
900
|
na = alphas.size
|
|
897
901
|
mse = np.zeros((na, t))
|
|
898
902
|
loo = np.zeros((n, t, na)) if self.store_cv_results else np.zeros(1)
|
|
899
|
-
|
|
900
|
-
|
|
903
|
+
store = int(bool(self.store_cv_results))
|
|
904
|
+
if mode == "svd":
|
|
905
|
+
k.ridge_gcv_scan(Z, lam, R, yc, alphas, 1.0 / n if self.fit_intercept else 0.0,
|
|
906
|
+
mse, loo, store, n, m, t, na)
|
|
907
|
+
else:
|
|
908
|
+
k.ridge_gcv_scan_dual(V, lam, R, alphas, drop, mse, loo, store, n, t, na)
|
|
901
909
|
if self.alpha_per_target and t > 1:
|
|
902
910
|
best = np.argmin(mse, axis=0)
|
|
903
911
|
al = alphas[best]
|
|
@@ -911,9 +919,12 @@ class GramRidgeCV(Tagged, RegressorMixin, BaseEstimator):
|
|
|
911
919
|
if mode == "svd":
|
|
912
920
|
coef = V @ (R / (lam[:, None] + al[None, :]))
|
|
913
921
|
else:
|
|
914
|
-
# (Xc Xc' + alpha I)^-1 yc by the eigenvectors, then Xc' of
|
|
915
|
-
|
|
916
|
-
|
|
922
|
+
# (Xc Xc' + alpha I)^-1 yc by the eigenvectors, then Xc' of
|
|
923
|
+
# it; yc has no part along 1, so the 11' added changes nothing
|
|
924
|
+
w = 1.0 / (lam[:, None] + al[None, :])
|
|
925
|
+
if drop >= 0:
|
|
926
|
+
w[drop] = 0.0
|
|
927
|
+
coef = Xc.T @ (V @ (R * w))
|
|
917
928
|
if y.ndim == 1:
|
|
918
929
|
self.coef_ = coef[:, 0]
|
|
919
930
|
self.intercept_ = float(ym[0] - xm @ coef[:, 0])
|
|
@@ -2259,6 +2270,17 @@ class GramKernelPCA(Tagged, TransformerMixin, BaseEstimator):
|
|
|
2259
2270
|
return K @ scaled
|
|
2260
2271
|
|
|
2261
2272
|
|
|
2273
|
+
def _lda_svd_dof(n, K):
|
|
2274
|
+
# the divisor of LinearDiscriminantAnalysis's svd solver: n from
|
|
2275
|
+
# scikit-learn 1.9.1, n - K before; n without scikit-learn
|
|
2276
|
+
try:
|
|
2277
|
+
import sklearn
|
|
2278
|
+
v = tuple(int(x) for x in sklearn.__version__.split(".")[:3] if x.isdigit())
|
|
2279
|
+
except Exception:
|
|
2280
|
+
return n
|
|
2281
|
+
return n - K if v < (1, 9, 1) else n
|
|
2282
|
+
|
|
2283
|
+
|
|
2262
2284
|
class GramLDA(Tagged, ClassifierMixin, TransformerMixin, BaseEstimator):
|
|
2263
2285
|
"""scikit-learn's ``LinearDiscriminantAnalysis`` over the Gram matrix
|
|
2264
2286
|
(``examples/kernel-only/lda.scm``): X'X by dsyrk and the class means
|
|
@@ -2353,6 +2375,10 @@ class GramLDA(Tagged, ClassifierMixin, TransformerMixin, BaseEstimator):
|
|
|
2353
2375
|
self.xbar_ = priors @ means
|
|
2354
2376
|
std, V, S = np.zeros(p), np.zeros((p, p)), np.zeros(p)
|
|
2355
2377
|
k.lda_svd_first(np.ascontiguousarray(Sw_emp), std, V, S, p)
|
|
2378
|
+
# S is the SVD of Xc D^-1 / sqrt(n); scikit-learn before 1.9.1
|
|
2379
|
+
# divides by sqrt(n - K) instead (#33626), and its tol and
|
|
2380
|
+
# scalings_ see that scale
|
|
2381
|
+
S *= np.sqrt(n / _lda_svd_dof(n, K))
|
|
2356
2382
|
rank = int(np.sum(S > self.tol))
|
|
2357
2383
|
scal = (V[:, :rank] / std[:, None]) / S[:rank]
|
|
2358
2384
|
fac = 1.0 if K == 1 else 1.0 / (K - 1)
|
|
@@ -2481,6 +2507,226 @@ class GramTruncatedSVD(Tagged, TransformerMixin, BaseEstimator):
|
|
|
2481
2507
|
return np.asarray(X) @ self.components_
|
|
2482
2508
|
|
|
2483
2509
|
|
|
2510
|
+
def _pls_moments(X, Y, scale):
|
|
2511
|
+
"""Centred (and, with scale, standardised) Cxx, Cxy, Cyy, with the
|
|
2512
|
+
means and deviations: from X'X, X'Y and Y'Y less the n m m' terms,
|
|
2513
|
+
the centred copies only when a column's mean dwarfs its spread (the
|
|
2514
|
+
correction would cancel its digits)."""
|
|
2515
|
+
n = X.shape[0]
|
|
2516
|
+
xm, ym = X.mean(axis=0), Y.mean(axis=0)
|
|
2517
|
+
Gxx, Gxy, Gyy = _gram(X), _gram_xy(X, Y), _gram(np.ascontiguousarray(Y))
|
|
2518
|
+
Gxy = Gxy.reshape(X.shape[1], Y.shape[1])
|
|
2519
|
+
nx, ny = n * xm * xm, n * ym * ym
|
|
2520
|
+
if np.all(np.diagonal(Gxx) - nx > 1e-4 * nx) and np.all(np.diagonal(Gyy) - ny > 1e-4 * ny):
|
|
2521
|
+
Cxx = Gxx - np.outer(xm, n * xm)
|
|
2522
|
+
Cxy = Gxy - np.outer(xm, n * ym)
|
|
2523
|
+
Cyy = Gyy - np.outer(ym, n * ym)
|
|
2524
|
+
else:
|
|
2525
|
+
Xc, Yc = np.ascontiguousarray(X - xm), np.ascontiguousarray(Y - ym)
|
|
2526
|
+
Cxx, Cyy = _gram(Xc), _gram(Yc)
|
|
2527
|
+
Cxy = _gram_xy(Xc, Yc).reshape(X.shape[1], Y.shape[1])
|
|
2528
|
+
if scale:
|
|
2529
|
+
xs = np.sqrt(np.maximum(np.diagonal(Cxx), 0.0) / (n - 1))
|
|
2530
|
+
ys = np.sqrt(np.maximum(np.diagonal(Cyy), 0.0) / (n - 1))
|
|
2531
|
+
xs[xs == 0.0] = 1.0
|
|
2532
|
+
ys[ys == 0.0] = 1.0
|
|
2533
|
+
Cxx = Cxx / np.outer(xs, xs)
|
|
2534
|
+
Cxy = Cxy / np.outer(xs, ys)
|
|
2535
|
+
Cyy = Cyy / np.outer(ys, ys)
|
|
2536
|
+
else:
|
|
2537
|
+
xs, ys = np.ones(X.shape[1]), np.ones(Y.shape[1])
|
|
2538
|
+
return (np.ascontiguousarray(Cxx), np.ascontiguousarray(Cxy), np.ascontiguousarray(Cyy),
|
|
2539
|
+
xm, ym, xs, ys)
|
|
2540
|
+
|
|
2541
|
+
|
|
2542
|
+
class _GramPLS(Tagged, TransformerMixin, BaseEstimator):
|
|
2543
|
+
# scikit-learn's _PLS over the cross products (examples/kernel-only/pls.scm)
|
|
2544
|
+
_multi_output = True
|
|
2545
|
+
_mode, _canon = 0, 0
|
|
2546
|
+
|
|
2547
|
+
def fit(self, X, y):
|
|
2548
|
+
X, y = fit_xy(self, X, y, multi_output=True)
|
|
2549
|
+
n, p = X.shape
|
|
2550
|
+
if n < 2:
|
|
2551
|
+
raise ValueError(f"Found array with {n} sample(s) (shape={X.shape}) while a "
|
|
2552
|
+
"minimum of 2 is required.")
|
|
2553
|
+
self._predict_1d = y.ndim == 1
|
|
2554
|
+
Y = y.reshape(n, -1)
|
|
2555
|
+
q = Y.shape[1]
|
|
2556
|
+
k = int(self.n_components)
|
|
2557
|
+
upper = min(n, p) if not self._canon else min(n, p, q)
|
|
2558
|
+
if not 1 <= k <= upper:
|
|
2559
|
+
raise ValueError(f"`n_components` upper bound is {upper}. Got {k} instead. "
|
|
2560
|
+
"Reduce `n_components`.")
|
|
2561
|
+
algo = 1 if getattr(self, "algorithm", "nipals") == "svd" else 0
|
|
2562
|
+
Cxx, Cxy, Cyy, self._x_mean, self._y_mean, self._x_std, self._y_std = \
|
|
2563
|
+
_pls_moments(X, Y, self.scale)
|
|
2564
|
+
xw, yw = np.zeros((p, k)), np.zeros((q, k))
|
|
2565
|
+
xl, yl = np.zeros((p, k)), np.zeros((q, k))
|
|
2566
|
+
niter = np.zeros(k, dtype=np.int32)
|
|
2567
|
+
found = _gramops_kernels().pls_fit(Cxx, Cxy, Cyy, xw, yw, xl, yl, niter, p, q, k,
|
|
2568
|
+
self._mode, self._canon, algo,
|
|
2569
|
+
int(self.max_iter), float(self.tol))
|
|
2570
|
+
if found < k:
|
|
2571
|
+
warnings.warn(f"y residual is constant at iteration {found}")
|
|
2572
|
+
# scikit-learn keeps the list empty for the svd algorithm
|
|
2573
|
+
self.n_iter_ = [int(t) for t in niter[:found]] if algo == 0 else []
|
|
2574
|
+
if algo == 0:
|
|
2575
|
+
if any(t == int(self.max_iter) for t in self.n_iter_):
|
|
2576
|
+
warnings.warn("Maximum number of iterations reached", UserWarning)
|
|
2577
|
+
self.x_weights_, self.y_weights_ = xw, yw
|
|
2578
|
+
self.x_loadings_, self.y_loadings_ = xl, yl
|
|
2579
|
+
self.x_rotations_ = xw @ np.linalg.pinv(xl.T @ xw)
|
|
2580
|
+
self.y_rotations_ = yw @ np.linalg.pinv(yl.T @ yw)
|
|
2581
|
+
coef = self.x_rotations_ @ yl.T
|
|
2582
|
+
self.coef_ = (coef * self._y_std).T / self._x_std
|
|
2583
|
+
self.intercept_ = self._y_mean
|
|
2584
|
+
self._n_features_out = k
|
|
2585
|
+
self._X, self._Y = X, Y
|
|
2586
|
+
return self
|
|
2587
|
+
|
|
2588
|
+
def transform(self, X, y=None, copy=True):
|
|
2589
|
+
check_is_fitted(self)
|
|
2590
|
+
Xs = (pred_x(self, X) - self._x_mean) / self._x_std
|
|
2591
|
+
xs = Xs @ self.x_rotations_
|
|
2592
|
+
if y is None:
|
|
2593
|
+
return xs
|
|
2594
|
+
Y = np.asarray(y, dtype=np.float64)
|
|
2595
|
+
Y = Y.reshape(-1, 1) if Y.ndim == 1 else Y
|
|
2596
|
+
return xs, ((Y - self._y_mean) / self._y_std) @ self.y_rotations_
|
|
2597
|
+
|
|
2598
|
+
def fit_transform(self, X, y=None):
|
|
2599
|
+
return self.fit(X, y).transform(X, y)
|
|
2600
|
+
|
|
2601
|
+
def inverse_transform(self, X, y=None):
|
|
2602
|
+
check_is_fitted(self)
|
|
2603
|
+
Xr = np.asarray(X, dtype=np.float64) @ self.x_loadings_.T * self._x_std + self._x_mean
|
|
2604
|
+
if y is None:
|
|
2605
|
+
return Xr
|
|
2606
|
+
Yr = np.asarray(y, dtype=np.float64) @ self.y_loadings_.T * self._y_std + self._y_mean
|
|
2607
|
+
return Xr, Yr
|
|
2608
|
+
|
|
2609
|
+
def predict(self, X, copy=True):
|
|
2610
|
+
check_is_fitted(self)
|
|
2611
|
+
yp = (pred_x(self, X) - self._x_mean) @ self.coef_.T + self.intercept_
|
|
2612
|
+
return yp.ravel() if self._predict_1d else yp
|
|
2613
|
+
|
|
2614
|
+
|
|
2615
|
+
class GramPLSRegression(RegressorMixin, _GramPLS):
|
|
2616
|
+
"""scikit-learn's ``PLSRegression`` over the cross products
|
|
2617
|
+
(``examples/kernel-only/pls.scm``): X'X (dsyrk), X'Y and Y'Y once,
|
|
2618
|
+
then NIPALS and the regression deflation as products and rank-one
|
|
2619
|
+
updates of those p x p, p x q and q x q matrices, never the n rows
|
|
2620
|
+
again. The scores x_scores_ = X R and y_scores_ (Y less the earlier
|
|
2621
|
+
components' X scores, times the Y weights) are formed at the end.
|
|
2622
|
+
|
|
2623
|
+
Attributes after fit: x_weights_, y_weights_, x_loadings_,
|
|
2624
|
+
y_loadings_, x_rotations_, y_rotations_, x_scores_, y_scores_,
|
|
2625
|
+
coef_, intercept_, n_iter_, n_features_in_.
|
|
2626
|
+
"""
|
|
2627
|
+
_mode, _canon = 0, 0
|
|
2628
|
+
|
|
2629
|
+
def __init__(self, n_components=2, *, scale=True, max_iter=500, tol=1e-06, copy=True):
|
|
2630
|
+
self.n_components, self.scale, self.max_iter = n_components, scale, max_iter
|
|
2631
|
+
self.tol, self.copy = tol, copy
|
|
2632
|
+
|
|
2633
|
+
def fit(self, X, y):
|
|
2634
|
+
super().fit(X, y)
|
|
2635
|
+
Xs = (self._X - self._x_mean) / self._x_std
|
|
2636
|
+
Ys = (self._Y - self._y_mean) / self._y_std
|
|
2637
|
+
T = Xs @ self.x_rotations_
|
|
2638
|
+
U = Ys @ self.y_weights_
|
|
2639
|
+
for k in range(U.shape[1]):
|
|
2640
|
+
# Y deflated by the earlier components' X scores (regression mode)
|
|
2641
|
+
U[:, k] -= T[:, :k] @ (self.y_loadings_[:, :k].T @ self.y_weights_[:, k])
|
|
2642
|
+
U[:, k] /= self.y_weights_[:, k] @ self.y_weights_[:, k]
|
|
2643
|
+
self.x_scores_, self.y_scores_ = T, U
|
|
2644
|
+
del self._X, self._Y
|
|
2645
|
+
return self
|
|
2646
|
+
|
|
2647
|
+
def fit_transform(self, X, y=None):
|
|
2648
|
+
return self.fit(X, y).transform(X, y)
|
|
2649
|
+
|
|
2650
|
+
|
|
2651
|
+
class GramPLSCanonical(_GramPLS):
|
|
2652
|
+
"""scikit-learn's ``PLSCanonical`` (canonical deflation, mode A,
|
|
2653
|
+
``algorithm`` "nipals" or "svd") over the cross products, as
|
|
2654
|
+
``GramPLSRegression``."""
|
|
2655
|
+
_mode, _canon = 0, 1
|
|
2656
|
+
|
|
2657
|
+
def __init__(self, n_components=2, *, scale=True, algorithm="nipals", max_iter=500,
|
|
2658
|
+
tol=1e-06, copy=True):
|
|
2659
|
+
self.n_components, self.scale, self.algorithm = n_components, scale, algorithm
|
|
2660
|
+
self.max_iter, self.tol, self.copy = max_iter, tol, copy
|
|
2661
|
+
|
|
2662
|
+
def fit(self, X, y):
|
|
2663
|
+
if self.algorithm not in ("nipals", "svd"):
|
|
2664
|
+
raise ValueError(f"algorithm={self.algorithm!r}: expected 'nipals' or 'svd'")
|
|
2665
|
+
super().fit(X, y)
|
|
2666
|
+
del self._X, self._Y
|
|
2667
|
+
return self
|
|
2668
|
+
|
|
2669
|
+
|
|
2670
|
+
class GramCCA(_GramPLS):
|
|
2671
|
+
"""scikit-learn's ``CCA`` (canonical deflation, mode B: pinv of each
|
|
2672
|
+
block from the eigenproblem of its Gram, cut where _pinv2_old cuts)
|
|
2673
|
+
over the cross products, as ``GramPLSRegression``."""
|
|
2674
|
+
_mode, _canon = 1, 1
|
|
2675
|
+
|
|
2676
|
+
def __init__(self, n_components=2, *, scale=True, max_iter=500, tol=1e-06, copy=True):
|
|
2677
|
+
self.n_components, self.scale, self.max_iter = n_components, scale, max_iter
|
|
2678
|
+
self.tol, self.copy = tol, copy
|
|
2679
|
+
|
|
2680
|
+
def fit(self, X, y):
|
|
2681
|
+
super().fit(X, y)
|
|
2682
|
+
del self._X, self._Y
|
|
2683
|
+
return self
|
|
2684
|
+
|
|
2685
|
+
|
|
2686
|
+
class GramPLSSVD(Tagged, TransformerMixin, BaseEstimator):
|
|
2687
|
+
"""scikit-learn's ``PLSSVD``: the SVD of the centred (scaled) X'Y,
|
|
2688
|
+
formed from X'Y less n mx my' instead of from centred copies."""
|
|
2689
|
+
_multi_output = True
|
|
2690
|
+
|
|
2691
|
+
def __init__(self, n_components=2, *, scale=True, copy=True):
|
|
2692
|
+
self.n_components, self.scale, self.copy = n_components, scale, copy
|
|
2693
|
+
|
|
2694
|
+
def fit(self, X, y):
|
|
2695
|
+
X, y = fit_xy(self, X, y, multi_output=True)
|
|
2696
|
+
n, p = X.shape
|
|
2697
|
+
if n < 2:
|
|
2698
|
+
raise ValueError(f"Found array with {n} sample(s) (shape={X.shape}) while a "
|
|
2699
|
+
"minimum of 2 is required.")
|
|
2700
|
+
Y = y.reshape(n, -1)
|
|
2701
|
+
k = int(self.n_components)
|
|
2702
|
+
upper = min(n, p, Y.shape[1])
|
|
2703
|
+
if not 1 <= k <= upper:
|
|
2704
|
+
raise ValueError(f"`n_components` upper bound is {upper}. Got {k} instead. "
|
|
2705
|
+
"Reduce `n_components`.")
|
|
2706
|
+
_, C, _, self._x_mean, self._y_mean, self._x_std, self._y_std = \
|
|
2707
|
+
_pls_moments(X, Y, self.scale)
|
|
2708
|
+
U, _, Vt = np.linalg.svd(C, full_matrices=False)
|
|
2709
|
+
U, Vt = U[:, :k], Vt[:k]
|
|
2710
|
+
# svd_flip, u-based: each column of U's largest entry positive
|
|
2711
|
+
sg = np.sign(U[np.argmax(np.abs(U), axis=0), np.arange(k)])
|
|
2712
|
+
sg[sg == 0] = 1.0
|
|
2713
|
+
self.x_weights_, self.y_weights_ = U * sg, (Vt * sg[:, None]).T
|
|
2714
|
+
self._n_features_out = k
|
|
2715
|
+
return self
|
|
2716
|
+
|
|
2717
|
+
def transform(self, X, y=None):
|
|
2718
|
+
check_is_fitted(self)
|
|
2719
|
+
xs = ((pred_x(self, X) - self._x_mean) / self._x_std) @ self.x_weights_
|
|
2720
|
+
if y is None:
|
|
2721
|
+
return xs
|
|
2722
|
+
Y = np.asarray(y, dtype=np.float64)
|
|
2723
|
+
Y = Y.reshape(-1, 1) if Y.ndim == 1 else Y
|
|
2724
|
+
return xs, ((Y - self._y_mean) / self._y_std) @ self.y_weights_
|
|
2725
|
+
|
|
2726
|
+
def fit_transform(self, X, y=None):
|
|
2727
|
+
return self.fit(X, y).transform(X, y)
|
|
2728
|
+
|
|
2729
|
+
|
|
2484
2730
|
class ParallelFastICA(Tagged, TransformerMixin, BaseEstimator):
|
|
2485
2731
|
"""FastICA, scikit-learn's ``FastICA`` at its defaults translated
|
|
2486
2732
|
whole (``examples/kernel-only/fastica.scm``: algorithm="parallel",
|
{scm2cpp_learn-0.18.0 → scm2cpp_learn-0.19.0}/src/scm2cpp_learn/_generated/_loader_gramops_blas.py
RENAMED
|
@@ -522,15 +522,25 @@ def ridge_gcv_primal(x, xm, yc, g, v, lam, z, r, n, p, t):
|
|
|
522
522
|
return _lib.scm2cpp_ridge_gcv_primal(x.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), xm.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), yc.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), g.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), v.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), lam.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), z.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), r.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), n, p, t)
|
|
523
523
|
|
|
524
524
|
_lib.scm2cpp_ridge_gcv_dual.restype = ctypes.c_int
|
|
525
|
-
_lib.scm2cpp_ridge_gcv_dual.argtypes = [ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.
|
|
526
|
-
def ridge_gcv_dual(k, q, mu, yc,
|
|
525
|
+
_lib.scm2cpp_ridge_gcv_dual.argtypes = [ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.c_int, ctypes.c_int, ctypes.c_int]
|
|
526
|
+
def ridge_gcv_dual(k, q, mu, yc, r, n, t, icpt):
|
|
527
527
|
k = np.ascontiguousarray(k, dtype=np.float64)
|
|
528
528
|
q = np.ascontiguousarray(q, dtype=np.float64)
|
|
529
529
|
mu = np.ascontiguousarray(mu, dtype=np.float64)
|
|
530
530
|
yc = np.ascontiguousarray(yc, dtype=np.float64)
|
|
531
|
-
z = np.ascontiguousarray(z, dtype=np.float64)
|
|
532
531
|
r = np.ascontiguousarray(r, dtype=np.float64)
|
|
533
|
-
return _lib.scm2cpp_ridge_gcv_dual(k.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), q.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), mu.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), yc.ctypes.data_as(ctypes.POINTER(ctypes.c_double)),
|
|
532
|
+
return _lib.scm2cpp_ridge_gcv_dual(k.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), q.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), mu.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), yc.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), r.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), n, t, icpt)
|
|
533
|
+
|
|
534
|
+
_lib.scm2cpp_ridge_gcv_scan_dual.restype = ctypes.c_int
|
|
535
|
+
_lib.scm2cpp_ridge_gcv_scan_dual.argtypes = [ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.c_int, ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.c_int, ctypes.c_int, ctypes.c_int, ctypes.c_int]
|
|
536
|
+
def ridge_gcv_scan_dual(q, mu, r, alphas, drop, mse, loo, store, n, t, na):
|
|
537
|
+
q = np.ascontiguousarray(q, dtype=np.float64)
|
|
538
|
+
mu = np.ascontiguousarray(mu, dtype=np.float64)
|
|
539
|
+
r = np.ascontiguousarray(r, dtype=np.float64)
|
|
540
|
+
alphas = np.ascontiguousarray(alphas, dtype=np.float64)
|
|
541
|
+
mse = np.ascontiguousarray(mse, dtype=np.float64)
|
|
542
|
+
loo = np.ascontiguousarray(loo, dtype=np.float64)
|
|
543
|
+
return _lib.scm2cpp_ridge_gcv_scan_dual(q.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), mu.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), r.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), alphas.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), drop, mse.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), loo.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), store, n, t, na)
|
|
534
544
|
|
|
535
545
|
_lib.scm2cpp_ridge_gcv_scan.restype = ctypes.c_int
|
|
536
546
|
_lib.scm2cpp_ridge_gcv_scan.argtypes = [ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.c_double, ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.c_int, ctypes.c_int, ctypes.c_int, ctypes.c_int, ctypes.c_int]
|
|
@@ -690,3 +700,73 @@ def tsvd_wide(x, v, s, z, n, p, k):
|
|
|
690
700
|
z = np.ascontiguousarray(z, dtype=np.float64)
|
|
691
701
|
return _lib.scm2cpp_tsvd_wide(x.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), v.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), s.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), z.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), n, p, k)
|
|
692
702
|
|
|
703
|
+
_lib.scm2cpp_svd_jacobi.restype = ctypes.c_int
|
|
704
|
+
_lib.scm2cpp_svd_jacobi.argtypes = [ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.c_int, ctypes.c_int]
|
|
705
|
+
def svd_jacobi(w, q, r, c):
|
|
706
|
+
w = np.ascontiguousarray(w, dtype=np.float64)
|
|
707
|
+
q = np.ascontiguousarray(q, dtype=np.float64)
|
|
708
|
+
return _lib.scm2cpp_svd_jacobi(w.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), q.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), r, c)
|
|
709
|
+
|
|
710
|
+
_lib.scm2cpp_svd_collect.restype = ctypes.c_int
|
|
711
|
+
_lib.scm2cpp_svd_collect.argtypes = [ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_int), ctypes.c_int, ctypes.c_int]
|
|
712
|
+
def svd_collect(w, q, s, l, rr, ord, r, c):
|
|
713
|
+
w = np.ascontiguousarray(w, dtype=np.float64)
|
|
714
|
+
q = np.ascontiguousarray(q, dtype=np.float64)
|
|
715
|
+
s = np.ascontiguousarray(s, dtype=np.float64)
|
|
716
|
+
l = np.ascontiguousarray(l, dtype=np.float64)
|
|
717
|
+
rr = np.ascontiguousarray(rr, dtype=np.float64)
|
|
718
|
+
ord = np.ascontiguousarray(ord, dtype=np.int32)
|
|
719
|
+
return _lib.scm2cpp_svd_collect(w.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), q.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), s.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), l.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), rr.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), ord.ctypes.data_as(ctypes.POINTER(ctypes.c_int)), r, c)
|
|
720
|
+
|
|
721
|
+
_lib.scm2cpp_sym_svd.restype = ctypes.c_int
|
|
722
|
+
_lib.scm2cpp_sym_svd.argtypes = [ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.c_int, ctypes.c_int]
|
|
723
|
+
def sym_svd(a, u, s, vt, m, n):
|
|
724
|
+
a = np.ascontiguousarray(a, dtype=np.float64)
|
|
725
|
+
u = np.ascontiguousarray(u, dtype=np.float64)
|
|
726
|
+
s = np.ascontiguousarray(s, dtype=np.float64)
|
|
727
|
+
vt = np.ascontiguousarray(vt, dtype=np.float64)
|
|
728
|
+
return _lib.scm2cpp_sym_svd(a.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), u.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), s.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), vt.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), m, n)
|
|
729
|
+
|
|
730
|
+
_lib.scm2cpp_pls_pinv.restype = ctypes.c_int
|
|
731
|
+
_lib.scm2cpp_pls_pinv.argtypes = [ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.c_int]
|
|
732
|
+
def pls_pinv(a, pv, m):
|
|
733
|
+
a = np.ascontiguousarray(a, dtype=np.float64)
|
|
734
|
+
pv = np.ascontiguousarray(pv, dtype=np.float64)
|
|
735
|
+
return _lib.scm2cpp_pls_pinv(a.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), pv.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), m)
|
|
736
|
+
|
|
737
|
+
_lib.scm2cpp_pls_mv.restype = ctypes.c_int
|
|
738
|
+
_lib.scm2cpp_pls_mv.argtypes = [ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.c_int, ctypes.c_int]
|
|
739
|
+
def pls_mv(a, x, y, m, n):
|
|
740
|
+
a = np.ascontiguousarray(a, dtype=np.float64)
|
|
741
|
+
x = np.ascontiguousarray(x, dtype=np.float64)
|
|
742
|
+
y = np.ascontiguousarray(y, dtype=np.float64)
|
|
743
|
+
return _lib.scm2cpp_pls_mv(a.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), x.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), y.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), m, n)
|
|
744
|
+
|
|
745
|
+
_lib.scm2cpp_pls_mtv.restype = ctypes.c_int
|
|
746
|
+
_lib.scm2cpp_pls_mtv.argtypes = [ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.c_int, ctypes.c_int]
|
|
747
|
+
def pls_mtv(a, x, y, m, n):
|
|
748
|
+
a = np.ascontiguousarray(a, dtype=np.float64)
|
|
749
|
+
x = np.ascontiguousarray(x, dtype=np.float64)
|
|
750
|
+
y = np.ascontiguousarray(y, dtype=np.float64)
|
|
751
|
+
return _lib.scm2cpp_pls_mtv(a.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), x.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), y.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), m, n)
|
|
752
|
+
|
|
753
|
+
_lib.scm2cpp_pls_dot.restype = ctypes.c_double
|
|
754
|
+
_lib.scm2cpp_pls_dot.argtypes = [ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.c_int]
|
|
755
|
+
def pls_dot(x, y, m):
|
|
756
|
+
x = np.ascontiguousarray(x, dtype=np.float64)
|
|
757
|
+
y = np.ascontiguousarray(y, dtype=np.float64)
|
|
758
|
+
return _lib.scm2cpp_pls_dot(x.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), y.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), m)
|
|
759
|
+
|
|
760
|
+
_lib.scm2cpp_pls_fit.restype = ctypes.c_int
|
|
761
|
+
_lib.scm2cpp_pls_fit.argtypes = [ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_int), ctypes.c_int, ctypes.c_int, ctypes.c_int, ctypes.c_int, ctypes.c_int, ctypes.c_int, ctypes.c_int, ctypes.c_double]
|
|
762
|
+
def pls_fit(cxx, cxy, cyy, xw, yw, xl, yl, niter, p, q, k, mode, canon, algo, maxit, tol):
|
|
763
|
+
cxx = np.ascontiguousarray(cxx, dtype=np.float64)
|
|
764
|
+
cxy = np.ascontiguousarray(cxy, dtype=np.float64)
|
|
765
|
+
cyy = np.ascontiguousarray(cyy, dtype=np.float64)
|
|
766
|
+
xw = np.ascontiguousarray(xw, dtype=np.float64)
|
|
767
|
+
yw = np.ascontiguousarray(yw, dtype=np.float64)
|
|
768
|
+
xl = np.ascontiguousarray(xl, dtype=np.float64)
|
|
769
|
+
yl = np.ascontiguousarray(yl, dtype=np.float64)
|
|
770
|
+
niter = np.ascontiguousarray(niter, dtype=np.int32)
|
|
771
|
+
return _lib.scm2cpp_pls_fit(cxx.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), cxy.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), cyy.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), xw.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), yw.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), xl.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), yl.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), niter.ctypes.data_as(ctypes.POINTER(ctypes.c_int)), p, q, k, mode, canon, algo, maxit, tol)
|
|
772
|
+
|