pelutils 4.3.0__tar.gz → 4.3.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.
- {pelutils-4.3.0 → pelutils-4.3.1}/PKG-INFO +24 -16
- {pelutils-4.3.0 → pelutils-4.3.1}/README.md +23 -15
- {pelutils-4.3.0 → pelutils-4.3.1}/pelutils/__version__.py +1 -1
- {pelutils-4.3.0 → pelutils-4.3.1}/pelutils/array/_blob.py +21 -0
- pelutils-4.3.1/pelutils/serialization/__init__.py +51 -0
- {pelutils-4.3.0 → pelutils-4.3.1}/pelutils/stats/__init__.py +7 -7
- {pelutils-4.3.0 → pelutils-4.3.1}/pelutils/stats/_distributions.py +26 -15
- {pelutils-4.3.0 → pelutils-4.3.1}/pelutils/stats/_stats.py +7 -3
- {pelutils-4.3.0 → pelutils-4.3.1}/pelutils.egg-info/PKG-INFO +24 -16
- pelutils-4.3.0/pelutils/serialization/__init__.py +0 -51
- {pelutils-4.3.0 → pelutils-4.3.1}/MANIFEST.in +0 -0
- {pelutils-4.3.0 → pelutils-4.3.1}/pelutils/__init__.py +0 -0
- {pelutils-4.3.0 → pelutils-4.3.1}/pelutils/_c/__init__.py +0 -0
- {pelutils-4.3.0 → pelutils-4.3.1}/pelutils/_c/array/blob.c +0 -0
- {pelutils-4.3.0 → pelutils-4.3.1}/pelutils/_c/array/blob.h +0 -0
- {pelutils-4.3.0 → pelutils-4.3.1}/pelutils/_c/array/unique.c +0 -0
- {pelutils-4.3.0 → pelutils-4.3.1}/pelutils/_c/array/unique.h +0 -0
- {pelutils-4.3.0 → pelutils-4.3.1}/pelutils/_c/deque/deque.c +0 -0
- {pelutils-4.3.0 → pelutils-4.3.1}/pelutils/_c/deque/deque.h +0 -0
- {pelutils-4.3.0 → pelutils-4.3.1}/pelutils/_c/hashmap/LICENSE +0 -0
- {pelutils-4.3.0 → pelutils-4.3.1}/pelutils/_c/hashmap/hashmap.c +0 -0
- {pelutils-4.3.0 → pelutils-4.3.1}/pelutils/_c/hashmap/hashmap.h +0 -0
- {pelutils-4.3.0 → pelutils-4.3.1}/pelutils/_c/pelutils.c +0 -0
- {pelutils-4.3.0 → pelutils-4.3.1}/pelutils/_c/types.h +0 -0
- {pelutils-4.3.0 → pelutils-4.3.1}/pelutils/_entry_points/__init__.py +0 -0
- {pelutils-4.3.0 → pelutils-4.3.1}/pelutils/_entry_points/linecounter.py +0 -0
- {pelutils-4.3.0 → pelutils-4.3.1}/pelutils/array/__init__.py +0 -0
- {pelutils-4.3.0 → pelutils-4.3.1}/pelutils/array/_unique.py +0 -0
- {pelutils-4.3.0 → pelutils-4.3.1}/pelutils/array/_utils.py +0 -0
- {pelutils-4.3.0 → pelutils-4.3.1}/pelutils/job_parser/__init__.py +0 -0
- {pelutils-4.3.0 → pelutils-4.3.1}/pelutils/job_parser/_job_parser.py +0 -0
- {pelutils-4.3.0 → pelutils-4.3.1}/pelutils/job_parser/_structs.py +0 -0
- {pelutils-4.3.0 → pelutils-4.3.1}/pelutils/legacy/__init__.py +0 -0
- {pelutils-4.3.0 → pelutils-4.3.1}/pelutils/legacy/v3/__init__.py +0 -0
- {pelutils-4.3.0 → pelutils-4.3.1}/pelutils/legacy/v3/_datastorage.py +0 -0
- {pelutils-4.3.0 → pelutils-4.3.1}/pelutils/logging/__init__.py +0 -0
- {pelutils-4.3.0 → pelutils-4.3.1}/pelutils/logging/_logger.py +0 -0
- {pelutils-4.3.0 → pelutils-4.3.1}/pelutils/logging/_rich_string.py +0 -0
- {pelutils-4.3.0 → pelutils-4.3.1}/pelutils/logging/_rotate.py +0 -0
- {pelutils-4.3.0 → pelutils-4.3.1}/pelutils/misc/__init__.py +0 -0
- {pelutils-4.3.0 → pelutils-4.3.1}/pelutils/misc/_conditional_import.py +0 -0
- {pelutils-4.3.0 → pelutils-4.3.1}/pelutils/misc/_files.py +0 -0
- {pelutils-4.3.0 → pelutils-4.3.1}/pelutils/misc/_git.py +0 -0
- {pelutils-4.3.0 → pelutils-4.3.1}/pelutils/misc/_misc.py +0 -0
- {pelutils-4.3.0 → pelutils-4.3.1}/pelutils/misc/_platform.py +0 -0
- {pelutils-4.3.0 → pelutils-4.3.1}/pelutils/misc/_table.py +0 -0
- {pelutils-4.3.0 → pelutils-4.3.1}/pelutils/plots/__init__.py +0 -0
- {pelutils-4.3.0 → pelutils-4.3.1}/pelutils/plots/_figure.py +0 -0
- {pelutils-4.3.0 → pelutils-4.3.1}/pelutils/plots/_histogram.py +0 -0
- {pelutils-4.3.0 → pelutils-4.3.1}/pelutils/plots/_utils.py +0 -0
- {pelutils-4.3.0 → pelutils-4.3.1}/pelutils/py.typed +0 -0
- {pelutils-4.3.0 → pelutils-4.3.1}/pelutils/serialization/_jsonl.py +0 -0
- {pelutils-4.3.0 → pelutils-4.3.1}/pelutils/serialization/_pretty_json.py +0 -0
- {pelutils-4.3.0 → pelutils-4.3.1}/pelutils/serialization/_universal_json_model.py +0 -0
- {pelutils-4.3.0 → pelutils-4.3.1}/pelutils/tests/__init__.py +0 -0
- {pelutils-4.3.0 → pelutils-4.3.1}/pelutils/tests/_tests.py +0 -0
- {pelutils-4.3.0 → pelutils-4.3.1}/pelutils/ticktock/__init__.py +0 -0
- {pelutils-4.3.0 → pelutils-4.3.1}/pelutils/ticktock/_ticktock.py +0 -0
- {pelutils-4.3.0 → pelutils-4.3.1}/pelutils/types/__init__.py +0 -0
- {pelutils-4.3.0 → pelutils-4.3.1}/pelutils/types/_types.py +0 -0
- {pelutils-4.3.0 → pelutils-4.3.1}/pelutils.egg-info/SOURCES.txt +0 -0
- {pelutils-4.3.0 → pelutils-4.3.1}/pelutils.egg-info/dependency_links.txt +0 -0
- {pelutils-4.3.0 → pelutils-4.3.1}/pelutils.egg-info/entry_points.txt +0 -0
- {pelutils-4.3.0 → pelutils-4.3.1}/pelutils.egg-info/requires.txt +0 -0
- {pelutils-4.3.0 → pelutils-4.3.1}/pelutils.egg-info/top_level.txt +0 -0
- {pelutils-4.3.0 → pelutils-4.3.1}/setup.cfg +0 -0
- {pelutils-4.3.0 → pelutils-4.3.1}/setup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: pelutils
|
|
3
|
-
Version: 4.3.
|
|
3
|
+
Version: 4.3.1
|
|
4
4
|
Summary: The Swiss army knife of Python projects
|
|
5
5
|
Home-page: https://github.com/peleiden/pelutils
|
|
6
6
|
Download-URL: https://pypi.org/project/pelutils/
|
|
@@ -164,10 +164,15 @@ importantly one per thread, as profiling is not thread-safe.
|
|
|
164
164
|
|
|
165
165
|
## Serialisation
|
|
166
166
|
|
|
167
|
-
`UniversalJsonModel`
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
167
|
+
`UniversalJsonModel` is for storing Pydantic models that contain a mixture of ordinary JSON
|
|
168
|
+
values and Python-specific values. Ordinary values remain JSON, so the file structure can be
|
|
169
|
+
inspected and diffed. Values that JSON cannot represent, such as NumPy arrays, tensors, and
|
|
170
|
+
other Python objects, are stored as base64-encoded pickle payloads.
|
|
171
|
+
|
|
172
|
+
The `save()` and `load()` methods support convient file-based workflows.
|
|
173
|
+
`save()` serialises the model to a JSON file, while `load()` reconstructs the model from one.
|
|
174
|
+
Use `to_json_dict()` and `from_json_dict(...)` when the serialized representation belongs inside
|
|
175
|
+
another structure or is handled by another storage layer.
|
|
171
176
|
|
|
172
177
|
```py
|
|
173
178
|
import numpy as np
|
|
@@ -193,11 +198,14 @@ result.save("results/run-1.json")
|
|
|
193
198
|
result = Result.load("results/run-1.json")
|
|
194
199
|
```
|
|
195
200
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
+
`pretty_json` is a string-returning formatter for standalone dictionaries and lists. It fills the
|
|
202
|
+
same role as `json.dumps`, with compact nested containers and wrapped primitive lists; write the
|
|
203
|
+
returned string to a file when needed. The module also includes JSONL read/write helpers
|
|
204
|
+
(`jsonl_dump`, `jsonl_load`, ...) for newline-delimited records.
|
|
205
|
+
|
|
206
|
+
This format is intended for trusted configuration objects, application state, experiment results, etc., not as a
|
|
207
|
+
language-neutral interchange format. Pickle payloads are Python-specific and loading them can
|
|
208
|
+
execute arbitrary code. Do not load files from untrusted sources.
|
|
201
209
|
|
|
202
210
|
## Config and command-line argument parsing
|
|
203
211
|
|
|
@@ -254,18 +262,18 @@ values, index, inverse, counts = unique(
|
|
|
254
262
|
|
|
255
263
|
### Statistics
|
|
256
264
|
|
|
257
|
-
Common statistical helpers, plus wrappers around
|
|
258
|
-
as in Jim Pitman's *Probability* (rather than
|
|
265
|
+
Common statistical helpers, plus wrappers around SciPy distributions reparametrised
|
|
266
|
+
as in Jim Pitman's *Probability* (rather than SciPy's `loc`/`scale`, which are
|
|
259
267
|
unintuitive for many distributions).
|
|
260
268
|
|
|
261
269
|
```py
|
|
262
|
-
from pelutils.stats import z_score
|
|
263
270
|
from pelutils.stats import expon
|
|
271
|
+
from pelutils.stats import z_score
|
|
264
272
|
|
|
265
|
-
# 95 % confidence interval half-width for a standard normal
|
|
266
|
-
half_width =
|
|
273
|
+
# 95 % confidence interval half-width for a standard normal
|
|
274
|
+
half_width = z_score() # standard deviation is 1
|
|
267
275
|
|
|
268
|
-
#
|
|
276
|
+
# Upper 1 % critical value for an Exponential(lambda=2)
|
|
269
277
|
zval = z_score(alpha=0.01, two_sided=False, distribution=expon(lambda_=2))
|
|
270
278
|
```
|
|
271
279
|
|
|
@@ -138,10 +138,15 @@ importantly one per thread, as profiling is not thread-safe.
|
|
|
138
138
|
|
|
139
139
|
## Serialisation
|
|
140
140
|
|
|
141
|
-
`UniversalJsonModel`
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
141
|
+
`UniversalJsonModel` is for storing Pydantic models that contain a mixture of ordinary JSON
|
|
142
|
+
values and Python-specific values. Ordinary values remain JSON, so the file structure can be
|
|
143
|
+
inspected and diffed. Values that JSON cannot represent, such as NumPy arrays, tensors, and
|
|
144
|
+
other Python objects, are stored as base64-encoded pickle payloads.
|
|
145
|
+
|
|
146
|
+
The `save()` and `load()` methods support convient file-based workflows.
|
|
147
|
+
`save()` serialises the model to a JSON file, while `load()` reconstructs the model from one.
|
|
148
|
+
Use `to_json_dict()` and `from_json_dict(...)` when the serialized representation belongs inside
|
|
149
|
+
another structure or is handled by another storage layer.
|
|
145
150
|
|
|
146
151
|
```py
|
|
147
152
|
import numpy as np
|
|
@@ -167,11 +172,14 @@ result.save("results/run-1.json")
|
|
|
167
172
|
result = Result.load("results/run-1.json")
|
|
168
173
|
```
|
|
169
174
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
+
`pretty_json` is a string-returning formatter for standalone dictionaries and lists. It fills the
|
|
176
|
+
same role as `json.dumps`, with compact nested containers and wrapped primitive lists; write the
|
|
177
|
+
returned string to a file when needed. The module also includes JSONL read/write helpers
|
|
178
|
+
(`jsonl_dump`, `jsonl_load`, ...) for newline-delimited records.
|
|
179
|
+
|
|
180
|
+
This format is intended for trusted configuration objects, application state, experiment results, etc., not as a
|
|
181
|
+
language-neutral interchange format. Pickle payloads are Python-specific and loading them can
|
|
182
|
+
execute arbitrary code. Do not load files from untrusted sources.
|
|
175
183
|
|
|
176
184
|
## Config and command-line argument parsing
|
|
177
185
|
|
|
@@ -228,18 +236,18 @@ values, index, inverse, counts = unique(
|
|
|
228
236
|
|
|
229
237
|
### Statistics
|
|
230
238
|
|
|
231
|
-
Common statistical helpers, plus wrappers around
|
|
232
|
-
as in Jim Pitman's *Probability* (rather than
|
|
239
|
+
Common statistical helpers, plus wrappers around SciPy distributions reparametrised
|
|
240
|
+
as in Jim Pitman's *Probability* (rather than SciPy's `loc`/`scale`, which are
|
|
233
241
|
unintuitive for many distributions).
|
|
234
242
|
|
|
235
243
|
```py
|
|
236
|
-
from pelutils.stats import z_score
|
|
237
244
|
from pelutils.stats import expon
|
|
245
|
+
from pelutils.stats import z_score
|
|
238
246
|
|
|
239
|
-
# 95 % confidence interval half-width for a standard normal
|
|
240
|
-
half_width =
|
|
247
|
+
# 95 % confidence interval half-width for a standard normal
|
|
248
|
+
half_width = z_score() # standard deviation is 1
|
|
241
249
|
|
|
242
|
-
#
|
|
250
|
+
# Upper 1 % critical value for an Exponential(lambda=2)
|
|
243
251
|
zval = z_score(alpha=0.01, two_sided=False, distribution=expon(lambda_=2))
|
|
244
252
|
```
|
|
245
253
|
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
# Do not put anything else in this file
|
|
2
|
-
__version__ = "4.3.
|
|
2
|
+
__version__ = "4.3.1"
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
from typing import SupportsIndex
|
|
4
|
+
|
|
3
5
|
import _pelutils_c as _c
|
|
4
6
|
import numpy as np
|
|
7
|
+
from typing_extensions import override
|
|
5
8
|
|
|
6
9
|
import pelutils._c as c_utils
|
|
7
10
|
from pelutils.types import BoolArray, IntArray
|
|
@@ -171,3 +174,21 @@ class SparseGridBlobDetection:
|
|
|
171
174
|
# If the error happens early in init (e.g. wrong call to __init__), _pointer_args has not yet been defined,
|
|
172
175
|
# and the hashmap has not been created
|
|
173
176
|
pass
|
|
177
|
+
|
|
178
|
+
def __copy__(self):
|
|
179
|
+
"""Prevent shallow copies of the C-backed detector."""
|
|
180
|
+
raise TypeError("SparseGridBlobDetection instances cannot be copied or pickled")
|
|
181
|
+
|
|
182
|
+
def __deepcopy__(self, memo: dict[int, object]):
|
|
183
|
+
"""Prevent deep copies of the C-backed detector."""
|
|
184
|
+
raise TypeError("SparseGridBlobDetection instances cannot be copied or pickled")
|
|
185
|
+
|
|
186
|
+
@override
|
|
187
|
+
def __reduce__(self):
|
|
188
|
+
"""Prevent pickling of the C-backed detector."""
|
|
189
|
+
raise TypeError("SparseGridBlobDetection instances cannot be copied or pickled")
|
|
190
|
+
|
|
191
|
+
@override
|
|
192
|
+
def __reduce_ex__(self, protocol: SupportsIndex):
|
|
193
|
+
"""Prevent protocol-specific pickling of the C-backed detector."""
|
|
194
|
+
raise TypeError("SparseGridBlobDetection instances cannot be copied or pickled")
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"""JSON persistence for Pydantic models containing non-JSON values.
|
|
2
|
+
|
|
3
|
+
JSON is useful when the structure of a file should remain inspectable, but it does not represent
|
|
4
|
+
values such as NumPy arrays, tensors, or arbitrary Python objects. ``UniversalJsonModel``
|
|
5
|
+
keeps JSON-native values in the document and stores unsupported field values as base64-encoded
|
|
6
|
+
pickle payloads. This preserves a readable JSON envelope without requiring callers to write
|
|
7
|
+
converters for every field type.
|
|
8
|
+
|
|
9
|
+
The usual interface is :meth:`UniversalJsonModel.save` and
|
|
10
|
+
:meth:`UniversalJsonModel.load`. ``save`` creates missing parent directories and writes the model to a JSON
|
|
11
|
+
file; ``load`` reconstructs the model from that file. Use :meth:`UniversalJsonModel.to_json_dict`
|
|
12
|
+
and :meth:`UniversalJsonModel.from_json_dict` when the serialized representation should be nested
|
|
13
|
+
inside another structure or handled by another storage layer.
|
|
14
|
+
|
|
15
|
+
For standalone dictionaries and lists, ``pretty_json`` converts Python objects to pretty-formatted JSON,
|
|
16
|
+
filling the same role as ``json.dumps``, but often making the resulting JSON more readable.
|
|
17
|
+
JSONL helpers handle files containing multiple JSON records separated by newlines.
|
|
18
|
+
|
|
19
|
+
Quick start
|
|
20
|
+
-----------
|
|
21
|
+
|
|
22
|
+
.. code-block:: python
|
|
23
|
+
|
|
24
|
+
import numpy as np
|
|
25
|
+
from pelutils.serialization import UniversalJsonModel
|
|
26
|
+
from pelutils.types import FloatArray
|
|
27
|
+
|
|
28
|
+
class Result(UniversalJsonModel):
|
|
29
|
+
accuracy: float
|
|
30
|
+
predictions: FloatArray # numpy arrays are handled automatically
|
|
31
|
+
|
|
32
|
+
result = Result(accuracy=0.97, predictions=np.arange(5, dtype=np.float16))
|
|
33
|
+
result.save("results/run-1.json")
|
|
34
|
+
result = Result.load("results/run-1.json")
|
|
35
|
+
|
|
36
|
+
This format is intended for trusted application data such as experiment results and cached state,
|
|
37
|
+
not as a language-neutral interchange format. Pickle payloads are Python-specific, and loading
|
|
38
|
+
them can execute arbitrary code. Use a format with an explicit schema and safe decoder when data
|
|
39
|
+
comes from outside the application.
|
|
40
|
+
|
|
41
|
+
.. warning::
|
|
42
|
+
|
|
43
|
+
``UniversalJsonModel.load`` and the pickle fallback execute code while loading. Never load
|
|
44
|
+
files from an untrusted source.
|
|
45
|
+
"""
|
|
46
|
+
|
|
47
|
+
from ._jsonl import jsonl_dump, jsonl_dumps, jsonl_load, jsonl_loads
|
|
48
|
+
from ._pretty_json import pretty_json
|
|
49
|
+
from ._universal_json_model import UniversalJsonModel
|
|
50
|
+
|
|
51
|
+
__all__ = ("UniversalJsonModel", "jsonl_dump", "jsonl_dumps", "jsonl_load", "jsonl_loads", "pretty_json")
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
"""Statistical helpers and
|
|
1
|
+
"""Statistical helpers and SciPy distributions parametrised the way textbooks are.
|
|
2
2
|
|
|
3
3
|
``scipy.stats`` parametrises every distribution through generic ``loc``/``scale``
|
|
4
4
|
arguments, which rarely match how a distribution is actually defined: an exponential's
|
|
5
5
|
``scale`` is ``1 / lambda``, a normal takes a standard deviation rather than a variance,
|
|
6
6
|
and a gamma's ``a``/``scale`` bear no obvious relation to its shape and rate. This module
|
|
7
|
-
wraps the
|
|
8
|
-
the conventions in Jim Pitman's *Probability* — and returns an ordinary frozen
|
|
7
|
+
wraps the SciPy distributions so you pass their *natural* parameters instead — following
|
|
8
|
+
the conventions in Jim Pitman's *Probability* — and returns an ordinary frozen SciPy
|
|
9
9
|
distribution, so ``.pdf``, ``.cdf``, ``.rvs`` and friends all work as usual. It also
|
|
10
10
|
provides :func:`z_score` for turning a significance level into a critical value.
|
|
11
11
|
|
|
@@ -17,12 +17,12 @@ Quick start
|
|
|
17
17
|
from pelutils.stats import expon, norm, z_score
|
|
18
18
|
|
|
19
19
|
dist = norm(mu=0, sigma2=4) # mean and *variance*, not standard deviation
|
|
20
|
-
dist.cdf(1.5) # a plain frozen
|
|
20
|
+
dist.cdf(1.5) # a plain frozen SciPy distribution
|
|
21
21
|
|
|
22
|
-
# 95 % confidence-interval half-width for a standard normal
|
|
23
|
-
half_width =
|
|
22
|
+
# 95 % confidence-interval half-width for a standard normal
|
|
23
|
+
half_width = z_score() # standard deviation is 1
|
|
24
24
|
|
|
25
|
-
#
|
|
25
|
+
# Upper 1 % critical value for an Exponential(lambda=2)
|
|
26
26
|
zval = z_score(alpha=0.01, two_sided=False, distribution=expon(lambda_=2))
|
|
27
27
|
|
|
28
28
|
Continuous distributions: :func:`norm`, :func:`lognorm`, :func:`expon`, :func:`gamma`,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""Functions returning
|
|
1
|
+
"""Functions returning SciPy distribution objects reparameterized to Jim Pitman's "Probability"."""
|
|
2
2
|
|
|
3
3
|
import numpy as np
|
|
4
4
|
from scipy import stats
|
|
@@ -6,25 +6,25 @@ from scipy import stats
|
|
|
6
6
|
|
|
7
7
|
# Continuous distributions
|
|
8
8
|
def norm(mu: float, sigma2: float):
|
|
9
|
-
"""Return a normal distribution
|
|
9
|
+
"""Return a normal distribution with mean ``mu`` and variance ``sigma2``."""
|
|
10
10
|
assert sigma2 > 0
|
|
11
11
|
return stats.norm(loc=mu, scale=np.sqrt(sigma2))
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
def lognorm(mu: float, sigma2: float):
|
|
15
|
-
"""Return a log
|
|
15
|
+
"""Return a log-normal distribution where ``log(X)`` has mean ``mu`` and variance ``sigma2``."""
|
|
16
16
|
assert sigma2 > 0
|
|
17
17
|
return stats.lognorm(s=np.sqrt(sigma2), scale=np.exp(mu))
|
|
18
18
|
|
|
19
19
|
|
|
20
20
|
def expon(lambda_: float):
|
|
21
|
-
"""Return an exponential distribution
|
|
21
|
+
"""Return an exponential distribution with rate ``lambda_`` and mean ``1 / lambda_``."""
|
|
22
22
|
assert lambda_ > 0
|
|
23
23
|
return stats.expon(scale=1 / lambda_)
|
|
24
24
|
|
|
25
25
|
|
|
26
26
|
def gamma(r: float, lambda_: float):
|
|
27
|
-
"""Return a gamma distribution
|
|
27
|
+
"""Return a gamma distribution with shape ``r`` and rate ``lambda_``."""
|
|
28
28
|
assert r > 0 and lambda_ > 0
|
|
29
29
|
return stats.gamma(a=r, loc=0, scale=1 / lambda_)
|
|
30
30
|
|
|
@@ -32,15 +32,16 @@ def gamma(r: float, lambda_: float):
|
|
|
32
32
|
def chi2(n: int | float):
|
|
33
33
|
"""Return a chi-squared distribution with the given number of degrees of freedom.
|
|
34
34
|
|
|
35
|
-
|
|
36
|
-
|
|
35
|
+
Although degrees of freedom are commonly given as an integer, the distribution
|
|
36
|
+
is here represented as a special case of the gamma distribution, making it defined
|
|
37
|
+
for any positive real ``n``.
|
|
37
38
|
"""
|
|
38
39
|
assert n > 0
|
|
39
40
|
return gamma(n / 2, 1 / 2)
|
|
40
41
|
|
|
41
42
|
|
|
42
43
|
def rayleigh():
|
|
43
|
-
"""Return a
|
|
44
|
+
"""Return a Rayleigh distribution."""
|
|
44
45
|
return stats.rayleigh()
|
|
45
46
|
|
|
46
47
|
|
|
@@ -52,42 +53,52 @@ def beta(r: float, s: float):
|
|
|
52
53
|
|
|
53
54
|
# Discrete distributions
|
|
54
55
|
def bernoulli(p: float):
|
|
55
|
-
"""Return a Bernoulli distribution
|
|
56
|
+
"""Return a Bernoulli distribution with success probability ``p``."""
|
|
56
57
|
assert 0 <= p <= 1
|
|
57
58
|
return stats.bernoulli(p)
|
|
58
59
|
|
|
59
60
|
|
|
60
61
|
def binomial(n: int, p: float):
|
|
61
|
-
"""Return a binomial distribution
|
|
62
|
+
"""Return a binomial distribution for ``n`` trials with success probability ``p``."""
|
|
62
63
|
assert n >= 0 and 0 <= p <= 1
|
|
63
64
|
return stats.binom(n=n, p=p)
|
|
64
65
|
|
|
65
66
|
|
|
66
67
|
def poisson(mu: float):
|
|
67
|
-
"""Return a Poisson distribution
|
|
68
|
+
"""Return a Poisson distribution with mean and rate ``mu``."""
|
|
68
69
|
assert mu >= 0
|
|
69
70
|
return stats.poisson(mu=mu)
|
|
70
71
|
|
|
71
72
|
|
|
72
73
|
def hypergeom(n: int, N: int, G: int): # noqa: N803
|
|
73
|
-
"""Return a hypergeometric distribution.
|
|
74
|
+
"""Return a hypergeometric distribution.
|
|
75
|
+
|
|
76
|
+
Parameters
|
|
77
|
+
----------
|
|
78
|
+
n:
|
|
79
|
+
Number of items drawn from the population.
|
|
80
|
+
N:
|
|
81
|
+
Population size.
|
|
82
|
+
G:
|
|
83
|
+
Number of successes in the population.
|
|
84
|
+
"""
|
|
74
85
|
assert N > n > 0 and N >= G > 0 and N > 1
|
|
75
86
|
return stats.hypergeom(M=N, n=G, N=n)
|
|
76
87
|
|
|
77
88
|
|
|
78
89
|
def geom0(p: float):
|
|
79
|
-
"""Return a geometric distribution
|
|
90
|
+
"""Return a geometric distribution of failures before the first success, with success probability ``p``."""
|
|
80
91
|
assert 0 < p <= 1
|
|
81
92
|
return stats.geom(loc=-1, p=p)
|
|
82
93
|
|
|
83
94
|
|
|
84
95
|
def geom1(p: float):
|
|
85
|
-
"""Return a geometric distribution
|
|
96
|
+
"""Return a geometric distribution of the trial of the first success, with success probability ``p``."""
|
|
86
97
|
assert 0 < p <= 1
|
|
87
98
|
return stats.geom(p=p)
|
|
88
99
|
|
|
89
100
|
|
|
90
101
|
def nbinom(r: int, p: float):
|
|
91
|
-
"""Return a negative binomial distribution
|
|
102
|
+
"""Return a negative binomial distribution of failures before ``r`` successes, with success probability ``p``."""
|
|
92
103
|
assert r > 0 and 0 <= p <= 1
|
|
93
104
|
return stats.nbinom(n=r, p=p)
|
|
@@ -4,16 +4,20 @@ from ._distributions import norm
|
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
def z_score(alpha: float = 0.05, two_sided: bool = True, distribution: Any | None = None) -> float: # pyright: ignore[reportExplicitAny]
|
|
7
|
-
"""Return
|
|
7
|
+
"""Return an upper critical value for a given significance level.
|
|
8
8
|
|
|
9
9
|
Parameters
|
|
10
10
|
----------
|
|
11
11
|
alpha : float, optional
|
|
12
12
|
Significance level in ``[0, 1]``.
|
|
13
13
|
two_sided : bool, optional
|
|
14
|
-
If ``True``,
|
|
14
|
+
If ``True``, use an upper-tail probability of ``alpha / 2``; otherwise use
|
|
15
|
+
``alpha``. For symmetric distributions this gives the usual two-sided
|
|
16
|
+
cutoff for a distribution symmetric about zero, with the lower cutoff equal
|
|
17
|
+
to the negative of the returned value.
|
|
18
|
+
For asymmetric distributions, the returned value is only the upper cutoff.
|
|
15
19
|
distribution : Any | None, optional
|
|
16
|
-
A frozen
|
|
20
|
+
A frozen SciPy distribution to draw the quantile from. Defaults to ``N(0, 1)``,
|
|
17
21
|
in which case the two-sided default returns the familiar ``~1.96``.
|
|
18
22
|
"""
|
|
19
23
|
if not 0 <= alpha <= 1:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: pelutils
|
|
3
|
-
Version: 4.3.
|
|
3
|
+
Version: 4.3.1
|
|
4
4
|
Summary: The Swiss army knife of Python projects
|
|
5
5
|
Home-page: https://github.com/peleiden/pelutils
|
|
6
6
|
Download-URL: https://pypi.org/project/pelutils/
|
|
@@ -164,10 +164,15 @@ importantly one per thread, as profiling is not thread-safe.
|
|
|
164
164
|
|
|
165
165
|
## Serialisation
|
|
166
166
|
|
|
167
|
-
`UniversalJsonModel`
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
167
|
+
`UniversalJsonModel` is for storing Pydantic models that contain a mixture of ordinary JSON
|
|
168
|
+
values and Python-specific values. Ordinary values remain JSON, so the file structure can be
|
|
169
|
+
inspected and diffed. Values that JSON cannot represent, such as NumPy arrays, tensors, and
|
|
170
|
+
other Python objects, are stored as base64-encoded pickle payloads.
|
|
171
|
+
|
|
172
|
+
The `save()` and `load()` methods support convient file-based workflows.
|
|
173
|
+
`save()` serialises the model to a JSON file, while `load()` reconstructs the model from one.
|
|
174
|
+
Use `to_json_dict()` and `from_json_dict(...)` when the serialized representation belongs inside
|
|
175
|
+
another structure or is handled by another storage layer.
|
|
171
176
|
|
|
172
177
|
```py
|
|
173
178
|
import numpy as np
|
|
@@ -193,11 +198,14 @@ result.save("results/run-1.json")
|
|
|
193
198
|
result = Result.load("results/run-1.json")
|
|
194
199
|
```
|
|
195
200
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
+
`pretty_json` is a string-returning formatter for standalone dictionaries and lists. It fills the
|
|
202
|
+
same role as `json.dumps`, with compact nested containers and wrapped primitive lists; write the
|
|
203
|
+
returned string to a file when needed. The module also includes JSONL read/write helpers
|
|
204
|
+
(`jsonl_dump`, `jsonl_load`, ...) for newline-delimited records.
|
|
205
|
+
|
|
206
|
+
This format is intended for trusted configuration objects, application state, experiment results, etc., not as a
|
|
207
|
+
language-neutral interchange format. Pickle payloads are Python-specific and loading them can
|
|
208
|
+
execute arbitrary code. Do not load files from untrusted sources.
|
|
201
209
|
|
|
202
210
|
## Config and command-line argument parsing
|
|
203
211
|
|
|
@@ -254,18 +262,18 @@ values, index, inverse, counts = unique(
|
|
|
254
262
|
|
|
255
263
|
### Statistics
|
|
256
264
|
|
|
257
|
-
Common statistical helpers, plus wrappers around
|
|
258
|
-
as in Jim Pitman's *Probability* (rather than
|
|
265
|
+
Common statistical helpers, plus wrappers around SciPy distributions reparametrised
|
|
266
|
+
as in Jim Pitman's *Probability* (rather than SciPy's `loc`/`scale`, which are
|
|
259
267
|
unintuitive for many distributions).
|
|
260
268
|
|
|
261
269
|
```py
|
|
262
|
-
from pelutils.stats import z_score
|
|
263
270
|
from pelutils.stats import expon
|
|
271
|
+
from pelutils.stats import z_score
|
|
264
272
|
|
|
265
|
-
# 95 % confidence interval half-width for a standard normal
|
|
266
|
-
half_width =
|
|
273
|
+
# 95 % confidence interval half-width for a standard normal
|
|
274
|
+
half_width = z_score() # standard deviation is 1
|
|
267
275
|
|
|
268
|
-
#
|
|
276
|
+
# Upper 1 % critical value for an Exponential(lambda=2)
|
|
269
277
|
zval = z_score(alpha=0.01, two_sided=False, distribution=expon(lambda_=2))
|
|
270
278
|
```
|
|
271
279
|
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
"""JSON persistence for values that plain ``json`` and even ``pydantic`` cannot handle.
|
|
2
|
-
|
|
3
|
-
Persisting data, whatever it may be, to disk usually usually comes down to a choice between
|
|
4
|
-
human-readable or not. If efficiency is not crucial, human-readable is preferable, but often
|
|
5
|
-
times, the data is not trivially serialisable to human-friendly formats. While ``pydantic``'s
|
|
6
|
-
``BaseModel.model_dump`` takes you some of the way, it falls short as soon as you introduce
|
|
7
|
-
data types which are not JSON-serialisable by default, making pickling the default choice and
|
|
8
|
-
ending up with an unreadable binary blob.
|
|
9
|
-
|
|
10
|
-
Even if all data is easily serialisable to a readable format, you still have to deal with all
|
|
11
|
-
the boilerplate of ensuring parent directories exist, and opening and closing files.
|
|
12
|
-
|
|
13
|
-
Enter :class:`UniversalJsonModel` — a ``pydantic.BaseModel`` whose
|
|
14
|
-
``save``/``load`` methods serialise/deserialise *any* attribute: JSON-native values stay plain and
|
|
15
|
-
human-readable, while anything else (numpy arrays, torch tensors, arbitrary objects) is
|
|
16
|
-
pickled and base64-encoded inline. The output is a single, easily readable JSON file.
|
|
17
|
-
|
|
18
|
-
Quick start
|
|
19
|
-
-----------
|
|
20
|
-
|
|
21
|
-
.. code-block:: python
|
|
22
|
-
|
|
23
|
-
import numpy as np
|
|
24
|
-
from pelutils.serialization import UniversalJsonModel
|
|
25
|
-
from pelutils.types import FloatArray
|
|
26
|
-
|
|
27
|
-
class Result(UniversalJsonModel):
|
|
28
|
-
accuracy: float
|
|
29
|
-
predictions: FloatArray # numpy arrays are handled automatically
|
|
30
|
-
|
|
31
|
-
result = Result(accuracy=0.97, predictions=np.arange(5, dtype=np.float16))
|
|
32
|
-
result.save("results/run-1.json")
|
|
33
|
-
result = Result.load("results/run-1.json")
|
|
34
|
-
|
|
35
|
-
The module also exposes :func:`pretty_json`, a function similar to the built-in `json.dumps`,
|
|
36
|
-
but which formats the given object to a pretty JSON string;
|
|
37
|
-
short containers stay on one line, and long primitive lists are packed across both the width and height
|
|
38
|
-
of the file.
|
|
39
|
-
JSONL helpers (:func:`jsonl_dump`, :func:`jsonl_load`, and their string variants) for files where each
|
|
40
|
-
line is its own JSON object are also provided.
|
|
41
|
-
|
|
42
|
-
.. warning::
|
|
43
|
-
|
|
44
|
-
Loading pickles executes arbitrary code, so never ``load`` data from an untrusted source.
|
|
45
|
-
"""
|
|
46
|
-
|
|
47
|
-
from ._jsonl import jsonl_dump, jsonl_dumps, jsonl_load, jsonl_loads
|
|
48
|
-
from ._pretty_json import pretty_json
|
|
49
|
-
from ._universal_json_model import UniversalJsonModel
|
|
50
|
-
|
|
51
|
-
__all__ = ("UniversalJsonModel", "jsonl_dump", "jsonl_dumps", "jsonl_load", "jsonl_loads", "pretty_json")
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|