dkist-processing-math 2.1.2__py3-none-any.whl → 2.2.0rc1__py3-none-any.whl
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.
- changelog/18.misc.rst +1 -0
- changelog/19.misc.rst +1 -0
- changelog/20.feature.rst +2 -0
- dkist_processing_math/statistics.py +62 -0
- dkist_processing_math/tests/conftest.py +16 -4
- dkist_processing_math/tests/test_statistics.py +22 -0
- {dkist_processing_math-2.1.2.dist-info → dkist_processing_math-2.2.0rc1.dist-info}/METADATA +2 -2
- {dkist_processing_math-2.1.2.dist-info → dkist_processing_math-2.2.0rc1.dist-info}/RECORD +10 -7
- {dkist_processing_math-2.1.2.dist-info → dkist_processing_math-2.2.0rc1.dist-info}/WHEEL +1 -1
- {dkist_processing_math-2.1.2.dist-info → dkist_processing_math-2.2.0rc1.dist-info}/top_level.txt +0 -0
changelog/18.misc.rst
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Update bitbucket pipelines to use common scripts for checking for changelog snippets and verifying doc builds.
|
changelog/19.misc.rst
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Update Bitbucket pipelines to use execute script for standard steps.
|
changelog/20.feature.rst
ADDED
|
@@ -38,3 +38,65 @@ def average_numpy_arrays(arrays: Union[Iterable[np.ndarray], np.ndarray]) -> np.
|
|
|
38
38
|
if output is not None:
|
|
39
39
|
return output / (count + 1)
|
|
40
40
|
raise ValueError("data_arrays is empty")
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def stddev_numpy_arrays(arrays: Iterable[np.ndarray]) -> np.ndarray:
|
|
44
|
+
r"""
|
|
45
|
+
Given an iterable of numpy arrays, calculate the pixel-wise standard deviation and return it in a numpy array.
|
|
46
|
+
|
|
47
|
+
This function uses Welford's single-pass algorithm. The standard deviation for the :math:`n^{th}` array is
|
|
48
|
+
|
|
49
|
+
.. math::
|
|
50
|
+
\sigma_n = \sqrt{\frac{M_{2,n}}{n}}
|
|
51
|
+
|
|
52
|
+
where
|
|
53
|
+
|
|
54
|
+
.. math::
|
|
55
|
+
M_{2,n} = M_{2,n-1} + (x_n - \bar{x}_{n-1})(x_n - \bar{x}_n)
|
|
56
|
+
|
|
57
|
+
and
|
|
58
|
+
|
|
59
|
+
.. math::
|
|
60
|
+
\bar{x}_n = \bar{x}_{n-1} + \frac{x_n - \bar{x}_{n-1}}{n}
|
|
61
|
+
|
|
62
|
+
Note that in computing :math:`\sigma` we divide by :math:`n` instead of :math:`(n-1)`. This is to match the default
|
|
63
|
+
behavior of `numpy.std`.
|
|
64
|
+
|
|
65
|
+
Parameters
|
|
66
|
+
----------
|
|
67
|
+
arrays
|
|
68
|
+
The arrays to be to compute the standard deviation of
|
|
69
|
+
|
|
70
|
+
Returns
|
|
71
|
+
-------
|
|
72
|
+
The standard deviation of the input arrays
|
|
73
|
+
"""
|
|
74
|
+
if isinstance(arrays, np.ndarray):
|
|
75
|
+
raise ValueError(
|
|
76
|
+
"Need an Iterator with at least two arrays, but a single array was provided."
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
running_mean = 0.0
|
|
80
|
+
running_M2 = 0.0
|
|
81
|
+
count = 0
|
|
82
|
+
for array in arrays:
|
|
83
|
+
count += 1
|
|
84
|
+
try:
|
|
85
|
+
delta = array - running_mean
|
|
86
|
+
except ValueError:
|
|
87
|
+
raise ValueError(
|
|
88
|
+
f"All arrays must be the same shape. "
|
|
89
|
+
f"Shape of initial array = {running_mean.shape} "
|
|
90
|
+
f"Shape of current array = {array.shape}"
|
|
91
|
+
)
|
|
92
|
+
running_mean += delta / count
|
|
93
|
+
delta2 = array - running_mean
|
|
94
|
+
running_M2 += delta * delta2
|
|
95
|
+
|
|
96
|
+
match count:
|
|
97
|
+
case 0:
|
|
98
|
+
raise ValueError("arrays is empty")
|
|
99
|
+
case 1:
|
|
100
|
+
raise ValueError(f"Need at least two arrays. Provided Iterator only has {count}")
|
|
101
|
+
case _:
|
|
102
|
+
return np.sqrt(running_M2 / count)
|
|
@@ -4,8 +4,13 @@ import pytest
|
|
|
4
4
|
rng = np.random.default_rng()
|
|
5
5
|
|
|
6
6
|
|
|
7
|
+
@pytest.fixture
|
|
8
|
+
def test_array_shape() -> tuple[int, int]:
|
|
9
|
+
return (10, 10)
|
|
10
|
+
|
|
11
|
+
|
|
7
12
|
@pytest.fixture()
|
|
8
|
-
def numpy_arrays():
|
|
13
|
+
def numpy_arrays(test_array_shape):
|
|
9
14
|
"""
|
|
10
15
|
Create an iterable of random 10 x 10 arrays
|
|
11
16
|
|
|
@@ -14,7 +19,11 @@ def numpy_arrays():
|
|
|
14
19
|
List[np.ndarray]
|
|
15
20
|
|
|
16
21
|
"""
|
|
17
|
-
arrays = [
|
|
22
|
+
arrays = [
|
|
23
|
+
rng.standard_normal(test_array_shape),
|
|
24
|
+
rng.standard_normal(test_array_shape),
|
|
25
|
+
rng.standard_normal(test_array_shape),
|
|
26
|
+
]
|
|
18
27
|
return arrays
|
|
19
28
|
|
|
20
29
|
|
|
@@ -32,7 +41,7 @@ def numpy_array(numpy_arrays):
|
|
|
32
41
|
|
|
33
42
|
|
|
34
43
|
@pytest.fixture()
|
|
35
|
-
def numpy_arrays_wrong_shape():
|
|
44
|
+
def numpy_arrays_wrong_shape(test_array_shape):
|
|
36
45
|
"""
|
|
37
46
|
Create an iterable of random arrays of differing sizes
|
|
38
47
|
|
|
@@ -41,7 +50,10 @@ def numpy_arrays_wrong_shape():
|
|
|
41
50
|
List[np.ndarray]
|
|
42
51
|
|
|
43
52
|
"""
|
|
44
|
-
arrays = [
|
|
53
|
+
arrays = [
|
|
54
|
+
rng.standard_normal(test_array_shape),
|
|
55
|
+
rng.standard_normal(tuple(i * 2 for i in test_array_shape)),
|
|
56
|
+
]
|
|
45
57
|
return arrays
|
|
46
58
|
|
|
47
59
|
|
|
@@ -2,6 +2,7 @@ import numpy as np
|
|
|
2
2
|
import pytest
|
|
3
3
|
|
|
4
4
|
from dkist_processing_math.statistics import average_numpy_arrays
|
|
5
|
+
from dkist_processing_math.statistics import stddev_numpy_arrays
|
|
5
6
|
|
|
6
7
|
|
|
7
8
|
@pytest.fixture()
|
|
@@ -60,3 +61,24 @@ def test_average_with_large_values(int_arrays_with_large_values):
|
|
|
60
61
|
"""
|
|
61
62
|
expected = np.ones((10, 10)) * 17500
|
|
62
63
|
np.testing.assert_equal(expected, average_numpy_arrays(int_arrays_with_large_values))
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def test_stddev_numpy_arrays(numpy_arrays):
|
|
67
|
+
expected_result = np.std(numpy_arrays, axis=0)
|
|
68
|
+
result = stddev_numpy_arrays(numpy_arrays)
|
|
69
|
+
|
|
70
|
+
np.testing.assert_allclose(result, expected_result)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def test_stddec_numpy_arrays_failures(numpy_arrays, numpy_arrays_wrong_shape):
|
|
74
|
+
with pytest.raises(ValueError, match="Need an Iterator with at least two arrays"):
|
|
75
|
+
stddev_numpy_arrays(numpy_arrays[0])
|
|
76
|
+
|
|
77
|
+
with pytest.raises(ValueError, match="All arrays must be the same shape"):
|
|
78
|
+
stddev_numpy_arrays(numpy_arrays_wrong_shape)
|
|
79
|
+
|
|
80
|
+
with pytest.raises(ValueError, match="Need at least two arrays"):
|
|
81
|
+
stddev_numpy_arrays([numpy_arrays[0]])
|
|
82
|
+
|
|
83
|
+
with pytest.raises(ValueError, match="arrays is empty"):
|
|
84
|
+
stddev_numpy_arrays([])
|
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
changelog/.gitempty,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
changelog/18.misc.rst,sha256=nhzzLztW_sNOvZ0EeO0jCOpMf1StXdl6IpsJWS6sc4I,111
|
|
3
|
+
changelog/19.misc.rst,sha256=oCFAWH7tQxLKxn6VfQBzAocWj903IvwXlgotpVuRSXY,69
|
|
4
|
+
changelog/20.feature.rst,sha256=5gRsTu_0ql426Z1Wn-x9IXiALTiIZYpczx3_9Y-HYR4,195
|
|
2
5
|
dkist_processing_math/__init__.py,sha256=Mf7liCQC9M5YgFrz2NZ0dZ5smvcuw47ww6MC9mijAHw,249
|
|
3
6
|
dkist_processing_math/arithmetic.py,sha256=h8E4DUBGQLDUiNWmZb2kZRrLMmjEpdl1S_mIi3ntZ6w,3694
|
|
4
7
|
dkist_processing_math/feature.py,sha256=vwrkXBlK7wM6-KFaWxhBsMpHiHbpsWOiuGOhf3PRLSY,2003
|
|
5
8
|
dkist_processing_math/linear_algebra.py,sha256=3ycmWklgLI89NjQgwgY81Zv1m_L4jJXHnt70TzQDVWQ,4179
|
|
6
|
-
dkist_processing_math/statistics.py,sha256=
|
|
9
|
+
dkist_processing_math/statistics.py,sha256=_N6LPRTAFT6lQXv8DJtzK6icIHT3JsM4YWR7JfOSiHA,3058
|
|
7
10
|
dkist_processing_math/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
8
|
-
dkist_processing_math/tests/conftest.py,sha256=
|
|
11
|
+
dkist_processing_math/tests/conftest.py,sha256=TV0o-R2lU1MvZleme0w-akcgO5wOTlFNKhjSlmDwkqg,1593
|
|
9
12
|
dkist_processing_math/tests/test_arithmetic.py,sha256=18YI4Fr_m0KU0dYR8_ef7CMmnOlb-Zc4I8ERgoYdxdA,5658
|
|
10
13
|
dkist_processing_math/tests/test_feature.py,sha256=ZB8r_IUrAyTAlKbxEXwr8Q2zS7KPmlJhaU1l0guK0Xc,2311
|
|
11
14
|
dkist_processing_math/tests/test_linear_algebra.py,sha256=k-XqIIBPsenNMKqo2nQnDkkN-6T1nvVT8BrJnupAIFU,6495
|
|
12
|
-
dkist_processing_math/tests/test_statistics.py,sha256=
|
|
15
|
+
dkist_processing_math/tests/test_statistics.py,sha256=N0S8C9Bwhd1VgCAkm6RqIZF_Ulwrcet9wqfbndw8KZs,2998
|
|
13
16
|
dkist_processing_math/tests/test_transform.py,sha256=M761Yceh3FKV00udvb6_AeKuyBpQrUAG-mLfO-PbHmc,20253
|
|
14
17
|
dkist_processing_math/transform/__init__.py,sha256=gZGyavJgtuquv8vc_VkXraJjz_8MkDTk9UwGQhthHwM,617
|
|
15
18
|
dkist_processing_math/transform/affine.py,sha256=wJvL-R3DMpOmEnCKL8YI8eRUE7enH2Vg-mSLLpfCEoE,8595
|
|
@@ -24,7 +27,7 @@ docs/landing_page.rst,sha256=JCyR9SRhYS6zeEUlonIzko1kQ0tAFDIfi7pCoQanZeA,251
|
|
|
24
27
|
docs/make.bat,sha256=mBAhtURwhQ7yc95pqwJzlhqBSvRknr1aqZ5s8NKvdKs,4513
|
|
25
28
|
docs/requirements.txt,sha256=Kbl_X4c7RQZw035YTeNB63We6I7pvXFU4T0Uflp2yDY,29
|
|
26
29
|
licenses/LICENSE.rst,sha256=piZaQplkzOMmH1NXg6QIdo9wwo9pPCoHkvm2-DmH76E,1462
|
|
27
|
-
dkist_processing_math-2.
|
|
28
|
-
dkist_processing_math-2.
|
|
29
|
-
dkist_processing_math-2.
|
|
30
|
-
dkist_processing_math-2.
|
|
30
|
+
dkist_processing_math-2.2.0rc1.dist-info/METADATA,sha256=20cGjV34kHUjkZI-Nm67oi8Y6VbYUg2_V1ELyN_kl08,4287
|
|
31
|
+
dkist_processing_math-2.2.0rc1.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
|
32
|
+
dkist_processing_math-2.2.0rc1.dist-info/top_level.txt,sha256=7NeFrOlR4xhZ3LMT4jN99LQugukjr6l9u3w_s6b-uO4,46
|
|
33
|
+
dkist_processing_math-2.2.0rc1.dist-info/RECORD,,
|
{dkist_processing_math-2.1.2.dist-info → dkist_processing_math-2.2.0rc1.dist-info}/top_level.txt
RENAMED
|
File without changes
|