bs-python-utils 0.5.3__tar.gz → 0.8.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.
- {bs_python_utils-0.5.3 → bs_python_utils-0.8.0}/PKG-INFO +65 -30
- {bs_python_utils-0.5.3 → bs_python_utils-0.8.0}/README.md +45 -8
- {bs_python_utils-0.5.3 → bs_python_utils-0.8.0}/bs_python_utils/__init__.py +1 -1
- {bs_python_utils-0.5.3 → bs_python_utils-0.8.0}/bs_python_utils/bivariate_quantiles.py +73 -57
- {bs_python_utils-0.5.3 → bs_python_utils-0.8.0}/bs_python_utils/bs_altair.py +248 -92
- {bs_python_utils-0.5.3 → bs_python_utils-0.8.0}/bs_python_utils/bs_logging.py +3 -2
- {bs_python_utils-0.5.3 → bs_python_utils-0.8.0}/bs_python_utils/bs_opt.py +124 -78
- bs_python_utils-0.8.0/bs_python_utils/bs_plots.py +62 -0
- {bs_python_utils-0.5.3 → bs_python_utils-0.8.0}/bs_python_utils/bs_seaborn.py +61 -29
- {bs_python_utils-0.5.3 → bs_python_utils-0.8.0}/bs_python_utils/bs_sparse_gaussian.py +3 -2
- bs_python_utils-0.8.0/bs_python_utils/bsmplutils.py +94 -0
- {bs_python_utils-0.5.3 → bs_python_utils-0.8.0}/bs_python_utils/bsnputils.py +175 -86
- {bs_python_utils-0.5.3 → bs_python_utils-0.8.0}/bs_python_utils/bssputils.py +15 -15
- {bs_python_utils-0.5.3 → bs_python_utils-0.8.0}/bs_python_utils/bsstats.py +47 -30
- {bs_python_utils-0.5.3 → bs_python_utils-0.8.0}/bs_python_utils/bsutils.py +49 -29
- {bs_python_utils-0.5.3 → bs_python_utils-0.8.0}/bs_python_utils/chebyshev.py +66 -53
- bs_python_utils-0.8.0/bs_python_utils/examples/examples_altair.py +225 -0
- {bs_python_utils-0.5.3/bs_python_utils → bs_python_utils-0.8.0/bs_python_utils/examples}/examples_mem.py +2 -1
- bs_python_utils-0.8.0/bs_python_utils/examples/examples_mpl.py +13 -0
- bs_python_utils-0.5.3/bs_python_utils/example_opt.py → bs_python_utils-0.8.0/bs_python_utils/examples/examples_opt.py +3 -2
- {bs_python_utils-0.5.3/bs_python_utils → bs_python_utils-0.8.0/bs_python_utils/examples}/examples_seaborn.py +14 -10
- {bs_python_utils-0.5.3/bs_python_utils → bs_python_utils-0.8.0/bs_python_utils/examples}/examples_sklearn.py +2 -1
- {bs_python_utils-0.5.3 → bs_python_utils-0.8.0}/bs_python_utils/pandas_utils.py +4 -4
- bs_python_utils-0.8.0/bs_python_utils/sklearn_utils.py +123 -0
- bs_python_utils-0.8.0/bs_python_utils/streamlit_utils.py +100 -0
- bs_python_utils-0.8.0/bs_python_utils.egg-info/PKG-INFO +118 -0
- bs_python_utils-0.8.0/bs_python_utils.egg-info/SOURCES.txt +46 -0
- bs_python_utils-0.8.0/bs_python_utils.egg-info/dependency_links.txt +1 -0
- bs_python_utils-0.8.0/bs_python_utils.egg-info/requires.txt +17 -0
- bs_python_utils-0.8.0/bs_python_utils.egg-info/top_level.txt +1 -0
- bs_python_utils-0.8.0/pyproject.toml +31 -0
- bs_python_utils-0.8.0/setup.cfg +4 -0
- bs_python_utils-0.8.0/tests/test_bivariate_quantiles.py +80 -0
- bs_python_utils-0.8.0/tests/test_bs_opt.py +81 -0
- bs_python_utils-0.8.0/tests/test_bs_sparse_gaussian.py +17 -0
- bs_python_utils-0.8.0/tests/test_bsnputils.py +338 -0
- bs_python_utils-0.8.0/tests/test_bssputils.py +29 -0
- bs_python_utils-0.8.0/tests/test_bsstats.py +56 -0
- bs_python_utils-0.8.0/tests/test_bsutils.py +169 -0
- bs_python_utils-0.8.0/tests/test_chebyshev.py +256 -0
- bs_python_utils-0.8.0/tests/test_nptri.py +51 -0
- bs_python_utils-0.8.0/tests/test_random_draws.py +32 -0
- bs_python_utils-0.8.0/tests/test_sklearn_utils.py +52 -0
- bs_python_utils-0.5.3/LICENSE +0 -21
- bs_python_utils-0.5.3/bs_python_utils/bs_plots.py +0 -3
- bs_python_utils-0.5.3/bs_python_utils/bsmplutils.py +0 -36
- bs_python_utils-0.5.3/bs_python_utils/examples_altair.py +0 -182
- bs_python_utils-0.5.3/bs_python_utils/sklearn_utils.py +0 -76
- bs_python_utils-0.5.3/pyproject.toml +0 -103
- {bs_python_utils-0.5.3 → bs_python_utils-0.8.0}/bs_python_utils/Timer.py +0 -0
- {bs_python_utils-0.5.3 → bs_python_utils-0.8.0}/bs_python_utils/bs_mathstr.py +0 -0
- {bs_python_utils-0.5.3 → bs_python_utils-0.8.0}/bs_python_utils/bs_mem.py +0 -0
- {bs_python_utils-0.5.3 → bs_python_utils-0.8.0}/bs_python_utils/distance_covariances.py +0 -0
- {bs_python_utils-0.5.3/bs_python_utils → bs_python_utils-0.8.0/bs_python_utils/examples}/examples_distance_covariances.py +0 -0
|
@@ -1,28 +1,26 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: bs-python-utils
|
|
3
|
-
Version: 0.
|
|
4
|
-
Summary:
|
|
5
|
-
|
|
6
|
-
Author: Bernard Salanie
|
|
7
|
-
Author-email: bsalanie@columbia.edu
|
|
8
|
-
Requires-Python: >=3.8,<4.0
|
|
9
|
-
Classifier: Programming Language :: Python :: 3
|
|
10
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
11
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
12
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
13
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
-
Requires-Dist: altair (>=4.2.2,<5.0.0)
|
|
15
|
-
Requires-Dist: altair-saver (>=0.5.0,<0.6.0)
|
|
16
|
-
Requires-Dist: emcee (>=3.1.4,<4.0.0)
|
|
17
|
-
Requires-Dist: griffe (>=0.32.3,<0.33.0)
|
|
18
|
-
Requires-Dist: matplotlib (>=3.7.1,<4.0.0)
|
|
19
|
-
Requires-Dist: scikit-learn (>=1.2.2,<2.0.0)
|
|
20
|
-
Requires-Dist: seaborn (>=0.12.2,<0.13.0)
|
|
21
|
-
Requires-Dist: statsmodels (>=0.13.5,<0.14.0)
|
|
22
|
-
Requires-Dist: vega-datasets (>=0.9.0,<0.10.0)
|
|
23
|
-
Project-URL: Documentation, https://bsalanie.github.io/bs-python-utils/
|
|
24
|
-
Project-URL: Repository, https://github.com/bsalanie/bs-python-utils
|
|
3
|
+
Version: 0.8.0
|
|
4
|
+
Summary: Add your description here
|
|
5
|
+
Requires-Python: >=3.12
|
|
25
6
|
Description-Content-Type: text/markdown
|
|
7
|
+
Requires-Dist: altair>=5.5.0
|
|
8
|
+
Requires-Dist: altair-saver>=0.5.0
|
|
9
|
+
Requires-Dist: emcee>=3.1.6
|
|
10
|
+
Requires-Dist: matplotlib>=3.10.6
|
|
11
|
+
Requires-Dist: mkdocs>=1.6.1
|
|
12
|
+
Requires-Dist: mkdocs-material>=9.6.20
|
|
13
|
+
Requires-Dist: mkdocstrings-python>=1.18.2
|
|
14
|
+
Requires-Dist: numpy>=2.3.3
|
|
15
|
+
Requires-Dist: pandas>=2.3.2
|
|
16
|
+
Requires-Dist: pre-commit>=4.3.0
|
|
17
|
+
Requires-Dist: pytest>=8.4.2
|
|
18
|
+
Requires-Dist: scikit-learn>=1.7.2
|
|
19
|
+
Requires-Dist: scipy>=1.16.2
|
|
20
|
+
Requires-Dist: seaborn>=0.13.2
|
|
21
|
+
Requires-Dist: statsmodels>=0.14.5
|
|
22
|
+
Requires-Dist: streamlit>=1.49.1
|
|
23
|
+
Requires-Dist: vega-datasets>=0.9.0
|
|
26
24
|
|
|
27
25
|
# bs-python-utils
|
|
28
26
|
|
|
@@ -32,35 +30,72 @@ Description-Content-Type: text/markdown
|
|
|
32
30
|
|
|
33
31
|
[](https://github.com/bsalanie/bs-python-utils/actions/workflows/main.yml?query=branch%3Amain) <!-- [](https://codecov.io/gh/bsalanie/bs-python-utils) --> <!-- [](https://img.shields.io/github/commit-activity/m/bsalanie/bs-python-utils) --> [](https://img.shields.io/github/license/bsalanie/bs-python-utils)
|
|
34
32
|
|
|
35
|
-
My Python utilities
|
|
33
|
+
**My Python utilities**.
|
|
36
34
|
|
|
37
|
-
-
|
|
38
|
-
-
|
|
35
|
+
- **Github repository**: <https://github.com/bsalanie/bs-python-utils/>
|
|
36
|
+
- **Documentation** <https://bsalanie.github.io/bs-python-utils/>
|
|
39
37
|
|
|
40
38
|
### Release notes
|
|
41
|
-
|
|
42
|
-
|
|
39
|
+
|
|
40
|
+
#### 0.8 (October 14, 2025)
|
|
41
|
+
Switched to `uv` for project management. Used Codex to clean up the code and generate more tests. Added the `examples` subdirectory.
|
|
42
|
+
|
|
43
|
+
#### 0.7 (June 18, 2024)
|
|
44
|
+
Added `make_lowertri` in `bsnputils`, and some utility code in `bs_plots`.
|
|
45
|
+
|
|
46
|
+
#### 0.6.4 (November 26, 2023)
|
|
47
|
+
Moved to Altair 5.0; made timing optional in `bs_opt`.
|
|
48
|
+
|
|
49
|
+
#### 0.6.3 (November 26, 2023)
|
|
50
|
+
Updated statsmodels dependency.
|
|
51
|
+
|
|
52
|
+
#### 0.6.1 and 0.6.2 (November 18, 2023)
|
|
53
|
+
Added a Matplotlib plot for discrete choice models, a boxplot for Altair, and a density plot for Seaborn.
|
|
54
|
+
|
|
55
|
+
#### 0.6 (November 9, 2023)
|
|
56
|
+
|
|
57
|
+
Added matrix heatmap plot in Altair and Streamlit utility code.
|
|
58
|
+
|
|
59
|
+
#### 0.5.5 (October 23, 2023)
|
|
60
|
+
|
|
61
|
+
Added `fstring***` in `bsutils`.
|
|
62
|
+
|
|
43
63
|
#### 0.5.2 (August 16, 2023)
|
|
64
|
+
|
|
44
65
|
Added two interpolation routines from values at the Chebyshev nodes in `chebyshev` module.
|
|
66
|
+
|
|
45
67
|
#### 0.5.1 (August 14, 2023)
|
|
46
|
-
|
|
68
|
+
|
|
69
|
+
Added two functions to draw random samples in `bsstats` module.
|
|
70
|
+
|
|
47
71
|
#### 0.5 (August 7, 2023)
|
|
72
|
+
|
|
48
73
|
Added 1-dimensional root finding in `chebyshev` module.
|
|
74
|
+
|
|
49
75
|
#### 0.4.2 (August 2, 2023)
|
|
76
|
+
|
|
50
77
|
Updated the docs.
|
|
78
|
+
|
|
51
79
|
#### 0.4.1 (July 23, 2023)
|
|
80
|
+
|
|
52
81
|
Only print if verbose in bivariate quantiles.
|
|
82
|
+
|
|
53
83
|
#### 0.4 (July 22, 2023)
|
|
84
|
+
|
|
54
85
|
Added bivariate quantiles and ranks à la optimal transportation.
|
|
86
|
+
|
|
55
87
|
#### 0.3 (July 21, 2023)
|
|
88
|
+
|
|
56
89
|
Added in Numpy utils a function to set upper and lower triangle to a scalar;
|
|
57
90
|
and `minimize_free` in `bs_opt`.
|
|
58
91
|
|
|
59
92
|
#### 0.2 (July 17, 2023)
|
|
93
|
+
|
|
60
94
|
Fixed printing in accelerated gradient descent.
|
|
61
95
|
|
|
62
96
|
#### 0.1 (June 20, 2023)
|
|
63
|
-
|
|
97
|
+
|
|
98
|
+
Added `grid_function` and the `chebyshev` module.
|
|
64
99
|
|
|
65
100
|
#### 0.0.6 (May 9, 2023)
|
|
66
101
|
|
|
@@ -6,35 +6,72 @@
|
|
|
6
6
|
|
|
7
7
|
[](https://github.com/bsalanie/bs-python-utils/actions/workflows/main.yml?query=branch%3Amain) <!-- [](https://codecov.io/gh/bsalanie/bs-python-utils) --> <!-- [](https://img.shields.io/github/commit-activity/m/bsalanie/bs-python-utils) --> [](https://img.shields.io/github/license/bsalanie/bs-python-utils)
|
|
8
8
|
|
|
9
|
-
My Python utilities
|
|
9
|
+
**My Python utilities**.
|
|
10
10
|
|
|
11
|
-
-
|
|
12
|
-
-
|
|
11
|
+
- **Github repository**: <https://github.com/bsalanie/bs-python-utils/>
|
|
12
|
+
- **Documentation** <https://bsalanie.github.io/bs-python-utils/>
|
|
13
13
|
|
|
14
14
|
### Release notes
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
|
|
16
|
+
#### 0.8 (October 14, 2025)
|
|
17
|
+
Switched to `uv` for project management. Used Codex to clean up the code and generate more tests. Added the `examples` subdirectory.
|
|
18
|
+
|
|
19
|
+
#### 0.7 (June 18, 2024)
|
|
20
|
+
Added `make_lowertri` in `bsnputils`, and some utility code in `bs_plots`.
|
|
21
|
+
|
|
22
|
+
#### 0.6.4 (November 26, 2023)
|
|
23
|
+
Moved to Altair 5.0; made timing optional in `bs_opt`.
|
|
24
|
+
|
|
25
|
+
#### 0.6.3 (November 26, 2023)
|
|
26
|
+
Updated statsmodels dependency.
|
|
27
|
+
|
|
28
|
+
#### 0.6.1 and 0.6.2 (November 18, 2023)
|
|
29
|
+
Added a Matplotlib plot for discrete choice models, a boxplot for Altair, and a density plot for Seaborn.
|
|
30
|
+
|
|
31
|
+
#### 0.6 (November 9, 2023)
|
|
32
|
+
|
|
33
|
+
Added matrix heatmap plot in Altair and Streamlit utility code.
|
|
34
|
+
|
|
35
|
+
#### 0.5.5 (October 23, 2023)
|
|
36
|
+
|
|
37
|
+
Added `fstring***` in `bsutils`.
|
|
38
|
+
|
|
17
39
|
#### 0.5.2 (August 16, 2023)
|
|
40
|
+
|
|
18
41
|
Added two interpolation routines from values at the Chebyshev nodes in `chebyshev` module.
|
|
42
|
+
|
|
19
43
|
#### 0.5.1 (August 14, 2023)
|
|
20
|
-
|
|
44
|
+
|
|
45
|
+
Added two functions to draw random samples in `bsstats` module.
|
|
46
|
+
|
|
21
47
|
#### 0.5 (August 7, 2023)
|
|
48
|
+
|
|
22
49
|
Added 1-dimensional root finding in `chebyshev` module.
|
|
50
|
+
|
|
23
51
|
#### 0.4.2 (August 2, 2023)
|
|
52
|
+
|
|
24
53
|
Updated the docs.
|
|
54
|
+
|
|
25
55
|
#### 0.4.1 (July 23, 2023)
|
|
56
|
+
|
|
26
57
|
Only print if verbose in bivariate quantiles.
|
|
58
|
+
|
|
27
59
|
#### 0.4 (July 22, 2023)
|
|
60
|
+
|
|
28
61
|
Added bivariate quantiles and ranks à la optimal transportation.
|
|
62
|
+
|
|
29
63
|
#### 0.3 (July 21, 2023)
|
|
64
|
+
|
|
30
65
|
Added in Numpy utils a function to set upper and lower triangle to a scalar;
|
|
31
66
|
and `minimize_free` in `bs_opt`.
|
|
32
67
|
|
|
33
68
|
#### 0.2 (July 17, 2023)
|
|
69
|
+
|
|
34
70
|
Fixed printing in accelerated gradient descent.
|
|
35
71
|
|
|
36
72
|
#### 0.1 (June 20, 2023)
|
|
37
|
-
|
|
73
|
+
|
|
74
|
+
Added `grid_function` and the `chebyshev` module.
|
|
38
75
|
|
|
39
76
|
#### 0.0.6 (May 9, 2023)
|
|
40
77
|
|
|
@@ -54,4 +91,4 @@ Satisfied mypy.
|
|
|
54
91
|
|
|
55
92
|
#### 0.0.2 (April 24, 2023)
|
|
56
93
|
|
|
57
|
-
Fixed main PyPI page.
|
|
94
|
+
Fixed main PyPI page.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""This package contains a number of functions that I have found useful in my programming.
|
|
1
|
+
"""This package contains a number of functions that I have found useful in my programming.
|
|
2
2
|
|
|
3
3
|
* `bsutils` has (inter alia) some I/O functions, error reporting, and $C^2$ extensions of log and exp
|
|
4
4
|
* `bs_logging` has customized logging
|
|
@@ -17,6 +17,7 @@ Steps 1 and 2 can be combined: `qtiles_y = bivariate_quantiles(y, v, u1, u2, n_n
|
|
|
17
17
|
|
|
18
18
|
Steps 1 and 3 can be combined: `ranks_y = bivariate_ranks(y, n_nodes)`
|
|
19
19
|
"""
|
|
20
|
+
|
|
20
21
|
from typing import cast
|
|
21
22
|
|
|
22
23
|
import numpy as np
|
|
@@ -28,62 +29,55 @@ from bs_python_utils.chebyshev import Interval, cheb_get_nodes_1d
|
|
|
28
29
|
|
|
29
30
|
|
|
30
31
|
def _compute_ab(y_sorted: np.ndarray, v_sorted: np.ndarray) -> TwoArrays:
|
|
31
|
-
"""
|
|
32
|
-
|
|
33
|
-
Args:
|
|
34
|
-
y_sorted: the observations, an `(n,2)` matrix sorted by increasing `y[:, 1]`
|
|
35
|
-
v_sorted: the weights, an `n`-vector in the same sort order
|
|
36
|
-
|
|
37
|
-
Returns:
|
|
38
|
-
two `(n, n)` matrices
|
|
39
|
-
|
|
40
|
-
Warning:
|
|
41
|
-
the user must make sure that `y` and `v` have been sorted beforehand
|
|
42
|
-
"""
|
|
43
|
-
n = v_sorted.size
|
|
32
|
+
"""Build the `A` and `B` matrices used in the dual optimisation."""
|
|
44
33
|
y1 = y_sorted[:, 0]
|
|
45
34
|
dy1 = np.subtract.outer(y1, y1)
|
|
46
35
|
y2 = y_sorted[:, 1]
|
|
47
36
|
dy2 = np.subtract.outer(y2, y2)
|
|
48
|
-
np.fill_diagonal(dy2,
|
|
37
|
+
np.fill_diagonal(dy2, 1.0)
|
|
49
38
|
dv = np.subtract.outer(v_sorted, v_sorted)
|
|
50
|
-
|
|
51
|
-
|
|
39
|
+
with np.errstate(divide="ignore", invalid="ignore"):
|
|
40
|
+
a_mat = np.divide(dy1.T, dy2, where=np.abs(dy2) > 1e-12)
|
|
41
|
+
b_mat = np.divide(dv.T, dy2, where=np.abs(dy2) > 1e-12)
|
|
42
|
+
a_mat = np.nan_to_num(a_mat, nan=0.0, posinf=0.0, neginf=0.0)
|
|
43
|
+
b_mat = np.nan_to_num(b_mat, nan=0.0, posinf=0.0, neginf=0.0)
|
|
52
44
|
return a_mat, b_mat
|
|
53
45
|
|
|
54
46
|
|
|
55
47
|
def _compute_u2_bounds(
|
|
56
48
|
k: int, u1: np.ndarray, a_mat: np.ndarray, b_mat: np.ndarray
|
|
57
49
|
) -> TwoArrays:
|
|
58
|
-
"""
|
|
59
|
-
|
|
60
|
-
Args:
|
|
61
|
-
k: an integer between 0 and (n-1)
|
|
62
|
-
u1: a vector of size `m`
|
|
63
|
-
a_mat: the `A` matrix of size `(n,n)`
|
|
64
|
-
b_mat: the `B` matrix of size `(n,n)`
|
|
65
|
-
|
|
66
|
-
Returns:
|
|
67
|
-
two vectors of size `m`, the left and right bounds in [0,1]
|
|
68
|
-
"""
|
|
50
|
+
"""Return the admissible interval of ``u2`` that selects index ``k``."""
|
|
69
51
|
n = a_mat.shape[0]
|
|
70
52
|
m = u1.size
|
|
71
53
|
if k == 0:
|
|
72
54
|
left_bound = np.zeros(m)
|
|
73
55
|
a_right = a_mat[0, 1:]
|
|
74
56
|
b_right = b_mat[0, 1:]
|
|
75
|
-
|
|
57
|
+
if a_right.size:
|
|
58
|
+
right_bound = np.min(np.outer(u1, a_right) - b_right, 1)
|
|
59
|
+
else:
|
|
60
|
+
right_bound = np.ones(m)
|
|
76
61
|
elif 1 <= k < n - 1:
|
|
77
62
|
a_left = a_mat[k, :k]
|
|
78
63
|
b_left = b_mat[k, :k]
|
|
79
|
-
|
|
64
|
+
if a_left.size:
|
|
65
|
+
left_bound = np.max(np.outer(u1, a_left) - b_left, 1)
|
|
66
|
+
else:
|
|
67
|
+
left_bound = np.zeros(m)
|
|
80
68
|
a_right = a_mat[k, (k + 1) :]
|
|
81
69
|
b_right = b_mat[k, (k + 1) :]
|
|
82
|
-
|
|
70
|
+
if a_right.size:
|
|
71
|
+
right_bound = np.min(np.outer(u1, a_right) - b_right, 1)
|
|
72
|
+
else:
|
|
73
|
+
right_bound = np.ones(m)
|
|
83
74
|
elif k == n - 1:
|
|
84
75
|
a_left = a_mat[-1, :-1]
|
|
85
76
|
b_left = b_mat[-1, :-1]
|
|
86
|
-
|
|
77
|
+
if a_left.size:
|
|
78
|
+
left_bound = np.max(np.outer(u1, a_left) - b_left, 1)
|
|
79
|
+
else:
|
|
80
|
+
left_bound = np.zeros(m)
|
|
87
81
|
right_bound = np.ones(m)
|
|
88
82
|
else:
|
|
89
83
|
bs_error_abort(f"{k=} is not compatible with {n=}")
|
|
@@ -94,34 +88,44 @@ def _compute_u2_bounds(
|
|
|
94
88
|
|
|
95
89
|
|
|
96
90
|
def bivariate_quantiles_v(y: np.ndarray, u: np.ndarray, v: np.ndarray) -> np.ndarray:
|
|
97
|
-
"""
|
|
91
|
+
"""Evaluate vector quantiles for a given set of dual weights.
|
|
98
92
|
|
|
99
93
|
Args:
|
|
100
|
-
y:
|
|
101
|
-
u:
|
|
102
|
-
v:
|
|
94
|
+
y: Observations with shape ``(n, 2)``.
|
|
95
|
+
u: Evaluation points in ``[0, 1]^2`` (shape ``(m, 2)``).
|
|
96
|
+
v: Dual weights solving the optimal transport problem (length ``n``).
|
|
103
97
|
|
|
104
98
|
Returns:
|
|
105
|
-
|
|
99
|
+
Array of quantile locations with shape ``(m, 2)``.
|
|
106
100
|
"""
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
101
|
+
u = np.atleast_2d(u)
|
|
102
|
+
if u.shape[1] != 2:
|
|
103
|
+
bs_error_abort("u must have two columns")
|
|
104
|
+
m = u.shape[0]
|
|
105
|
+
q = np.empty((m, 2))
|
|
106
|
+
block = max(1, min(m, 5_000))
|
|
107
|
+
for start in range(0, m, block):
|
|
108
|
+
stop = min(start + block, m)
|
|
109
|
+
chunk = u[start:stop]
|
|
110
|
+
net_val = chunk @ y.T - v
|
|
111
|
+
k_max = np.argmax(net_val, axis=1)
|
|
112
|
+
q[start:stop] = y[k_max]
|
|
113
|
+
return cast(np.ndarray, q)
|
|
110
114
|
|
|
111
115
|
|
|
112
116
|
def bivariate_ranks_v(
|
|
113
117
|
y: np.ndarray, v: np.ndarray, n_nodes: int = 32, presorted: bool = False
|
|
114
118
|
) -> np.ndarray:
|
|
115
|
-
"""
|
|
119
|
+
"""Compute the barycentric ranks of each observation given optimal weights.
|
|
116
120
|
|
|
117
121
|
Args:
|
|
118
|
-
y:
|
|
119
|
-
v:
|
|
120
|
-
n_nodes:
|
|
121
|
-
presorted:
|
|
122
|
+
y: Observations with shape ``(n, 2)``.
|
|
123
|
+
v: Dual weights returned by ``solve_for_v_``.
|
|
124
|
+
n_nodes: Number of Chebyshev nodes used in the quadrature.
|
|
125
|
+
presorted: Set to ``True`` when ``y``/``v`` are pre-sorted by the second coordinate.
|
|
122
126
|
|
|
123
127
|
Returns:
|
|
124
|
-
|
|
128
|
+
Array of average ranks (shape ``(n, 2)``) with ``nan`` for zero-mass cells.
|
|
125
129
|
"""
|
|
126
130
|
n, d = y.shape
|
|
127
131
|
|
|
@@ -151,6 +155,9 @@ def bivariate_ranks_v(
|
|
|
151
155
|
right_bounds * right_bounds - left_bounds * left_bounds, 0.0
|
|
152
156
|
)
|
|
153
157
|
prob_k = pos_diffs @ u1_weights
|
|
158
|
+
if prob_k <= 1e-12:
|
|
159
|
+
average_ranks[sort_order[k], :] = np.array([np.nan, np.nan])
|
|
160
|
+
continue
|
|
154
161
|
average_ranks[sort_order[k], 0] = ((u1_nodes * pos_diffs) @ u1_weights) / prob_k
|
|
155
162
|
average_ranks[sort_order[k], 1] = ((pos_diffs_sq @ u1_weights) / 2.0) / prob_k
|
|
156
163
|
|
|
@@ -213,6 +220,16 @@ def _grad(v_sorted: np.ndarray, args: list):
|
|
|
213
220
|
|
|
214
221
|
|
|
215
222
|
def solve_for_v_(y: np.ndarray, n_nodes: int = 32, verbose: bool = False) -> np.ndarray:
|
|
223
|
+
"""Solve the dual optimisation to obtain the optimal weights ``v``.
|
|
224
|
+
|
|
225
|
+
Args:
|
|
226
|
+
y: Observations with shape ``(n, 2)``.
|
|
227
|
+
n_nodes: Number of Chebyshev nodes for the quadrature.
|
|
228
|
+
verbose: Print optimisation diagnostics when ``True``.
|
|
229
|
+
|
|
230
|
+
Returns:
|
|
231
|
+
Array of length ``n`` containing the optimal weights (including the residual term).
|
|
232
|
+
"""
|
|
216
233
|
n, d = y.shape
|
|
217
234
|
|
|
218
235
|
if d != 2:
|
|
@@ -250,17 +267,16 @@ def solve_for_v_(y: np.ndarray, n_nodes: int = 32, verbose: bool = False) -> np.
|
|
|
250
267
|
def bivariate_quantiles(
|
|
251
268
|
y: np.ndarray, u: np.ndarray, n_nodes: int = 32, verbose: bool = False
|
|
252
269
|
) -> np.ndarray:
|
|
253
|
-
"""
|
|
270
|
+
"""Solve for the dual weights then evaluate bivariate quantiles.
|
|
254
271
|
|
|
255
272
|
Args:
|
|
256
|
-
y:
|
|
257
|
-
u:
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
verbose: if `True`, print some information
|
|
273
|
+
y: Observations, shape ``(n, 2)``.
|
|
274
|
+
u: Query points in ``[0, 1]^2`` (shape ``(m, 2)``).
|
|
275
|
+
n_nodes: Number of Chebyshev nodes for the quadrature.
|
|
276
|
+
verbose: Print optimisation diagnostics when ``True``.
|
|
261
277
|
|
|
262
278
|
Returns:
|
|
263
|
-
|
|
279
|
+
Bivariate quantiles at ``u``.
|
|
264
280
|
"""
|
|
265
281
|
v = solve_for_v_(y, n_nodes, verbose)
|
|
266
282
|
return bivariate_quantiles_v(y, u, v)
|
|
@@ -269,15 +285,15 @@ def bivariate_quantiles(
|
|
|
269
285
|
def bivariate_ranks(
|
|
270
286
|
y: np.ndarray, n_nodes: int = 32, verbose: bool = False
|
|
271
287
|
) -> np.ndarray:
|
|
272
|
-
"""
|
|
288
|
+
"""Compute ranks by first solving for the optimal weights ``v``.
|
|
273
289
|
|
|
274
290
|
Args:
|
|
275
|
-
y:
|
|
276
|
-
n_nodes:
|
|
277
|
-
verbose:
|
|
291
|
+
y: Observations, shape ``(n, 2)``.
|
|
292
|
+
n_nodes: Number of Chebyshev nodes for the quadrature.
|
|
293
|
+
verbose: Print optimisation diagnostics when ``True``.
|
|
278
294
|
|
|
279
295
|
Returns:
|
|
280
|
-
|
|
296
|
+
Average ranks with shape ``(n, 2)``.
|
|
281
297
|
"""
|
|
282
298
|
v = solve_for_v_(y, n_nodes, verbose)
|
|
283
299
|
return bivariate_ranks_v(y, v, n_nodes)
|