pynumerics 2.3.0__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.
- pynumerics/__init__.py +73 -0
- pynumerics/_bin/Microsoft.CodeAnalysis.CSharp.dll +0 -0
- pynumerics/_bin/Microsoft.CodeAnalysis.LICENSE.txt +27 -0
- pynumerics/_bin/Microsoft.CodeAnalysis.dll +0 -0
- pynumerics/_bin/Numerics.dll +0 -0
- pynumerics/_bin/pynumerics.runtimeconfig.json +15 -0
- pynumerics/_coverage.py +3825 -0
- pynumerics/_util.py +237 -0
- pynumerics/_version.py +40 -0
- pynumerics/bootstrap.py +593 -0
- pynumerics/callbacks.py +791 -0
- pynumerics/copulas.py +910 -0
- pynumerics/data.py +2233 -0
- pynumerics/differentiation.py +348 -0
- pynumerics/distributions.py +4043 -0
- pynumerics/download.py +623 -0
- pynumerics/enums.py +119 -0
- pynumerics/errors.py +245 -0
- pynumerics/functions.py +1142 -0
- pynumerics/goodness_of_fit.py +699 -0
- pynumerics/graphs.py +556 -0
- pynumerics/hypothesis_tests.py +445 -0
- pynumerics/identity.py +144 -0
- pynumerics/integration.py +677 -0
- pynumerics/linalg.py +1408 -0
- pynumerics/machine_learning.py +1335 -0
- pynumerics/marshal.py +733 -0
- pynumerics/mathematics.py +1053 -0
- pynumerics/mcmc.py +1406 -0
- pynumerics/multivariate.py +1539 -0
- pynumerics/ode.py +156 -0
- pynumerics/optimization.py +1736 -0
- pynumerics/probability.py +966 -0
- pynumerics/py.typed +0 -0
- pynumerics/regional.py +522 -0
- pynumerics/roots.py +274 -0
- pynumerics/runtime.py +384 -0
- pynumerics/sampling.py +1758 -0
- pynumerics/special.py +1079 -0
- pynumerics/statistics.py +1958 -0
- pynumerics/timeseries.py +1326 -0
- pynumerics-2.3.0.dist-info/METADATA +142 -0
- pynumerics-2.3.0.dist-info/RECORD +46 -0
- pynumerics-2.3.0.dist-info/WHEEL +5 -0
- pynumerics-2.3.0.dist-info/licenses/LICENSE +10 -0
- pynumerics-2.3.0.dist-info/top_level.txt +1 -0
pynumerics/statistics.py
ADDED
|
@@ -0,0 +1,1958 @@
|
|
|
1
|
+
"""Descriptive statistics from ``Numerics.Data.Statistics``.
|
|
2
|
+
|
|
3
|
+
Thin calls into ``Statistics`` (sequential sums, Type-7 and weighted percentiles, ranks and
|
|
4
|
+
L-moments), ``Correlation`` (Pearson, Spearman and Kendall's tau-b), ``BoxCox``,
|
|
5
|
+
``RunningStatistics`` (streaming moments), ``PlottingPositions`` and ``Autocorrelation``.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import operator
|
|
11
|
+
from typing import Any
|
|
12
|
+
|
|
13
|
+
import numpy as np
|
|
14
|
+
|
|
15
|
+
from pynumerics import callbacks
|
|
16
|
+
from pynumerics._util import bind, bind_list, cached_overload, evaluate, loop, namespace, net_enum
|
|
17
|
+
from pynumerics.enums import AutocorrelationType, PlottingPosition, WeightType
|
|
18
|
+
from pynumerics.errors import translate_public
|
|
19
|
+
from pynumerics.marshal import _bound, to_net_doubles, to_net_matrix, to_numpy_doubles, to_numpy_ints, to_numpy_matrix
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _stats() -> Any:
|
|
23
|
+
"""Return the ``Numerics.Data.Statistics`` namespace after starting the runtime."""
|
|
24
|
+
return namespace("Numerics.Data.Statistics")
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def _statistics_member(name: str, *signature: str) -> Any:
|
|
28
|
+
"""Return one overload of a ``Statistics`` method group, bound once per process.
|
|
29
|
+
|
|
30
|
+
``signature`` names the parameter types: ``"list"`` (``IList<double>``), ``"double"``,
|
|
31
|
+
``"bool"``, ``"int"``, ``"kind"`` (``PlottingPositions.PlottingPostionType``) and ``"weight"``
|
|
32
|
+
(``WeightType``). The bound overload is the member pythonnet would resolve for the same
|
|
33
|
+
arguments; binding it once removes the per-call resolution (see ``_util.cached_overload``).
|
|
34
|
+
"""
|
|
35
|
+
def factory() -> Any:
|
|
36
|
+
stats = _stats()
|
|
37
|
+
import System # noqa: PLC0415 - the runtime is running
|
|
38
|
+
from System.Collections.Generic import IList # noqa: PLC0415
|
|
39
|
+
|
|
40
|
+
types = {"list": IList[System.Double], "double": System.Double, "bool": System.Boolean, "int": System.Int32,
|
|
41
|
+
"kind": stats.PlottingPositions.PlottingPostionType, "weight": stats.WeightType}
|
|
42
|
+
return getattr(stats.Statistics, name).Overloads[tuple(types[item] for item in signature)]
|
|
43
|
+
|
|
44
|
+
return cached_overload(f"Statistics.{name}({', '.join(signature)})", factory)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def mean(data: Any, weights: Any = None) -> float:
|
|
48
|
+
"""Return the mean through ``Statistics.Mean`` (sequential summation).
|
|
49
|
+
|
|
50
|
+
Parameters
|
|
51
|
+
----------
|
|
52
|
+
data : array_like
|
|
53
|
+
Values.
|
|
54
|
+
weights : array_like, optional
|
|
55
|
+
Weights for ``Statistics.Mean(IList, IList)``.
|
|
56
|
+
|
|
57
|
+
Returns
|
|
58
|
+
-------
|
|
59
|
+
float
|
|
60
|
+
The (weighted) mean.
|
|
61
|
+
"""
|
|
62
|
+
if weights is None:
|
|
63
|
+
return float(_statistics_member("Mean", "list")(to_net_doubles(data)))
|
|
64
|
+
return float(_statistics_member("Mean", "list", "list")(to_net_doubles(data), to_net_doubles(weights)))
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def variance(data: Any, weights: Any = None, weight_type: WeightType | str = WeightType.FREQUENCY) -> float:
|
|
68
|
+
"""Return the sample variance through ``Statistics.Variance``.
|
|
69
|
+
|
|
70
|
+
Parameters
|
|
71
|
+
----------
|
|
72
|
+
data : array_like
|
|
73
|
+
Values.
|
|
74
|
+
weights : array_like, optional
|
|
75
|
+
Weights; when given ``weight_type`` selects frequency or reliability weights.
|
|
76
|
+
weight_type : WeightType or str, optional
|
|
77
|
+
Weight interpretation; default frequency.
|
|
78
|
+
|
|
79
|
+
Returns
|
|
80
|
+
-------
|
|
81
|
+
float
|
|
82
|
+
The variance.
|
|
83
|
+
"""
|
|
84
|
+
stats = _stats()
|
|
85
|
+
if weights is None:
|
|
86
|
+
return float(_statistics_member("Variance", "list")(to_net_doubles(data)))
|
|
87
|
+
member = _statistics_member("Variance", "list", "list", "weight")
|
|
88
|
+
return float(member(to_net_doubles(data), to_net_doubles(weights), net_enum(stats.WeightType, weight_type)))
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def standard_deviation(data: Any, weights: Any = None, weight_type: WeightType | str = WeightType.FREQUENCY) -> float:
|
|
92
|
+
"""Return the sample standard deviation through ``Statistics.StandardDeviation``.
|
|
93
|
+
|
|
94
|
+
Parameters
|
|
95
|
+
----------
|
|
96
|
+
data : array_like
|
|
97
|
+
Values.
|
|
98
|
+
weights : array_like, optional
|
|
99
|
+
Weights; when given ``weight_type`` selects frequency or reliability weights.
|
|
100
|
+
weight_type : WeightType or str, optional
|
|
101
|
+
Weight interpretation; default frequency.
|
|
102
|
+
|
|
103
|
+
Returns
|
|
104
|
+
-------
|
|
105
|
+
float
|
|
106
|
+
The standard deviation.
|
|
107
|
+
"""
|
|
108
|
+
stats = _stats()
|
|
109
|
+
if weights is None:
|
|
110
|
+
return float(_statistics_member("StandardDeviation", "list")(to_net_doubles(data)))
|
|
111
|
+
member = _statistics_member("StandardDeviation", "list", "list", "weight")
|
|
112
|
+
return float(member(to_net_doubles(data), to_net_doubles(weights), net_enum(stats.WeightType, weight_type)))
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def median(data: Any, data_is_sorted: bool = False) -> float:
|
|
116
|
+
"""Return the median through ``Statistics.Median``.
|
|
117
|
+
|
|
118
|
+
For an even count the result is the correctly rounded midpoint ``0.5 * (lo + hi)`` of the two
|
|
119
|
+
middle values, as ``numpy.median`` computes it; ``percentile(data, 0.5)`` (Type 7) can differ
|
|
120
|
+
from it in the last bit.
|
|
121
|
+
|
|
122
|
+
Parameters
|
|
123
|
+
----------
|
|
124
|
+
data : array_like
|
|
125
|
+
Values.
|
|
126
|
+
data_is_sorted : bool, optional
|
|
127
|
+
Whether ``data`` is already ascending; default False.
|
|
128
|
+
|
|
129
|
+
Returns
|
|
130
|
+
-------
|
|
131
|
+
float
|
|
132
|
+
The median.
|
|
133
|
+
"""
|
|
134
|
+
return float(_statistics_member("Median", "list", "bool")(to_net_doubles(data), bool(data_is_sorted)))
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def percentile(data: Any, k: Any, weights: Any = None, data_is_sorted: bool = False) -> Any:
|
|
138
|
+
"""Return percentiles through ``Statistics.Percentile``.
|
|
139
|
+
|
|
140
|
+
Unweighted percentiles are Type 7 (position (n − 1)k). Weighted percentiles use
|
|
141
|
+
``Statistics.Percentile(IList, k, IList weights, bool)``, which reduces to Type 7 at
|
|
142
|
+
unit weights.
|
|
143
|
+
|
|
144
|
+
Parameters
|
|
145
|
+
----------
|
|
146
|
+
data : array_like
|
|
147
|
+
Values.
|
|
148
|
+
k : float or array_like
|
|
149
|
+
Percentiles as fractions in [0, 1].
|
|
150
|
+
weights : array_like, optional
|
|
151
|
+
Weights, one per value.
|
|
152
|
+
data_is_sorted : bool, optional
|
|
153
|
+
Whether ``data`` is already ascending; default False.
|
|
154
|
+
|
|
155
|
+
Returns
|
|
156
|
+
-------
|
|
157
|
+
float or numpy.ndarray
|
|
158
|
+
Percentile values, shaped like ``k``.
|
|
159
|
+
"""
|
|
160
|
+
values = to_net_doubles(data)
|
|
161
|
+
karr = np.asarray(k, dtype=np.float64)
|
|
162
|
+
scalar = karr.ndim == 0
|
|
163
|
+
ks = float(karr) if scalar else to_net_doubles(karr.ravel())
|
|
164
|
+
k_type = "double" if scalar else "list"
|
|
165
|
+
if weights is None:
|
|
166
|
+
result = _statistics_member("Percentile", "list", k_type, "bool")(values, ks, bool(data_is_sorted))
|
|
167
|
+
else:
|
|
168
|
+
result = _statistics_member("Percentile", "list", k_type, "list", "bool")(values, ks, to_net_doubles(weights),
|
|
169
|
+
bool(data_is_sorted))
|
|
170
|
+
return float(result) if scalar else to_numpy_doubles(result).reshape(karr.shape)
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def plotting_position_percentile(data: Any, k: Any,
|
|
174
|
+
kind: PlottingPosition | str = PlottingPosition.WEIBULL,
|
|
175
|
+
data_is_sorted: bool = False, weights: Any = None) -> Any:
|
|
176
|
+
"""Return percentiles interpolated between order statistics at plotting positions.
|
|
177
|
+
|
|
178
|
+
Calls ``Statistics.Percentile(IList, k, PlottingPostionType, bool)``: the i-th order
|
|
179
|
+
statistic sits at its plotting position and the percentile interpolates linearly between
|
|
180
|
+
them, held at the sample extremes outside the first and last positions. Weibull is
|
|
181
|
+
Hyndman-Fan type 6 (NumPy ``method="weibull"``), Hazen type 5 and Kaplan-Meier type 4. For
|
|
182
|
+
Weibull, Blom and Hazen the interpolation weight is formed from ``k`` and the two bracketing
|
|
183
|
+
positions, which is closer to exact rational evaluation than the fractional part of the rank.
|
|
184
|
+
|
|
185
|
+
With ``weights`` it calls ``Statistics.Percentile(IList, k, IList weights, PlottingPostionType,
|
|
186
|
+
bool)``, with an array ``k`` the list overload, which validates and sorts the sample once and
|
|
187
|
+
serves every probability in one walk, each value bitwise the scalar call. Point i sits at the
|
|
188
|
+
weighted position ``(c_(i-1) + (1 - alpha) w_i) / (W + (1 - 2 alpha) w_mean)``
|
|
189
|
+
(``(c_(i-1) + w_i / 2) / W`` for Hazen, ``c_i / W`` for Kaplan-Meier), zero weights included.
|
|
190
|
+
|
|
191
|
+
Parameters
|
|
192
|
+
----------
|
|
193
|
+
data : array_like
|
|
194
|
+
Values.
|
|
195
|
+
k : float or array_like
|
|
196
|
+
Percentiles as fractions in [0, 1].
|
|
197
|
+
kind : PlottingPosition or str, optional
|
|
198
|
+
The plotting-position formula; default Weibull.
|
|
199
|
+
data_is_sorted : bool, optional
|
|
200
|
+
Whether ``data`` is already ascending; default False.
|
|
201
|
+
weights : array_like, optional
|
|
202
|
+
The non-negative weight of each value, aligned with ``data``; default unweighted.
|
|
203
|
+
|
|
204
|
+
Returns
|
|
205
|
+
-------
|
|
206
|
+
float or numpy.ndarray
|
|
207
|
+
Percentile values, shaped like ``k``.
|
|
208
|
+
"""
|
|
209
|
+
kind_net = net_enum(_stats().PlottingPositions.PlottingPostionType, kind)
|
|
210
|
+
values = to_net_doubles(data)
|
|
211
|
+
karr = np.asarray(k, dtype=np.float64)
|
|
212
|
+
if weights is not None:
|
|
213
|
+
k_type = "double" if karr.ndim == 0 else "list"
|
|
214
|
+
member = _statistics_member("Percentile", "list", k_type, "list", "kind", "bool")
|
|
215
|
+
net_weights = to_net_doubles(weights)
|
|
216
|
+
if karr.ndim == 0:
|
|
217
|
+
return float(member(values, float(karr), net_weights, kind_net, bool(data_is_sorted)))
|
|
218
|
+
result = member(values, to_net_doubles(karr.ravel()), net_weights, kind_net, bool(data_is_sorted))
|
|
219
|
+
return to_numpy_doubles(result).reshape(karr.shape)
|
|
220
|
+
if karr.ndim == 0:
|
|
221
|
+
return float(_statistics_member("Percentile", "list", "double", "kind", "bool")(
|
|
222
|
+
values, float(karr), kind_net, bool(data_is_sorted)))
|
|
223
|
+
result = _statistics_member("Percentile", "list", "list", "kind", "bool")(
|
|
224
|
+
values, to_net_doubles(karr.ravel()), kind_net, bool(data_is_sorted))
|
|
225
|
+
return to_numpy_doubles(result).reshape(karr.shape)
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
def column_percentiles(data: Any, k: Any,
|
|
229
|
+
kind: PlottingPosition | str | None = None) -> tuple[np.ndarray, np.ndarray]:
|
|
230
|
+
"""Return the percentiles of each column over its finite entries (``Statistics.ColumnPercentiles``).
|
|
231
|
+
|
|
232
|
+
Each column's finite entries go through ``Statistics.Percentile`` in one call for the
|
|
233
|
+
whole matrix, so every value is bitwise the per-column ``percentile`` (Type 7, the
|
|
234
|
+
default) or ``plotting_position_percentile`` (when ``kind`` is given) of the finite
|
|
235
|
+
entries; NaN and infinite entries are excluded rather than sorted in.
|
|
236
|
+
|
|
237
|
+
Parameters
|
|
238
|
+
----------
|
|
239
|
+
data : array_like
|
|
240
|
+
Two-dimensional samples, one row per member (for example a realization) and one
|
|
241
|
+
column per variable (for example a curve node).
|
|
242
|
+
k : float or array_like
|
|
243
|
+
Percentiles as fractions in [0, 1].
|
|
244
|
+
kind : PlottingPosition or str, optional
|
|
245
|
+
A plotting-position formula (``"weibull"`` is Hyndman-Fan type 6) for
|
|
246
|
+
``ColumnPercentiles(double[,], IList, PlottingPostionType, out int[])``; None (the
|
|
247
|
+
default) gives the Type 7 percentiles.
|
|
248
|
+
|
|
249
|
+
Returns
|
|
250
|
+
-------
|
|
251
|
+
percentiles : numpy.ndarray
|
|
252
|
+
Shape ``(len(k), columns)`` (``(columns,)`` for a scalar ``k``); NaN for a column
|
|
253
|
+
without a finite entry.
|
|
254
|
+
excluded : numpy.ndarray
|
|
255
|
+
The int32 number of non-finite entries excluded from each column.
|
|
256
|
+
"""
|
|
257
|
+
stats = _stats()
|
|
258
|
+
karr = np.asarray(k, dtype=np.float64)
|
|
259
|
+
matrix, ks = to_net_matrix(data), to_net_doubles(karr.ravel())
|
|
260
|
+
if kind is None:
|
|
261
|
+
table, excluded = stats.Statistics.ColumnPercentiles(matrix, ks, None)
|
|
262
|
+
else:
|
|
263
|
+
kind_net = net_enum(stats.PlottingPositions.PlottingPostionType, kind)
|
|
264
|
+
table, excluded = stats.Statistics.ColumnPercentiles(matrix, ks, kind_net, None)
|
|
265
|
+
result = to_numpy_matrix(table)
|
|
266
|
+
if karr.ndim == 0:
|
|
267
|
+
result = result[0]
|
|
268
|
+
return result, to_numpy_ints(excluded)
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
def column_means(data: Any) -> tuple[np.ndarray, np.ndarray]:
|
|
272
|
+
"""Return the mean of each column over its finite entries (``Statistics.ColumnMeans``).
|
|
273
|
+
|
|
274
|
+
Each column's finite entries go through ``Statistics.Mean`` (a sequential sum) in one call for
|
|
275
|
+
the whole matrix, so every value is bitwise :func:`mean` of the column's finite entries; NaN and
|
|
276
|
+
infinite entries are excluded, as in :func:`column_percentiles`.
|
|
277
|
+
|
|
278
|
+
Parameters
|
|
279
|
+
----------
|
|
280
|
+
data : array_like
|
|
281
|
+
Two-dimensional samples, one row per member and one column per variable.
|
|
282
|
+
|
|
283
|
+
Returns
|
|
284
|
+
-------
|
|
285
|
+
means : numpy.ndarray
|
|
286
|
+
One mean per column; NaN for a column without a finite entry.
|
|
287
|
+
excluded : numpy.ndarray
|
|
288
|
+
The int32 number of non-finite entries excluded from each column.
|
|
289
|
+
"""
|
|
290
|
+
means, excluded = _column_statistic("ColumnMeans", data)
|
|
291
|
+
return to_numpy_doubles(means), excluded
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
def _column_statistic(member: str, data: Any) -> tuple[Any, np.ndarray]:
|
|
295
|
+
"""Call a ``Statistics`` column member through its ``(double[,], out int[])`` overload, bound once per process.
|
|
296
|
+
|
|
297
|
+
The matrix crosses in one copy; the overload is resolved on first use only.
|
|
298
|
+
"""
|
|
299
|
+
def factory() -> Any:
|
|
300
|
+
group = getattr(_stats().Statistics, member)
|
|
301
|
+
import clr # noqa: PLC0415 - the runtime is running
|
|
302
|
+
import System # noqa: PLC0415
|
|
303
|
+
|
|
304
|
+
return group.Overloads[_bound()["doubles_matrix"], clr.GetClrType(System.Array[System.Int32]).MakeByRefType()]
|
|
305
|
+
|
|
306
|
+
values, excluded = cached_overload(f"Statistics.{member}(double[,], out int[])", factory)(to_net_matrix(data), None)
|
|
307
|
+
return values, to_numpy_ints(excluded)
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
def column_variances(data: Any) -> tuple[np.ndarray, np.ndarray]:
|
|
311
|
+
"""Return the sample variance of each column over its finite entries (``Statistics.ColumnVariances``).
|
|
312
|
+
|
|
313
|
+
Every value is bitwise :func:`variance` (n - 1 divisor, corrected two-pass) of the column's
|
|
314
|
+
finite entries, computed for the whole matrix in one call; NaN and infinite entries are excluded,
|
|
315
|
+
as in :func:`column_means`. Equals ``numpy.nanvar(data, axis=0, ddof=1)`` to rounding when every
|
|
316
|
+
entry is finite or NaN.
|
|
317
|
+
|
|
318
|
+
Parameters
|
|
319
|
+
----------
|
|
320
|
+
data : array_like
|
|
321
|
+
Two-dimensional samples, one row per member and one column per variable.
|
|
322
|
+
|
|
323
|
+
Returns
|
|
324
|
+
-------
|
|
325
|
+
variances : numpy.ndarray
|
|
326
|
+
One variance per column; NaN for a column with fewer than two finite entries.
|
|
327
|
+
excluded : numpy.ndarray
|
|
328
|
+
The int32 number of non-finite entries excluded from each column.
|
|
329
|
+
"""
|
|
330
|
+
values, excluded = _column_statistic("ColumnVariances", data)
|
|
331
|
+
return to_numpy_doubles(values), excluded
|
|
332
|
+
|
|
333
|
+
|
|
334
|
+
def column_standard_deviations(data: Any) -> tuple[np.ndarray, np.ndarray]:
|
|
335
|
+
"""Return the sample standard deviation of each column over its finite entries.
|
|
336
|
+
|
|
337
|
+
Wraps ``Statistics.ColumnStandardDeviations``.
|
|
338
|
+
|
|
339
|
+
Every value is bitwise :func:`standard_deviation` of the column's finite entries, the square
|
|
340
|
+
root of the :func:`column_variances` value.
|
|
341
|
+
|
|
342
|
+
Parameters
|
|
343
|
+
----------
|
|
344
|
+
data : array_like
|
|
345
|
+
Two-dimensional samples, one row per member and one column per variable.
|
|
346
|
+
|
|
347
|
+
Returns
|
|
348
|
+
-------
|
|
349
|
+
standard_deviations : numpy.ndarray
|
|
350
|
+
One standard deviation per column; NaN for a column with fewer than two finite entries.
|
|
351
|
+
excluded : numpy.ndarray
|
|
352
|
+
The int32 number of non-finite entries excluded from each column.
|
|
353
|
+
"""
|
|
354
|
+
values, excluded = _column_statistic("ColumnStandardDeviations", data)
|
|
355
|
+
return to_numpy_doubles(values), excluded
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
def column_linear_moments(data: Any) -> tuple[np.ndarray, np.ndarray]:
|
|
359
|
+
"""Return the L-moments of each column over its finite entries (``Statistics.ColumnLinearMoments``).
|
|
360
|
+
|
|
361
|
+
Every column is bitwise :func:`linear_moments` of its finite entries. The L-CV of a column is
|
|
362
|
+
``moments[1] / moments[0]``, bitwise :func:`linear_coefficient_of_variation`.
|
|
363
|
+
|
|
364
|
+
Parameters
|
|
365
|
+
----------
|
|
366
|
+
data : array_like
|
|
367
|
+
Two-dimensional samples, one row per member and one column per variable.
|
|
368
|
+
|
|
369
|
+
Returns
|
|
370
|
+
-------
|
|
371
|
+
moments : numpy.ndarray
|
|
372
|
+
A (4, p) array with rows lambda1, lambda2, tau3 and tau4; NaN for a column with fewer than
|
|
373
|
+
four finite entries.
|
|
374
|
+
excluded : numpy.ndarray
|
|
375
|
+
The int32 number of non-finite entries excluded from each column.
|
|
376
|
+
"""
|
|
377
|
+
values, excluded = _column_statistic("ColumnLinearMoments", data)
|
|
378
|
+
return to_numpy_matrix(values), excluded
|
|
379
|
+
|
|
380
|
+
|
|
381
|
+
def wilson_score_interval(successes: float, trials: float, confidence_level: float) -> tuple[float, float]:
|
|
382
|
+
"""Return the Wilson score interval of a binomial proportion (``Statistics.WilsonScoreInterval``).
|
|
383
|
+
|
|
384
|
+
Parameters
|
|
385
|
+
----------
|
|
386
|
+
successes : float
|
|
387
|
+
The number of successes, in [0, ``trials``]; may be fractional.
|
|
388
|
+
trials : float
|
|
389
|
+
The number of trials (positive).
|
|
390
|
+
confidence_level : float
|
|
391
|
+
The two-sided level in (0, 1).
|
|
392
|
+
|
|
393
|
+
Returns
|
|
394
|
+
-------
|
|
395
|
+
tuple of float
|
|
396
|
+
The lower and upper bounds, clamped to [0, 1].
|
|
397
|
+
"""
|
|
398
|
+
bounds = _stats().Statistics.WilsonScoreInterval(float(successes), float(trials), float(confidence_level))
|
|
399
|
+
return float(bounds.Item1), float(bounds.Item2)
|
|
400
|
+
|
|
401
|
+
|
|
402
|
+
def linear_moments(data: Any, nmom: int | None = None) -> np.ndarray:
|
|
403
|
+
"""Return the sample L-moments through ``Statistics.LinearMoments``.
|
|
404
|
+
|
|
405
|
+
With ``nmom`` it calls ``Statistics.LinearMoments(IList, int)``, the unbiased estimator of
|
|
406
|
+
Hosking's SAMLMR through probability weighted moments, whose first four values are bitwise those
|
|
407
|
+
without ``nmom``; ``nmom=5`` adds the ratio ``t5`` used in regional frequency analysis.
|
|
408
|
+
|
|
409
|
+
Parameters
|
|
410
|
+
----------
|
|
411
|
+
data : array_like
|
|
412
|
+
Values (sorted by Numerics).
|
|
413
|
+
nmom : int, optional
|
|
414
|
+
The number of L-moments, at least 1; default the four-value member.
|
|
415
|
+
|
|
416
|
+
Returns
|
|
417
|
+
-------
|
|
418
|
+
numpy.ndarray
|
|
419
|
+
``[l1, l2, t3, t4]``: the first two L-moments and the L-skewness and L-kurtosis
|
|
420
|
+
ratios, as Numerics returns them; with ``nmom``, ``[l1, l2, t3, ..., t_nmom]``. All NaN
|
|
421
|
+
when there are fewer than four values (fewer than ``nmom`` with ``nmom``).
|
|
422
|
+
|
|
423
|
+
Raises
|
|
424
|
+
------
|
|
425
|
+
TypeError
|
|
426
|
+
If ``nmom`` is not an integer, for example a float.
|
|
427
|
+
ValueError
|
|
428
|
+
If ``nmom`` is less than 1.
|
|
429
|
+
"""
|
|
430
|
+
if nmom is None:
|
|
431
|
+
return to_numpy_doubles(_statistics_member("LinearMoments", "list")(to_net_doubles(data)))
|
|
432
|
+
member = _statistics_member("LinearMoments", "list", "int")
|
|
433
|
+
return to_numpy_doubles(member(to_net_doubles(data), operator.index(nmom)))
|
|
434
|
+
|
|
435
|
+
|
|
436
|
+
def linear_coefficient_of_variation(data: Any) -> float:
|
|
437
|
+
"""Return the sample L-coefficient of variation through ``Statistics.LinearCoefficientOfVariation``.
|
|
438
|
+
|
|
439
|
+
Parameters
|
|
440
|
+
----------
|
|
441
|
+
data : array_like
|
|
442
|
+
Values (sorted by Numerics).
|
|
443
|
+
|
|
444
|
+
Returns
|
|
445
|
+
-------
|
|
446
|
+
float
|
|
447
|
+
``l2 / l1``, bitwise the ratio of the first two entries of :func:`linear_moments`; NaN for
|
|
448
|
+
fewer than four values or any NaN.
|
|
449
|
+
"""
|
|
450
|
+
return float(_stats().Statistics.LinearCoefficientOfVariation(to_net_doubles(data)))
|
|
451
|
+
|
|
452
|
+
|
|
453
|
+
def ranks(data: Any, return_ties: bool = False) -> np.ndarray | tuple[np.ndarray, np.ndarray]:
|
|
454
|
+
"""Return the one-based average ranks of the values through ``Statistics.RanksInPlace``.
|
|
455
|
+
|
|
456
|
+
Values that compare equal, infinities included, share their average rank, as
|
|
457
|
+
``scipy.stats.rankdata(method="average")`` assigns them. The input is not modified.
|
|
458
|
+
|
|
459
|
+
Parameters
|
|
460
|
+
----------
|
|
461
|
+
data : array_like
|
|
462
|
+
Values, in any order.
|
|
463
|
+
return_ties : bool, optional
|
|
464
|
+
Also return the tie-run lengths of ``RanksInPlace(double[], out double[])``; default False.
|
|
465
|
+
|
|
466
|
+
Returns
|
|
467
|
+
-------
|
|
468
|
+
ranks : numpy.ndarray
|
|
469
|
+
One rank per value, in input order.
|
|
470
|
+
ties : numpy.ndarray
|
|
471
|
+
Only when ``return_ties`` is True: in sorted order, the last position of each run of k equal
|
|
472
|
+
values holds k - 1 and every other entry is zero.
|
|
473
|
+
"""
|
|
474
|
+
s = _stats().Statistics
|
|
475
|
+
values = to_net_doubles(data)
|
|
476
|
+
if not return_ties:
|
|
477
|
+
return to_numpy_doubles(s.RanksInPlace(values))
|
|
478
|
+
result, ties = s.RanksInPlace(values, None)
|
|
479
|
+
return to_numpy_doubles(result), to_numpy_doubles(ties)
|
|
480
|
+
|
|
481
|
+
|
|
482
|
+
def _correlation(name: str, sample1: Any, sample2: Any) -> Any:
|
|
483
|
+
"""Call a ``Correlation`` member on two samples, or on the columns of one 2-D array."""
|
|
484
|
+
correlation = _stats().Correlation
|
|
485
|
+
if sample2 is None:
|
|
486
|
+
return to_numpy_matrix(getattr(correlation, name)(to_net_matrix(sample1)))
|
|
487
|
+
return float(getattr(correlation, name)(to_net_doubles(sample1), to_net_doubles(sample2)))
|
|
488
|
+
|
|
489
|
+
|
|
490
|
+
def pearson(sample1: Any, sample2: Any = None) -> Any:
|
|
491
|
+
"""Return the Pearson correlation through ``Correlation.Pearson``.
|
|
492
|
+
|
|
493
|
+
Parameters
|
|
494
|
+
----------
|
|
495
|
+
sample1 : array_like
|
|
496
|
+
The first sample, or, when ``sample2`` is omitted, a 2-D array with one row per observation
|
|
497
|
+
and one column per variable.
|
|
498
|
+
sample2 : array_like, optional
|
|
499
|
+
The second sample, of the same length.
|
|
500
|
+
|
|
501
|
+
Returns
|
|
502
|
+
-------
|
|
503
|
+
float or numpy.ndarray
|
|
504
|
+
The coefficient, or the correlation matrix of the columns of ``sample1``.
|
|
505
|
+
"""
|
|
506
|
+
return _correlation("Pearson", sample1, sample2)
|
|
507
|
+
|
|
508
|
+
|
|
509
|
+
def spearman(sample1: Any, sample2: Any = None) -> Any:
|
|
510
|
+
"""Return the Spearman rank correlation through ``Correlation.Spearman``.
|
|
511
|
+
|
|
512
|
+
The Pearson correlation of the average ranks of :func:`ranks`.
|
|
513
|
+
|
|
514
|
+
Parameters
|
|
515
|
+
----------
|
|
516
|
+
sample1 : array_like
|
|
517
|
+
The first sample, or, when ``sample2`` is omitted, a 2-D array with one row per observation
|
|
518
|
+
and one column per variable.
|
|
519
|
+
sample2 : array_like, optional
|
|
520
|
+
The second sample, of the same length.
|
|
521
|
+
|
|
522
|
+
Returns
|
|
523
|
+
-------
|
|
524
|
+
float or numpy.ndarray
|
|
525
|
+
The coefficient, or the rank correlation matrix of the columns of ``sample1``.
|
|
526
|
+
"""
|
|
527
|
+
return _correlation("Spearman", sample1, sample2)
|
|
528
|
+
|
|
529
|
+
|
|
530
|
+
def kendalls_tau(sample1: Any, sample2: Any) -> float:
|
|
531
|
+
"""Return Kendall's tau-b through ``Correlation.KendallsTau``.
|
|
532
|
+
|
|
533
|
+
``(n_c - n_d) / sqrt(n_1 n_2)``, with ties counted as ``scipy.stats.kendalltau`` counts them.
|
|
534
|
+
Pairs are counted in O(n log n) for samples of 48 or more values (Knight, 1966).
|
|
535
|
+
|
|
536
|
+
Parameters
|
|
537
|
+
----------
|
|
538
|
+
sample1, sample2 : array_like
|
|
539
|
+
Samples of the same length.
|
|
540
|
+
|
|
541
|
+
Returns
|
|
542
|
+
-------
|
|
543
|
+
float
|
|
544
|
+
Tau-b; NaN when either sample contains NaN or is constant.
|
|
545
|
+
"""
|
|
546
|
+
return float(_stats().Correlation.KendallsTau(to_net_doubles(sample1), to_net_doubles(sample2)))
|
|
547
|
+
|
|
548
|
+
|
|
549
|
+
def box_cox_transform(values: Any, lam: float) -> Any:
|
|
550
|
+
"""Return the Box-Cox transformation through ``BoxCox.Transform``.
|
|
551
|
+
|
|
552
|
+
``(x^lam - 1) / lam``, or ``ln x`` for ``|lam| < 1e-8``.
|
|
553
|
+
|
|
554
|
+
Parameters
|
|
555
|
+
----------
|
|
556
|
+
values : float or array_like
|
|
557
|
+
Positive values.
|
|
558
|
+
lam : float
|
|
559
|
+
The exponent, in [-5, 5].
|
|
560
|
+
|
|
561
|
+
Returns
|
|
562
|
+
-------
|
|
563
|
+
float or numpy.ndarray
|
|
564
|
+
The transformed values, shaped like ``values``; NaN for a non-positive value or ``|lam| > 5``.
|
|
565
|
+
"""
|
|
566
|
+
box_cox = _stats().BoxCox
|
|
567
|
+
exponent = float(lam)
|
|
568
|
+
scalar = cached_overload("BoxCox.Transform(double, double)", lambda: bind(box_cox.Transform, 2))
|
|
569
|
+
return evaluate(values, lambda x: scalar(x, exponent), lambda v: box_cox.Transform(v, exponent))
|
|
570
|
+
|
|
571
|
+
|
|
572
|
+
def box_cox_inverse_transform(values: Any, lam: float) -> Any:
|
|
573
|
+
"""Return the inverse Box-Cox transformation through ``BoxCox.InverseTransform``.
|
|
574
|
+
|
|
575
|
+
Parameters
|
|
576
|
+
----------
|
|
577
|
+
values : float or array_like
|
|
578
|
+
Transformed values.
|
|
579
|
+
lam : float
|
|
580
|
+
The exponent, in [-5, 5].
|
|
581
|
+
|
|
582
|
+
Returns
|
|
583
|
+
-------
|
|
584
|
+
float or numpy.ndarray
|
|
585
|
+
The original-scale values, shaped like ``values``.
|
|
586
|
+
"""
|
|
587
|
+
box_cox = _stats().BoxCox
|
|
588
|
+
exponent = float(lam)
|
|
589
|
+
scalar = cached_overload("BoxCox.InverseTransform(double, double)", lambda: bind(box_cox.InverseTransform, 2))
|
|
590
|
+
return evaluate(values, lambda y: scalar(y, exponent), lambda v: box_cox.InverseTransform(v, exponent))
|
|
591
|
+
|
|
592
|
+
|
|
593
|
+
def box_cox_derivative(values: Any, lam: float) -> Any:
|
|
594
|
+
"""Return the derivative of the Box-Cox transformation through ``BoxCox.Derivative``.
|
|
595
|
+
|
|
596
|
+
``x^(lam - 1)``, or ``1 / x`` where the transformation is the logarithm. Numerics has no array
|
|
597
|
+
overload, so an array is evaluated element by element with the scalar member.
|
|
598
|
+
|
|
599
|
+
Parameters
|
|
600
|
+
----------
|
|
601
|
+
values : float or array_like
|
|
602
|
+
Positive values.
|
|
603
|
+
lam : float
|
|
604
|
+
The exponent, in [-5, 5].
|
|
605
|
+
|
|
606
|
+
Returns
|
|
607
|
+
-------
|
|
608
|
+
float or numpy.ndarray
|
|
609
|
+
The derivatives, shaped like ``values``; NaN for a non-positive value or ``|lam| > 5``.
|
|
610
|
+
"""
|
|
611
|
+
member, exponent = _stats().BoxCox.Derivative, float(lam)
|
|
612
|
+
return loop(values, lambda x: member(x, exponent))
|
|
613
|
+
|
|
614
|
+
|
|
615
|
+
def box_cox_fit_lambda(values: Any) -> tuple[bool, float]:
|
|
616
|
+
"""Fit the Box-Cox exponent by maximum likelihood through ``BoxCox.TryFitLambda``.
|
|
617
|
+
|
|
618
|
+
Parameters
|
|
619
|
+
----------
|
|
620
|
+
values : array_like
|
|
621
|
+
Positive values, not all equal.
|
|
622
|
+
|
|
623
|
+
Returns
|
|
624
|
+
-------
|
|
625
|
+
success : bool
|
|
626
|
+
Whether a finite exponent was found.
|
|
627
|
+
lam : float
|
|
628
|
+
The exponent in [-5, 5], or NaN when the sample cannot support a fit or the search fails.
|
|
629
|
+
"""
|
|
630
|
+
success, lam = _stats().BoxCox.TryFitLambda(to_net_doubles(values), 0.0)
|
|
631
|
+
return bool(success), float(lam)
|
|
632
|
+
|
|
633
|
+
|
|
634
|
+
def plotting_positions(n: int, kind: PlottingPosition | str | float = PlottingPosition.WEIBULL) -> np.ndarray:
|
|
635
|
+
"""Return plotting-position probabilities through ``PlottingPositions.Function``.
|
|
636
|
+
|
|
637
|
+
Parameters
|
|
638
|
+
----------
|
|
639
|
+
n : int
|
|
640
|
+
Sample size.
|
|
641
|
+
kind : PlottingPosition, str or float, optional
|
|
642
|
+
A named formula, or the plotting-position parameter α of (i − α)/(n + 1 − 2α).
|
|
643
|
+
|
|
644
|
+
Returns
|
|
645
|
+
-------
|
|
646
|
+
numpy.ndarray
|
|
647
|
+
The n ascending probabilities.
|
|
648
|
+
"""
|
|
649
|
+
pp = _stats().PlottingPositions
|
|
650
|
+
if isinstance(kind, (int, float)) and not isinstance(kind, bool):
|
|
651
|
+
return to_numpy_doubles(pp.Function(int(n), float(kind)))
|
|
652
|
+
return to_numpy_doubles(pp.Function(int(n), net_enum(pp.PlottingPostionType, kind)))
|
|
653
|
+
|
|
654
|
+
|
|
655
|
+
def weighted_plotting_positions(weights: Any, alpha: float | PlottingPosition | str) -> np.ndarray:
|
|
656
|
+
"""Return weighted plotting positions through ``PlottingPositions.Function(IList, ...)``.
|
|
657
|
+
|
|
658
|
+
``F_i = (c_i - alpha w_i) / (W + (1 - 2 alpha) W / n)`` with ``c_i`` the sequential cumulative
|
|
659
|
+
weight and ``W`` the total; unit weights give bitwise the positions of
|
|
660
|
+
:func:`plotting_positions`. A named formula selects ``Function(IList, PlottingPostionType)``:
|
|
661
|
+
the alpha formulas at :func:`plotting_position_alpha`, and Kaplan-Meier as ``c_i / W``.
|
|
662
|
+
|
|
663
|
+
Parameters
|
|
664
|
+
----------
|
|
665
|
+
weights : array_like
|
|
666
|
+
Non-negative weights of the observations in ascending order of their values.
|
|
667
|
+
alpha : float, PlottingPosition or str
|
|
668
|
+
The plotting-position parameter in [0, 0.5] (0 Weibull, 0.44 Gringorten, 0.5 Hazen; above
|
|
669
|
+
one half a small last weight would give a position above one), or a named formula.
|
|
670
|
+
|
|
671
|
+
Returns
|
|
672
|
+
-------
|
|
673
|
+
numpy.ndarray
|
|
674
|
+
The non-decreasing positions, one per weight.
|
|
675
|
+
"""
|
|
676
|
+
pp = _stats().PlottingPositions
|
|
677
|
+
if isinstance(alpha, (int, float)) and not isinstance(alpha, bool):
|
|
678
|
+
return to_numpy_doubles(pp.Function(to_net_doubles(weights), float(alpha)))
|
|
679
|
+
return to_numpy_doubles(pp.Function(to_net_doubles(weights), net_enum(pp.PlottingPostionType, alpha)))
|
|
680
|
+
|
|
681
|
+
|
|
682
|
+
def plotting_position_alpha(kind: PlottingPosition | str) -> float:
|
|
683
|
+
"""Return the alpha coefficient of a named plotting-position formula (``PlottingPositions.Alpha``).
|
|
684
|
+
|
|
685
|
+
Parameters
|
|
686
|
+
----------
|
|
687
|
+
kind : PlottingPosition or str
|
|
688
|
+
An alpha formula (Weibull, Median, Blom, Cunnane, Gringorten or Hazen).
|
|
689
|
+
|
|
690
|
+
Returns
|
|
691
|
+
-------
|
|
692
|
+
float
|
|
693
|
+
The coefficient of (i - alpha) / (n + 1 - 2 alpha).
|
|
694
|
+
"""
|
|
695
|
+
pp = _stats().PlottingPositions
|
|
696
|
+
return float(pp.Alpha(net_enum(pp.PlottingPostionType, kind)))
|
|
697
|
+
|
|
698
|
+
|
|
699
|
+
class RunningStatistics:
|
|
700
|
+
"""Streaming moments (``Numerics.Data.Statistics.RunningStatistics``).
|
|
701
|
+
|
|
702
|
+
Parameters
|
|
703
|
+
----------
|
|
704
|
+
values : array_like, optional
|
|
705
|
+
Initial values to push.
|
|
706
|
+
|
|
707
|
+
Attributes
|
|
708
|
+
----------
|
|
709
|
+
net : Numerics.Data.Statistics.RunningStatistics
|
|
710
|
+
The wrapped .NET object.
|
|
711
|
+
"""
|
|
712
|
+
|
|
713
|
+
def __init__(self, values: Any = None) -> None:
|
|
714
|
+
stats = _stats()
|
|
715
|
+
self.net = stats.RunningStatistics() if values is None else stats.RunningStatistics(to_net_doubles(values))
|
|
716
|
+
|
|
717
|
+
def push(self, values: Any) -> None:
|
|
718
|
+
"""Push one value or an array (``Push(double)`` / ``Push(IList<double>)``).
|
|
719
|
+
|
|
720
|
+
Parameters
|
|
721
|
+
----------
|
|
722
|
+
values : float or array_like
|
|
723
|
+
Values to add.
|
|
724
|
+
"""
|
|
725
|
+
array = np.asarray(values, dtype=np.float64)
|
|
726
|
+
if array.ndim == 0:
|
|
727
|
+
self.net.Push(float(array))
|
|
728
|
+
else:
|
|
729
|
+
self.net.Push(to_net_doubles(array.ravel()))
|
|
730
|
+
|
|
731
|
+
def clear(self) -> None:
|
|
732
|
+
"""Reset to the empty state in place (``RunningStatistics.Clear``).
|
|
733
|
+
|
|
734
|
+
Pushing the same values afterwards gives bitwise the statistics of a new accumulator.
|
|
735
|
+
"""
|
|
736
|
+
self.net.Clear()
|
|
737
|
+
|
|
738
|
+
@classmethod
|
|
739
|
+
def combine(cls, a: RunningStatistics, b: RunningStatistics) -> RunningStatistics:
|
|
740
|
+
"""Merge two accumulators (``RunningStatistics.Combine``).
|
|
741
|
+
|
|
742
|
+
Parameters
|
|
743
|
+
----------
|
|
744
|
+
a, b : RunningStatistics
|
|
745
|
+
Accumulators.
|
|
746
|
+
|
|
747
|
+
Returns
|
|
748
|
+
-------
|
|
749
|
+
RunningStatistics
|
|
750
|
+
The combined accumulator.
|
|
751
|
+
"""
|
|
752
|
+
out = cls.__new__(cls)
|
|
753
|
+
out.net = _stats().RunningStatistics.Combine(a.net, b.net)
|
|
754
|
+
return out
|
|
755
|
+
|
|
756
|
+
@property
|
|
757
|
+
def count(self) -> int:
|
|
758
|
+
"""Number of values pushed."""
|
|
759
|
+
return int(self.net.Count)
|
|
760
|
+
|
|
761
|
+
@property
|
|
762
|
+
def minimum(self) -> float:
|
|
763
|
+
"""Smallest value."""
|
|
764
|
+
return float(self.net.Minimum)
|
|
765
|
+
|
|
766
|
+
@property
|
|
767
|
+
def maximum(self) -> float:
|
|
768
|
+
"""Largest value."""
|
|
769
|
+
return float(self.net.Maximum)
|
|
770
|
+
|
|
771
|
+
@property
|
|
772
|
+
def mean(self) -> float:
|
|
773
|
+
"""Mean."""
|
|
774
|
+
return float(self.net.Mean)
|
|
775
|
+
|
|
776
|
+
@property
|
|
777
|
+
def variance(self) -> float:
|
|
778
|
+
"""Sample variance."""
|
|
779
|
+
return float(self.net.Variance)
|
|
780
|
+
|
|
781
|
+
@property
|
|
782
|
+
def standard_deviation(self) -> float:
|
|
783
|
+
"""Sample standard deviation."""
|
|
784
|
+
return float(self.net.StandardDeviation)
|
|
785
|
+
|
|
786
|
+
@property
|
|
787
|
+
def skewness(self) -> float:
|
|
788
|
+
"""Sample skewness."""
|
|
789
|
+
return float(self.net.Skewness)
|
|
790
|
+
|
|
791
|
+
@property
|
|
792
|
+
def kurtosis(self) -> float:
|
|
793
|
+
"""Sample kurtosis."""
|
|
794
|
+
return float(self.net.Kurtosis)
|
|
795
|
+
|
|
796
|
+
@property
|
|
797
|
+
def population_variance(self) -> float:
|
|
798
|
+
"""Population variance (divisor n); 0 for a single value."""
|
|
799
|
+
return float(self.net.PopulationVariance)
|
|
800
|
+
|
|
801
|
+
@property
|
|
802
|
+
def population_standard_deviation(self) -> float:
|
|
803
|
+
"""Population standard deviation (divisor n); 0 for a single value."""
|
|
804
|
+
return float(self.net.PopulationStandardDeviation)
|
|
805
|
+
|
|
806
|
+
@property
|
|
807
|
+
def coefficient_of_variation(self) -> float:
|
|
808
|
+
"""Coefficient of variation, the sample standard deviation over the mean."""
|
|
809
|
+
return float(self.net.CoefficientOfVariation)
|
|
810
|
+
|
|
811
|
+
@property
|
|
812
|
+
def population_skewness(self) -> float:
|
|
813
|
+
"""Population skewness (type 1, no bias correction)."""
|
|
814
|
+
return float(self.net.PopulationSkewness)
|
|
815
|
+
|
|
816
|
+
@property
|
|
817
|
+
def population_kurtosis(self) -> float:
|
|
818
|
+
"""Population kurtosis (type 1, no bias correction)."""
|
|
819
|
+
return float(self.net.PopulationKurtosis)
|
|
820
|
+
|
|
821
|
+
def clone(self) -> RunningStatistics:
|
|
822
|
+
"""Return an independent copy of the accumulator (``RunningStatistics.Clone``).
|
|
823
|
+
|
|
824
|
+
Returns
|
|
825
|
+
-------
|
|
826
|
+
RunningStatistics
|
|
827
|
+
A new accumulator with the same state.
|
|
828
|
+
"""
|
|
829
|
+
out = type(self).__new__(type(self))
|
|
830
|
+
out.net = self.net.Clone()
|
|
831
|
+
return out
|
|
832
|
+
|
|
833
|
+
|
|
834
|
+
def autocorrelation(data: Any, max_lag: int | None = None,
|
|
835
|
+
kind: AutocorrelationType | str = AutocorrelationType.CORRELATION,
|
|
836
|
+
centered: bool = True) -> tuple[np.ndarray, np.ndarray]:
|
|
837
|
+
"""Return a sample autocorrelation function through ``Autocorrelation.Function``.
|
|
838
|
+
|
|
839
|
+
``COVARIANCE`` is ``R(k) = n^-1 sum_{t=k}^{n-1} (x_t - xbar)(x_{t-k} - xbar)`` (divisor ``n`` at
|
|
840
|
+
every lag, the mean by ``Statistics.Mean``), ``CORRELATION`` is ``R(k) / R(0)`` and ``PARTIAL``
|
|
841
|
+
is the Durbin-Levinson partial autocorrelation from lag 1. With ``centered=False`` the mean is
|
|
842
|
+
taken as zero, for a process whose mean is known to be zero: ``R(k) = n^-1 sum x_t x_{t-k}`` and
|
|
843
|
+
the correlation is ``sum x_t x_{t-k} / sum x_t^2``.
|
|
844
|
+
|
|
845
|
+
Parameters
|
|
846
|
+
----------
|
|
847
|
+
data : array_like
|
|
848
|
+
The series, in time order: one-dimensional, finite, with at least two values.
|
|
849
|
+
max_lag : int, optional
|
|
850
|
+
The largest lag, an integer in [1, n - 1]; default Numerics' ``floor(min(10 log10(n), n - 1))``.
|
|
851
|
+
kind : AutocorrelationType or str, optional
|
|
852
|
+
``CORRELATION`` (default), ``COVARIANCE`` or ``PARTIAL``.
|
|
853
|
+
centered : bool, optional
|
|
854
|
+
Remove the sample mean (default True); False evaluates about zero.
|
|
855
|
+
|
|
856
|
+
Returns
|
|
857
|
+
-------
|
|
858
|
+
lags : numpy.ndarray
|
|
859
|
+
The lags (``0..max_lag``; ``1..max_lag`` for ``PARTIAL``), as integers.
|
|
860
|
+
values : numpy.ndarray
|
|
861
|
+
The function at those lags.
|
|
862
|
+
|
|
863
|
+
Raises
|
|
864
|
+
------
|
|
865
|
+
ValueError
|
|
866
|
+
If ``data`` is not one-dimensional, holds a non-finite value or has fewer than two values;
|
|
867
|
+
if ``max_lag`` is not an integer in [1, n - 1]; or if Numerics returns no function (a
|
|
868
|
+
zero-variance series for ``CORRELATION``). Each message names the argument at fault.
|
|
869
|
+
"""
|
|
870
|
+
series = np.asarray(data, dtype=np.float64)
|
|
871
|
+
if series.ndim != 1:
|
|
872
|
+
raise ValueError(f"data must be one-dimensional; got shape {series.shape}.")
|
|
873
|
+
if series.size < 2:
|
|
874
|
+
raise ValueError(f"data needs at least two values; got {series.size}.")
|
|
875
|
+
if not np.all(np.isfinite(series)):
|
|
876
|
+
raise ValueError("data must be finite; it holds NaN or infinite values.")
|
|
877
|
+
if max_lag is None:
|
|
878
|
+
lag = -1
|
|
879
|
+
else:
|
|
880
|
+
if isinstance(max_lag, (bool, np.bool_)) or not isinstance(max_lag, (int, np.integer)):
|
|
881
|
+
raise ValueError(f"max_lag must be an integer; got {max_lag!r}.")
|
|
882
|
+
lag = int(max_lag)
|
|
883
|
+
if not 1 <= lag <= series.size - 1:
|
|
884
|
+
raise ValueError(f"max_lag must lie in [1, {series.size - 1}] for {series.size} values; got {lag}.")
|
|
885
|
+
stats = _stats()
|
|
886
|
+
net_kind = net_enum(stats.Autocorrelation.Type, kind)
|
|
887
|
+
if centered:
|
|
888
|
+
table = stats.Autocorrelation.Function(to_net_doubles(series), lag, net_kind)
|
|
889
|
+
else:
|
|
890
|
+
table = stats.Autocorrelation.Function(to_net_doubles(series), lag, net_kind, False)
|
|
891
|
+
if table is None:
|
|
892
|
+
raise ValueError("Autocorrelation.Function returned no function: the series needs at least two values, "
|
|
893
|
+
"a maximum lag of at least 1 and, for the correlation, a nonzero variance.")
|
|
894
|
+
result = to_numpy_matrix(table)
|
|
895
|
+
return result[:, 0].astype(np.int64), np.ascontiguousarray(result[:, 1])
|
|
896
|
+
|
|
897
|
+
|
|
898
|
+
def _one(name: str, data: Any) -> float:
|
|
899
|
+
"""Call a one-sample ``Statistics`` member through its bound ``IList<double>`` overload."""
|
|
900
|
+
return float(_statistics_member(name, "list")(to_net_doubles(data)))
|
|
901
|
+
|
|
902
|
+
|
|
903
|
+
def minimum(data: Any) -> float:
|
|
904
|
+
"""Return the smallest value through ``Statistics.Minimum``.
|
|
905
|
+
|
|
906
|
+
Parameters
|
|
907
|
+
----------
|
|
908
|
+
data : array_like
|
|
909
|
+
Values, in any order.
|
|
910
|
+
|
|
911
|
+
Returns
|
|
912
|
+
-------
|
|
913
|
+
float
|
|
914
|
+
The minimum; NaN for an empty sample or any NaN.
|
|
915
|
+
"""
|
|
916
|
+
return _one("Minimum", data)
|
|
917
|
+
|
|
918
|
+
|
|
919
|
+
def maximum(data: Any) -> float:
|
|
920
|
+
"""Return the largest value through ``Statistics.Maximum``.
|
|
921
|
+
|
|
922
|
+
Parameters
|
|
923
|
+
----------
|
|
924
|
+
data : array_like
|
|
925
|
+
Values, in any order.
|
|
926
|
+
|
|
927
|
+
Returns
|
|
928
|
+
-------
|
|
929
|
+
float
|
|
930
|
+
The maximum; NaN for an empty sample or any NaN.
|
|
931
|
+
"""
|
|
932
|
+
return _one("Maximum", data)
|
|
933
|
+
|
|
934
|
+
|
|
935
|
+
def sum(data: Any) -> float:
|
|
936
|
+
"""Return the sequential sum through ``Statistics.Sum``.
|
|
937
|
+
|
|
938
|
+
Parameters
|
|
939
|
+
----------
|
|
940
|
+
data : array_like
|
|
941
|
+
Values, in any order.
|
|
942
|
+
|
|
943
|
+
Returns
|
|
944
|
+
-------
|
|
945
|
+
float
|
|
946
|
+
The sum in index order; NaN for an empty sample or any NaN.
|
|
947
|
+
"""
|
|
948
|
+
return _one("Sum", data)
|
|
949
|
+
|
|
950
|
+
|
|
951
|
+
def parallel_mean(data: Any) -> float:
|
|
952
|
+
"""Return the mean through ``Statistics.ParallelMean`` (deterministic chunked reduction).
|
|
953
|
+
|
|
954
|
+
The chunk boundaries depend only on the sample length, so the result is reproducible across
|
|
955
|
+
runs and machines; it can differ from :func:`mean` in the last bits.
|
|
956
|
+
|
|
957
|
+
Parameters
|
|
958
|
+
----------
|
|
959
|
+
data : array_like
|
|
960
|
+
Values, in any order.
|
|
961
|
+
|
|
962
|
+
Returns
|
|
963
|
+
-------
|
|
964
|
+
float
|
|
965
|
+
The mean; NaN for an empty sample or any NaN.
|
|
966
|
+
"""
|
|
967
|
+
return _one("ParallelMean", data)
|
|
968
|
+
|
|
969
|
+
|
|
970
|
+
def geometric_mean(data: Any) -> float:
|
|
971
|
+
"""Return the geometric mean through ``Statistics.GeometricMean``.
|
|
972
|
+
|
|
973
|
+
Parameters
|
|
974
|
+
----------
|
|
975
|
+
data : array_like
|
|
976
|
+
Positive values.
|
|
977
|
+
|
|
978
|
+
Returns
|
|
979
|
+
-------
|
|
980
|
+
float
|
|
981
|
+
The geometric mean; NaN for an empty sample or any NaN.
|
|
982
|
+
"""
|
|
983
|
+
return _one("GeometricMean", data)
|
|
984
|
+
|
|
985
|
+
|
|
986
|
+
def harmonic_mean(data: Any) -> float:
|
|
987
|
+
"""Return the harmonic mean through ``Statistics.HarmonicMean``.
|
|
988
|
+
|
|
989
|
+
Parameters
|
|
990
|
+
----------
|
|
991
|
+
data : array_like
|
|
992
|
+
Nonzero values.
|
|
993
|
+
|
|
994
|
+
Returns
|
|
995
|
+
-------
|
|
996
|
+
float
|
|
997
|
+
The harmonic mean; NaN for an empty sample or any NaN.
|
|
998
|
+
"""
|
|
999
|
+
return _one("HarmonicMean", data)
|
|
1000
|
+
|
|
1001
|
+
|
|
1002
|
+
def population_variance(data: Any) -> float:
|
|
1003
|
+
"""Return the population variance (divisor n) through ``Statistics.PopulationVariance``.
|
|
1004
|
+
|
|
1005
|
+
Parameters
|
|
1006
|
+
----------
|
|
1007
|
+
data : array_like
|
|
1008
|
+
Values.
|
|
1009
|
+
|
|
1010
|
+
Returns
|
|
1011
|
+
-------
|
|
1012
|
+
float
|
|
1013
|
+
The variance with divisor n; NaN for an empty sample or any NaN.
|
|
1014
|
+
"""
|
|
1015
|
+
return _one("PopulationVariance", data)
|
|
1016
|
+
|
|
1017
|
+
|
|
1018
|
+
def population_standard_deviation(data: Any) -> float:
|
|
1019
|
+
"""Return the population standard deviation (divisor n) through ``Statistics.PopulationStandardDeviation``.
|
|
1020
|
+
|
|
1021
|
+
Parameters
|
|
1022
|
+
----------
|
|
1023
|
+
data : array_like
|
|
1024
|
+
Values.
|
|
1025
|
+
|
|
1026
|
+
Returns
|
|
1027
|
+
-------
|
|
1028
|
+
float
|
|
1029
|
+
The standard deviation with divisor n; NaN for an empty sample or any NaN.
|
|
1030
|
+
"""
|
|
1031
|
+
return _one("PopulationStandardDeviation", data)
|
|
1032
|
+
|
|
1033
|
+
|
|
1034
|
+
def _pair(result: Any) -> tuple[float, float]:
|
|
1035
|
+
"""Return a .NET ``ValueTuple<double, double>`` as a Python pair."""
|
|
1036
|
+
return float(result.Item1), float(result.Item2)
|
|
1037
|
+
|
|
1038
|
+
|
|
1039
|
+
def mean_variance(data: Any) -> tuple[float, float]:
|
|
1040
|
+
"""Return the mean and sample variance in one pass through ``Statistics.MeanVariance``.
|
|
1041
|
+
|
|
1042
|
+
Parameters
|
|
1043
|
+
----------
|
|
1044
|
+
data : array_like
|
|
1045
|
+
Values.
|
|
1046
|
+
|
|
1047
|
+
Returns
|
|
1048
|
+
-------
|
|
1049
|
+
tuple of float
|
|
1050
|
+
The mean and the sample variance (divisor n - 1).
|
|
1051
|
+
"""
|
|
1052
|
+
return _pair(_stats().Statistics.MeanVariance(to_net_doubles(data)))
|
|
1053
|
+
|
|
1054
|
+
|
|
1055
|
+
def mean_standard_deviation(data: Any) -> tuple[float, float]:
|
|
1056
|
+
"""Return the mean and sample standard deviation through ``Statistics.MeanStandardDeviation``.
|
|
1057
|
+
|
|
1058
|
+
Parameters
|
|
1059
|
+
----------
|
|
1060
|
+
data : array_like
|
|
1061
|
+
Values.
|
|
1062
|
+
|
|
1063
|
+
Returns
|
|
1064
|
+
-------
|
|
1065
|
+
tuple of float
|
|
1066
|
+
The mean and the sample standard deviation (divisor n - 1).
|
|
1067
|
+
"""
|
|
1068
|
+
return _pair(_stats().Statistics.MeanStandardDeviation(to_net_doubles(data)))
|
|
1069
|
+
|
|
1070
|
+
|
|
1071
|
+
def coefficient_of_variation(data: Any) -> float:
|
|
1072
|
+
"""Return the coefficient of variation through ``Statistics.CoefficientOfVariation``.
|
|
1073
|
+
|
|
1074
|
+
Parameters
|
|
1075
|
+
----------
|
|
1076
|
+
data : array_like
|
|
1077
|
+
Values.
|
|
1078
|
+
|
|
1079
|
+
Returns
|
|
1080
|
+
-------
|
|
1081
|
+
float
|
|
1082
|
+
The sample standard deviation over the mean.
|
|
1083
|
+
"""
|
|
1084
|
+
return _one("CoefficientOfVariation", data)
|
|
1085
|
+
|
|
1086
|
+
|
|
1087
|
+
def _weighted_moment(name: str, data: Any, weights: Any, weight_type: WeightType | str) -> float:
|
|
1088
|
+
"""Call ``Statistics.Skewness`` or ``Kurtosis``, unweighted or with weights."""
|
|
1089
|
+
if weights is None:
|
|
1090
|
+
return _one(name, data)
|
|
1091
|
+
member = _statistics_member(name, "list", "list", "weight")
|
|
1092
|
+
return float(member(to_net_doubles(data), to_net_doubles(weights), net_enum(_stats().WeightType, weight_type)))
|
|
1093
|
+
|
|
1094
|
+
|
|
1095
|
+
def skewness(data: Any, weights: Any = None, weight_type: WeightType | str = WeightType.FREQUENCY) -> float:
|
|
1096
|
+
"""Return the bias-corrected sample skewness through ``Statistics.Skewness``.
|
|
1097
|
+
|
|
1098
|
+
The adjusted Fisher-Pearson coefficient ``G1``, as ``scipy.stats.skew(bias=False)``. With
|
|
1099
|
+
weights the correction uses the effective sample size of ``weight_type``.
|
|
1100
|
+
|
|
1101
|
+
Parameters
|
|
1102
|
+
----------
|
|
1103
|
+
data : array_like
|
|
1104
|
+
Values.
|
|
1105
|
+
weights : array_like, optional
|
|
1106
|
+
Non-negative, finite weights, one per value.
|
|
1107
|
+
weight_type : WeightType or str, optional
|
|
1108
|
+
Weight interpretation; default frequency.
|
|
1109
|
+
|
|
1110
|
+
Returns
|
|
1111
|
+
-------
|
|
1112
|
+
float
|
|
1113
|
+
The skewness; NaN for an empty sample, any NaN, or an effective sample size of two or less.
|
|
1114
|
+
"""
|
|
1115
|
+
return _weighted_moment("Skewness", data, weights, weight_type)
|
|
1116
|
+
|
|
1117
|
+
|
|
1118
|
+
def kurtosis(data: Any, weights: Any = None, weight_type: WeightType | str = WeightType.FREQUENCY) -> float:
|
|
1119
|
+
"""Return the bias-corrected sample excess kurtosis through ``Statistics.Kurtosis``.
|
|
1120
|
+
|
|
1121
|
+
The small-sample estimator ``G2``, as ``scipy.stats.kurtosis(bias=False)``. With weights the
|
|
1122
|
+
correction uses the effective sample size of ``weight_type``.
|
|
1123
|
+
|
|
1124
|
+
Parameters
|
|
1125
|
+
----------
|
|
1126
|
+
data : array_like
|
|
1127
|
+
Values.
|
|
1128
|
+
weights : array_like, optional
|
|
1129
|
+
Non-negative, finite weights, one per value.
|
|
1130
|
+
weight_type : WeightType or str, optional
|
|
1131
|
+
Weight interpretation; default frequency.
|
|
1132
|
+
|
|
1133
|
+
Returns
|
|
1134
|
+
-------
|
|
1135
|
+
float
|
|
1136
|
+
The excess kurtosis; NaN for an empty sample, any NaN, or an effective sample size of three
|
|
1137
|
+
or less.
|
|
1138
|
+
"""
|
|
1139
|
+
return _weighted_moment("Kurtosis", data, weights, weight_type)
|
|
1140
|
+
|
|
1141
|
+
|
|
1142
|
+
def covariance(data1: Any, data2: Any) -> float:
|
|
1143
|
+
"""Return the sample covariance (divisor n - 1) through ``Statistics.Covariance``.
|
|
1144
|
+
|
|
1145
|
+
Parameters
|
|
1146
|
+
----------
|
|
1147
|
+
data1, data2 : array_like
|
|
1148
|
+
Samples of the same length.
|
|
1149
|
+
|
|
1150
|
+
Returns
|
|
1151
|
+
-------
|
|
1152
|
+
float
|
|
1153
|
+
The covariance; NaN for fewer than two pairs or any NaN.
|
|
1154
|
+
"""
|
|
1155
|
+
return float(_stats().Statistics.Covariance(to_net_doubles(data1), to_net_doubles(data2)))
|
|
1156
|
+
|
|
1157
|
+
|
|
1158
|
+
def population_covariance(data1: Any, data2: Any) -> float:
|
|
1159
|
+
"""Return the population covariance (divisor n) through ``Statistics.PopulationCovariance``.
|
|
1160
|
+
|
|
1161
|
+
Parameters
|
|
1162
|
+
----------
|
|
1163
|
+
data1, data2 : array_like
|
|
1164
|
+
Samples of the same length.
|
|
1165
|
+
|
|
1166
|
+
Returns
|
|
1167
|
+
-------
|
|
1168
|
+
float
|
|
1169
|
+
The covariance; NaN for an empty sample or any NaN.
|
|
1170
|
+
"""
|
|
1171
|
+
return float(_stats().Statistics.PopulationCovariance(to_net_doubles(data1), to_net_doubles(data2)))
|
|
1172
|
+
|
|
1173
|
+
|
|
1174
|
+
def product_moments(data: Any) -> np.ndarray:
|
|
1175
|
+
"""Return the first four product moments through ``Statistics.ProductMoments``.
|
|
1176
|
+
|
|
1177
|
+
Parameters
|
|
1178
|
+
----------
|
|
1179
|
+
data : array_like
|
|
1180
|
+
Values.
|
|
1181
|
+
|
|
1182
|
+
Returns
|
|
1183
|
+
-------
|
|
1184
|
+
numpy.ndarray
|
|
1185
|
+
``[mean, standard deviation, skewness, excess kurtosis]`` with the bias-corrected skewness
|
|
1186
|
+
and kurtosis; four NaN values for fewer than four values or any NaN.
|
|
1187
|
+
"""
|
|
1188
|
+
return to_numpy_doubles(_stats().Statistics.ProductMoments(to_net_doubles(data)))
|
|
1189
|
+
|
|
1190
|
+
|
|
1191
|
+
def five_number_summary(data: Any) -> np.ndarray:
|
|
1192
|
+
"""Return the five-number summary through ``Statistics.FiveNumberSummary``.
|
|
1193
|
+
|
|
1194
|
+
Parameters
|
|
1195
|
+
----------
|
|
1196
|
+
data : array_like
|
|
1197
|
+
Values, in any order.
|
|
1198
|
+
|
|
1199
|
+
Returns
|
|
1200
|
+
-------
|
|
1201
|
+
numpy.ndarray
|
|
1202
|
+
``[min, 25th, 50th, 75th percentile, max]``, the percentiles Type 7.
|
|
1203
|
+
"""
|
|
1204
|
+
return to_numpy_doubles(_stats().Statistics.FiveNumberSummary(to_net_doubles(data)))
|
|
1205
|
+
|
|
1206
|
+
|
|
1207
|
+
def seven_number_summary(data: Any) -> np.ndarray:
|
|
1208
|
+
"""Return the seven-number summary through ``Statistics.SevenNumberSummary``.
|
|
1209
|
+
|
|
1210
|
+
Parameters
|
|
1211
|
+
----------
|
|
1212
|
+
data : array_like
|
|
1213
|
+
Values, in any order.
|
|
1214
|
+
|
|
1215
|
+
Returns
|
|
1216
|
+
-------
|
|
1217
|
+
numpy.ndarray
|
|
1218
|
+
``[min, 5th, 25th, 50th, 75th, 95th percentile, max]``, the percentiles Type 7.
|
|
1219
|
+
"""
|
|
1220
|
+
return to_numpy_doubles(_stats().Statistics.SevenNumberSummary(to_net_doubles(data)))
|
|
1221
|
+
|
|
1222
|
+
|
|
1223
|
+
def jackknife_standard_error(data: Any, statistic: Any) -> float:
|
|
1224
|
+
"""Return the jackknife standard error of a statistic through ``Statistics.JackKnifeStandardError``.
|
|
1225
|
+
|
|
1226
|
+
Numerics evaluates the leave-one-out samples in parallel. A Python callable serializes on the
|
|
1227
|
+
GIL; pass C# source (compiled with :func:`pynumerics.callbacks.compile_csharp`) for a
|
|
1228
|
+
statistic that runs without crossing into Python.
|
|
1229
|
+
|
|
1230
|
+
Parameters
|
|
1231
|
+
----------
|
|
1232
|
+
data : array_like
|
|
1233
|
+
Values.
|
|
1234
|
+
statistic : callable, str or System.Delegate
|
|
1235
|
+
The statistic of one sample, a ``Func<IList<double>, double>``: a Python callable taking a
|
|
1236
|
+
NumPy array, C# source, or a .NET delegate.
|
|
1237
|
+
|
|
1238
|
+
Returns
|
|
1239
|
+
-------
|
|
1240
|
+
float
|
|
1241
|
+
The standard error; 0 for a single value.
|
|
1242
|
+
"""
|
|
1243
|
+
fn = callbacks.to_delegate(statistic, "Func<IList<double>,double>")
|
|
1244
|
+
return float(_stats().Statistics.JackKnifeStandardError(to_net_doubles(data), fn))
|
|
1245
|
+
|
|
1246
|
+
|
|
1247
|
+
def jackknife_sample(data: Any, statistic: Any) -> np.ndarray | None:
|
|
1248
|
+
"""Return the statistic of every leave-one-out sample through ``Statistics.JackKnifeSample``.
|
|
1249
|
+
|
|
1250
|
+
Parameters
|
|
1251
|
+
----------
|
|
1252
|
+
data : array_like
|
|
1253
|
+
Values.
|
|
1254
|
+
statistic : callable, str or System.Delegate
|
|
1255
|
+
The statistic of one sample, as for :func:`jackknife_standard_error`.
|
|
1256
|
+
|
|
1257
|
+
Returns
|
|
1258
|
+
-------
|
|
1259
|
+
numpy.ndarray or None
|
|
1260
|
+
One value per left-out index, or None for an empty sample.
|
|
1261
|
+
"""
|
|
1262
|
+
fn = callbacks.to_delegate(statistic, "Func<IList<double>,double>")
|
|
1263
|
+
result = _stats().Statistics.JackKnifeSample(to_net_doubles(data), fn)
|
|
1264
|
+
return None if result is None else to_numpy_doubles(result)
|
|
1265
|
+
|
|
1266
|
+
|
|
1267
|
+
def entropy(data: Any, pdf: Any) -> float:
|
|
1268
|
+
"""Return ``-sum p log p`` over the density values at the data through ``Statistics.Entropy``.
|
|
1269
|
+
|
|
1270
|
+
Values where the density is zero or negative are skipped.
|
|
1271
|
+
|
|
1272
|
+
Parameters
|
|
1273
|
+
----------
|
|
1274
|
+
data : array_like
|
|
1275
|
+
Points at which the density is evaluated.
|
|
1276
|
+
pdf : callable, str or System.Delegate
|
|
1277
|
+
The density, a ``Func<double, double>``: a Python callable (for example a distribution's
|
|
1278
|
+
``pdf``), C# source, or a .NET delegate.
|
|
1279
|
+
|
|
1280
|
+
Returns
|
|
1281
|
+
-------
|
|
1282
|
+
float
|
|
1283
|
+
The entropy sum.
|
|
1284
|
+
"""
|
|
1285
|
+
return float(_stats().Statistics.Entropy(to_net_doubles(data), callbacks.scalar_function(pdf)))
|
|
1286
|
+
|
|
1287
|
+
|
|
1288
|
+
def effective_sample_size(weights: Any) -> float:
|
|
1289
|
+
"""Return the Kish effective sample size ``(sum w)^2 / sum w^2`` through ``Statistics.EffectiveSampleSize``.
|
|
1290
|
+
|
|
1291
|
+
The total and the sum of squares are accumulated sequentially in index order, the order the
|
|
1292
|
+
reliability-weighted statistics use. This is the effective size of a weighted sample, not of
|
|
1293
|
+
a correlated series: for the effective size of MCMC draws use
|
|
1294
|
+
:func:`pynumerics.mcmc.effective_sample_size`.
|
|
1295
|
+
|
|
1296
|
+
Parameters
|
|
1297
|
+
----------
|
|
1298
|
+
weights : array_like
|
|
1299
|
+
Non-negative, finite weights.
|
|
1300
|
+
|
|
1301
|
+
Returns
|
|
1302
|
+
-------
|
|
1303
|
+
float
|
|
1304
|
+
The effective sample size, between one and the number of positive weights; NaN for an
|
|
1305
|
+
empty input.
|
|
1306
|
+
|
|
1307
|
+
Raises
|
|
1308
|
+
------
|
|
1309
|
+
ValueError
|
|
1310
|
+
If a weight is negative or not finite.
|
|
1311
|
+
"""
|
|
1312
|
+
return float(_stats().Statistics.EffectiveSampleSize(to_net_doubles(weights)))
|
|
1313
|
+
|
|
1314
|
+
|
|
1315
|
+
def box_cox_log_likelihood(values: Any, lam: float) -> float:
|
|
1316
|
+
"""Return the Box-Cox profile log-likelihood through ``BoxCox.LogLikelihood``.
|
|
1317
|
+
|
|
1318
|
+
Parameters
|
|
1319
|
+
----------
|
|
1320
|
+
values : array_like
|
|
1321
|
+
Positive values.
|
|
1322
|
+
lam : float
|
|
1323
|
+
The exponent, in [-5, 5].
|
|
1324
|
+
|
|
1325
|
+
Returns
|
|
1326
|
+
-------
|
|
1327
|
+
float
|
|
1328
|
+
The normal log-likelihood of the transformed values plus the log-Jacobian.
|
|
1329
|
+
"""
|
|
1330
|
+
return float(_stats().BoxCox.LogLikelihood(to_net_doubles(values), float(lam)))
|
|
1331
|
+
|
|
1332
|
+
|
|
1333
|
+
def box_cox_log_jacobian(values: Any, lam: float) -> float:
|
|
1334
|
+
"""Return the log-Jacobian ``(lam - 1) sum ln x`` of the Box-Cox transformation (``BoxCox.LogJacobian``).
|
|
1335
|
+
|
|
1336
|
+
Parameters
|
|
1337
|
+
----------
|
|
1338
|
+
values : array_like
|
|
1339
|
+
Positive values.
|
|
1340
|
+
lam : float
|
|
1341
|
+
The exponent, in [-5, 5].
|
|
1342
|
+
|
|
1343
|
+
Returns
|
|
1344
|
+
-------
|
|
1345
|
+
float
|
|
1346
|
+
The log-Jacobian.
|
|
1347
|
+
"""
|
|
1348
|
+
return float(_stats().BoxCox.LogJacobian(to_net_doubles(values), float(lam)))
|
|
1349
|
+
|
|
1350
|
+
|
|
1351
|
+
def yeo_johnson_transform(values: Any, lam: float) -> Any:
|
|
1352
|
+
"""Return the Yeo-Johnson transformation through ``YeoJohnson.Transform``.
|
|
1353
|
+
|
|
1354
|
+
Parameters
|
|
1355
|
+
----------
|
|
1356
|
+
values : float or array_like
|
|
1357
|
+
Values of any sign.
|
|
1358
|
+
lam : float
|
|
1359
|
+
The exponent, in [-5, 5].
|
|
1360
|
+
|
|
1361
|
+
Returns
|
|
1362
|
+
-------
|
|
1363
|
+
float or numpy.ndarray
|
|
1364
|
+
The transformed values, shaped like ``values``.
|
|
1365
|
+
"""
|
|
1366
|
+
yeo_johnson = _stats().YeoJohnson
|
|
1367
|
+
exponent = float(lam)
|
|
1368
|
+
scalar = cached_overload("YeoJohnson.Transform(double, double)", lambda: bind(yeo_johnson.Transform, 2))
|
|
1369
|
+
return evaluate(values, lambda x: scalar(x, exponent), lambda v: yeo_johnson.Transform(v, exponent))
|
|
1370
|
+
|
|
1371
|
+
|
|
1372
|
+
def yeo_johnson_inverse_transform(values: Any, lam: float) -> Any:
|
|
1373
|
+
"""Return the inverse Yeo-Johnson transformation through ``YeoJohnson.InverseTransform``.
|
|
1374
|
+
|
|
1375
|
+
Parameters
|
|
1376
|
+
----------
|
|
1377
|
+
values : float or array_like
|
|
1378
|
+
Transformed values.
|
|
1379
|
+
lam : float
|
|
1380
|
+
The exponent, in [-5, 5].
|
|
1381
|
+
|
|
1382
|
+
Returns
|
|
1383
|
+
-------
|
|
1384
|
+
float or numpy.ndarray
|
|
1385
|
+
The original-scale values, shaped like ``values``.
|
|
1386
|
+
"""
|
|
1387
|
+
yeo_johnson = _stats().YeoJohnson
|
|
1388
|
+
exponent = float(lam)
|
|
1389
|
+
scalar = cached_overload("YeoJohnson.InverseTransform(double, double)",
|
|
1390
|
+
lambda: bind(yeo_johnson.InverseTransform, 2))
|
|
1391
|
+
return evaluate(values, lambda y: scalar(y, exponent), lambda v: yeo_johnson.InverseTransform(v, exponent))
|
|
1392
|
+
|
|
1393
|
+
|
|
1394
|
+
def yeo_johnson_derivative(values: Any, lam: float) -> Any:
|
|
1395
|
+
"""Return the derivative of the Yeo-Johnson transformation through ``YeoJohnson.Derivative``.
|
|
1396
|
+
|
|
1397
|
+
Numerics has no array overload, so an array is evaluated element by element.
|
|
1398
|
+
|
|
1399
|
+
Parameters
|
|
1400
|
+
----------
|
|
1401
|
+
values : float or array_like
|
|
1402
|
+
Values of any sign.
|
|
1403
|
+
lam : float
|
|
1404
|
+
The exponent, in [-5, 5].
|
|
1405
|
+
|
|
1406
|
+
Returns
|
|
1407
|
+
-------
|
|
1408
|
+
float or numpy.ndarray
|
|
1409
|
+
The derivatives, shaped like ``values``.
|
|
1410
|
+
"""
|
|
1411
|
+
member, exponent = _stats().YeoJohnson.Derivative, float(lam)
|
|
1412
|
+
return loop(values, lambda x: member(x, exponent))
|
|
1413
|
+
|
|
1414
|
+
|
|
1415
|
+
def yeo_johnson_fit_lambda(values: Any) -> float:
|
|
1416
|
+
"""Fit the Yeo-Johnson exponent by maximum likelihood through ``YeoJohnson.FitLambda``.
|
|
1417
|
+
|
|
1418
|
+
Parameters
|
|
1419
|
+
----------
|
|
1420
|
+
values : array_like
|
|
1421
|
+
At least two values.
|
|
1422
|
+
|
|
1423
|
+
Returns
|
|
1424
|
+
-------
|
|
1425
|
+
float
|
|
1426
|
+
The exponent in [-5, 5], or NaN when the search fails.
|
|
1427
|
+
|
|
1428
|
+
Raises
|
|
1429
|
+
------
|
|
1430
|
+
ValueError
|
|
1431
|
+
If fewer than two values are given.
|
|
1432
|
+
"""
|
|
1433
|
+
member = cached_overload("YeoJohnson.FitLambda(IList)", lambda: bind_list(_stats().YeoJohnson.FitLambda))
|
|
1434
|
+
return float(member(to_net_doubles(values)))
|
|
1435
|
+
|
|
1436
|
+
|
|
1437
|
+
def yeo_johnson_log_likelihood(values: Any, lam: float) -> float:
|
|
1438
|
+
"""Return the Yeo-Johnson profile log-likelihood through ``YeoJohnson.LogLikelihood``.
|
|
1439
|
+
|
|
1440
|
+
Parameters
|
|
1441
|
+
----------
|
|
1442
|
+
values : array_like
|
|
1443
|
+
Values of any sign.
|
|
1444
|
+
lam : float
|
|
1445
|
+
The exponent, in [-5, 5].
|
|
1446
|
+
|
|
1447
|
+
Returns
|
|
1448
|
+
-------
|
|
1449
|
+
float
|
|
1450
|
+
The normal log-likelihood of the transformed values plus the log-Jacobian.
|
|
1451
|
+
"""
|
|
1452
|
+
return float(_stats().YeoJohnson.LogLikelihood(to_net_doubles(values), float(lam)))
|
|
1453
|
+
|
|
1454
|
+
|
|
1455
|
+
def yeo_johnson_log_jacobian(values: Any, lam: float) -> float:
|
|
1456
|
+
"""Return the log-Jacobian of the Yeo-Johnson transformation through ``YeoJohnson.LogJacobian``.
|
|
1457
|
+
|
|
1458
|
+
Parameters
|
|
1459
|
+
----------
|
|
1460
|
+
values : array_like
|
|
1461
|
+
Values of any sign.
|
|
1462
|
+
lam : float
|
|
1463
|
+
The exponent, in [-5, 5].
|
|
1464
|
+
|
|
1465
|
+
Returns
|
|
1466
|
+
-------
|
|
1467
|
+
float
|
|
1468
|
+
``(lam - 1) sum sign(x) ln(1 + |x|)``.
|
|
1469
|
+
"""
|
|
1470
|
+
return float(_stats().YeoJohnson.LogJacobian(to_net_doubles(values), float(lam)))
|
|
1471
|
+
|
|
1472
|
+
|
|
1473
|
+
def autocorrelation_confidence_interval(sample_size: int, interval: float = 0.95) -> tuple[float, float]:
|
|
1474
|
+
"""Return the white-noise band of the sample autocorrelation (``Autocorrelation.CorrelationConfidenceInterval``).
|
|
1475
|
+
|
|
1476
|
+
Parameters
|
|
1477
|
+
----------
|
|
1478
|
+
sample_size : int
|
|
1479
|
+
The series length.
|
|
1480
|
+
interval : float, optional
|
|
1481
|
+
The two-sided level; default 0.95.
|
|
1482
|
+
|
|
1483
|
+
Returns
|
|
1484
|
+
-------
|
|
1485
|
+
tuple of float
|
|
1486
|
+
The lower and upper bounds ``-+ z / sqrt(n)``.
|
|
1487
|
+
"""
|
|
1488
|
+
bounds = _stats().Autocorrelation.CorrelationConfidenceInterval(int(sample_size), float(interval))
|
|
1489
|
+
return float(bounds[0]), float(bounds[1])
|
|
1490
|
+
|
|
1491
|
+
|
|
1492
|
+
def _sorted(values: Any, data_is_sorted: bool) -> Any:
|
|
1493
|
+
"""Return the values as a ``System.Double[]``, sorted ascending unless already sorted."""
|
|
1494
|
+
array = np.asarray(values, dtype=np.float64)
|
|
1495
|
+
return to_net_doubles(array if data_is_sorted else np.sort(array))
|
|
1496
|
+
|
|
1497
|
+
|
|
1498
|
+
def first_order_sobol(x: Any, y: Any, bins: int = 20) -> float:
|
|
1499
|
+
"""Estimate the first-order Sobol index of an input from given data (``GlobalSensitivity.FirstOrderSobol``).
|
|
1500
|
+
|
|
1501
|
+
The variance of the conditional output mean over equal-frequency input bins, divided by the
|
|
1502
|
+
output variance (Plischke, Borgonovo and Smith, 2013).
|
|
1503
|
+
|
|
1504
|
+
Parameters
|
|
1505
|
+
----------
|
|
1506
|
+
x : array_like
|
|
1507
|
+
The input sample.
|
|
1508
|
+
y : array_like
|
|
1509
|
+
The output sample, aligned with ``x``.
|
|
1510
|
+
bins : int, optional
|
|
1511
|
+
The number of equal-frequency input bins; default 20.
|
|
1512
|
+
|
|
1513
|
+
Returns
|
|
1514
|
+
-------
|
|
1515
|
+
float
|
|
1516
|
+
The index, clamped to [0, 1]; 0 for a constant output.
|
|
1517
|
+
|
|
1518
|
+
Raises
|
|
1519
|
+
------
|
|
1520
|
+
ValueError
|
|
1521
|
+
If the samples differ in length, are shorter than ``bins``, ``bins`` is below two, or a
|
|
1522
|
+
value is not finite.
|
|
1523
|
+
"""
|
|
1524
|
+
return float(_stats().GlobalSensitivity.FirstOrderSobol(to_net_doubles(x), to_net_doubles(y), int(bins)))
|
|
1525
|
+
|
|
1526
|
+
|
|
1527
|
+
def pawn(x: Any, y: Any, bins: int = 20) -> np.ndarray:
|
|
1528
|
+
"""Return the per-bin PAWN statistics of an input from given data (``GlobalSensitivity.Pawn``).
|
|
1529
|
+
|
|
1530
|
+
For each equal-frequency input bin, the two-sample Kolmogorov-Smirnov statistic between the
|
|
1531
|
+
conditional and the unconditional output (Pianosi and Wagener, 2015).
|
|
1532
|
+
|
|
1533
|
+
Parameters
|
|
1534
|
+
----------
|
|
1535
|
+
x : array_like
|
|
1536
|
+
The input sample.
|
|
1537
|
+
y : array_like
|
|
1538
|
+
The output sample, aligned with ``x``.
|
|
1539
|
+
bins : int, optional
|
|
1540
|
+
The number of equal-frequency input bins; default 20.
|
|
1541
|
+
|
|
1542
|
+
Returns
|
|
1543
|
+
-------
|
|
1544
|
+
numpy.ndarray
|
|
1545
|
+
One statistic per bin, in bin order.
|
|
1546
|
+
|
|
1547
|
+
Raises
|
|
1548
|
+
------
|
|
1549
|
+
ValueError
|
|
1550
|
+
As for :func:`first_order_sobol`.
|
|
1551
|
+
"""
|
|
1552
|
+
return to_numpy_doubles(_stats().GlobalSensitivity.Pawn(to_net_doubles(x), to_net_doubles(y), int(bins)))
|
|
1553
|
+
|
|
1554
|
+
|
|
1555
|
+
def pawn_median(x: Any, y: Any, bins: int = 20) -> float:
|
|
1556
|
+
"""Return the PAWN index, the median of :func:`pawn` (``GlobalSensitivity.PawnMedian``).
|
|
1557
|
+
|
|
1558
|
+
Parameters
|
|
1559
|
+
----------
|
|
1560
|
+
x : array_like
|
|
1561
|
+
The input sample.
|
|
1562
|
+
y : array_like
|
|
1563
|
+
The output sample, aligned with ``x``.
|
|
1564
|
+
bins : int, optional
|
|
1565
|
+
The number of equal-frequency input bins; default 20.
|
|
1566
|
+
|
|
1567
|
+
Returns
|
|
1568
|
+
-------
|
|
1569
|
+
float
|
|
1570
|
+
The median per-bin statistic.
|
|
1571
|
+
|
|
1572
|
+
Raises
|
|
1573
|
+
------
|
|
1574
|
+
ValueError
|
|
1575
|
+
As for :func:`first_order_sobol`.
|
|
1576
|
+
"""
|
|
1577
|
+
return float(_stats().GlobalSensitivity.PawnMedian(to_net_doubles(x), to_net_doubles(y), int(bins)))
|
|
1578
|
+
|
|
1579
|
+
|
|
1580
|
+
def borgonovo_delta(x: Any, y: Any, x_bins: int = 20, y_bins: int = 20) -> float:
|
|
1581
|
+
"""Estimate the Borgonovo moment-independent delta from given data (``GlobalSensitivity.BorgonovoDelta``).
|
|
1582
|
+
|
|
1583
|
+
Half the bin-weighted total variation between conditional and unconditional frequencies of
|
|
1584
|
+
equal-frequency output classes; invariant to increasing transforms of the output.
|
|
1585
|
+
|
|
1586
|
+
Parameters
|
|
1587
|
+
----------
|
|
1588
|
+
x : array_like
|
|
1589
|
+
The input sample.
|
|
1590
|
+
y : array_like
|
|
1591
|
+
The output sample, aligned with ``x``.
|
|
1592
|
+
x_bins : int, optional
|
|
1593
|
+
The number of equal-frequency input bins; default 20.
|
|
1594
|
+
y_bins : int, optional
|
|
1595
|
+
The number of equal-frequency output classes; default 20.
|
|
1596
|
+
|
|
1597
|
+
Returns
|
|
1598
|
+
-------
|
|
1599
|
+
float
|
|
1600
|
+
The delta, in [0, 1 - 1 / y_bins].
|
|
1601
|
+
|
|
1602
|
+
Raises
|
|
1603
|
+
------
|
|
1604
|
+
ValueError
|
|
1605
|
+
As for :func:`first_order_sobol`, or if ``y_bins`` is below two or above the sample size.
|
|
1606
|
+
"""
|
|
1607
|
+
return float(_stats().GlobalSensitivity.BorgonovoDelta(to_net_doubles(x), to_net_doubles(y), int(x_bins),
|
|
1608
|
+
int(y_bins)))
|
|
1609
|
+
|
|
1610
|
+
|
|
1611
|
+
class HistogramBin:
|
|
1612
|
+
"""One histogram bin (``Numerics.Data.Statistics.Histogram.Bin``).
|
|
1613
|
+
|
|
1614
|
+
Parameters
|
|
1615
|
+
----------
|
|
1616
|
+
lower_bound : float
|
|
1617
|
+
The lower bound.
|
|
1618
|
+
upper_bound : float
|
|
1619
|
+
The upper bound.
|
|
1620
|
+
frequency : int, optional
|
|
1621
|
+
The count; default 0.
|
|
1622
|
+
|
|
1623
|
+
Attributes
|
|
1624
|
+
----------
|
|
1625
|
+
net : Numerics.Data.Statistics.Histogram.Bin
|
|
1626
|
+
The wrapped .NET object.
|
|
1627
|
+
"""
|
|
1628
|
+
|
|
1629
|
+
__hash__ = None # mutable: compared by value, never hashed
|
|
1630
|
+
|
|
1631
|
+
def __init__(self, lower_bound: float, upper_bound: float, frequency: int = 0) -> None:
|
|
1632
|
+
self.net = _stats().Histogram.Bin(float(lower_bound), float(upper_bound), int(frequency))
|
|
1633
|
+
|
|
1634
|
+
@classmethod
|
|
1635
|
+
def _from_net(cls, net: Any) -> HistogramBin:
|
|
1636
|
+
out = cls.__new__(cls)
|
|
1637
|
+
out.net = net
|
|
1638
|
+
return out
|
|
1639
|
+
|
|
1640
|
+
@property
|
|
1641
|
+
def lower_bound(self) -> float:
|
|
1642
|
+
"""Lower bound."""
|
|
1643
|
+
return float(self.net.LowerBound)
|
|
1644
|
+
|
|
1645
|
+
@lower_bound.setter
|
|
1646
|
+
def lower_bound(self, value: float) -> None:
|
|
1647
|
+
self.net.LowerBound = float(value)
|
|
1648
|
+
|
|
1649
|
+
@property
|
|
1650
|
+
def upper_bound(self) -> float:
|
|
1651
|
+
"""Upper bound."""
|
|
1652
|
+
return float(self.net.UpperBound)
|
|
1653
|
+
|
|
1654
|
+
@upper_bound.setter
|
|
1655
|
+
def upper_bound(self, value: float) -> None:
|
|
1656
|
+
self.net.UpperBound = float(value)
|
|
1657
|
+
|
|
1658
|
+
@property
|
|
1659
|
+
def midpoint(self) -> float:
|
|
1660
|
+
"""Midpoint of the bounds."""
|
|
1661
|
+
return float(self.net.Midpoint)
|
|
1662
|
+
|
|
1663
|
+
@property
|
|
1664
|
+
def frequency(self) -> int:
|
|
1665
|
+
"""Count of values in the bin."""
|
|
1666
|
+
return int(self.net.Frequency)
|
|
1667
|
+
|
|
1668
|
+
@frequency.setter
|
|
1669
|
+
def frequency(self, value: int) -> None:
|
|
1670
|
+
self.net.Frequency = int(value)
|
|
1671
|
+
|
|
1672
|
+
def clone(self) -> HistogramBin:
|
|
1673
|
+
"""Return an independent copy (``Bin.Clone``).
|
|
1674
|
+
|
|
1675
|
+
Returns
|
|
1676
|
+
-------
|
|
1677
|
+
HistogramBin
|
|
1678
|
+
The copy.
|
|
1679
|
+
"""
|
|
1680
|
+
return HistogramBin._from_net(self.net.Clone())
|
|
1681
|
+
|
|
1682
|
+
def compare_to(self, other: HistogramBin | None) -> int:
|
|
1683
|
+
"""Order two non-overlapping bins (``Bin.CompareTo``).
|
|
1684
|
+
|
|
1685
|
+
Parameters
|
|
1686
|
+
----------
|
|
1687
|
+
other : HistogramBin or None
|
|
1688
|
+
The bin to compare with.
|
|
1689
|
+
|
|
1690
|
+
Returns
|
|
1691
|
+
-------
|
|
1692
|
+
int
|
|
1693
|
+
0 when both bounds are bitwise equal, +1 when this bin is higher (or ``other`` is
|
|
1694
|
+
None), -1 otherwise.
|
|
1695
|
+
"""
|
|
1696
|
+
return int(self.net.CompareTo(None if other is None else other.net))
|
|
1697
|
+
|
|
1698
|
+
def __eq__(self, other: object) -> bool:
|
|
1699
|
+
return isinstance(other, HistogramBin) and bool(self.net.Equals(other.net))
|
|
1700
|
+
|
|
1701
|
+
def __repr__(self) -> str:
|
|
1702
|
+
return f"HistogramBin({self.lower_bound!r}, {self.upper_bound!r}, {self.frequency!r})"
|
|
1703
|
+
|
|
1704
|
+
|
|
1705
|
+
class Histogram:
|
|
1706
|
+
"""An adaptive histogram (``Numerics.Data.Statistics.Histogram``).
|
|
1707
|
+
|
|
1708
|
+
Equal-width bins span the data range; values added later outside the range widen the first or
|
|
1709
|
+
last bin. A value on an interior edge counts in the bin above it.
|
|
1710
|
+
|
|
1711
|
+
Parameters
|
|
1712
|
+
----------
|
|
1713
|
+
data : array_like
|
|
1714
|
+
The initial values.
|
|
1715
|
+
number_of_bins : int, optional
|
|
1716
|
+
The bin count; default Numerics' ``ceil(2 n^(1/3)) + 1``.
|
|
1717
|
+
|
|
1718
|
+
Attributes
|
|
1719
|
+
----------
|
|
1720
|
+
net : Numerics.Data.Statistics.Histogram
|
|
1721
|
+
The wrapped .NET object.
|
|
1722
|
+
"""
|
|
1723
|
+
|
|
1724
|
+
def __init__(self, data: Any, number_of_bins: int | None = None) -> None:
|
|
1725
|
+
values = to_net_doubles(data)
|
|
1726
|
+
h = _stats().Histogram
|
|
1727
|
+
self.net = h(values) if number_of_bins is None else h(values, int(number_of_bins))
|
|
1728
|
+
|
|
1729
|
+
@property
|
|
1730
|
+
def lower_bound(self) -> float:
|
|
1731
|
+
"""Lower edge of the first bin."""
|
|
1732
|
+
return float(self.net.LowerBound)
|
|
1733
|
+
|
|
1734
|
+
@property
|
|
1735
|
+
def upper_bound(self) -> float:
|
|
1736
|
+
"""Upper edge of the last bin."""
|
|
1737
|
+
return float(self.net.UpperBound)
|
|
1738
|
+
|
|
1739
|
+
@property
|
|
1740
|
+
def number_of_bins(self) -> int:
|
|
1741
|
+
"""Number of bins."""
|
|
1742
|
+
return int(self.net.NumberOfBins)
|
|
1743
|
+
|
|
1744
|
+
@property
|
|
1745
|
+
def bin_width(self) -> float:
|
|
1746
|
+
"""Initial bin width."""
|
|
1747
|
+
return float(self.net.BinWidth)
|
|
1748
|
+
|
|
1749
|
+
@property
|
|
1750
|
+
def data_count(self) -> int:
|
|
1751
|
+
"""Total count over the bins."""
|
|
1752
|
+
return int(self.net.DataCount)
|
|
1753
|
+
|
|
1754
|
+
@property
|
|
1755
|
+
def mean(self) -> float:
|
|
1756
|
+
"""Frequency-weighted mean of the bin midpoints; 0 when empty."""
|
|
1757
|
+
return float(self.net.Mean)
|
|
1758
|
+
|
|
1759
|
+
@property
|
|
1760
|
+
def median(self) -> float:
|
|
1761
|
+
"""Midpoint of the bin holding the median count; NaN when empty."""
|
|
1762
|
+
return float(self.net.Median)
|
|
1763
|
+
|
|
1764
|
+
@property
|
|
1765
|
+
def mode(self) -> float:
|
|
1766
|
+
"""Midpoint of the most frequent bin."""
|
|
1767
|
+
return float(self.net.Mode)
|
|
1768
|
+
|
|
1769
|
+
@property
|
|
1770
|
+
def standard_deviation(self) -> float:
|
|
1771
|
+
"""Frequency-weighted standard deviation of the bin midpoints (divisor n); 0 when empty."""
|
|
1772
|
+
return float(self.net.StandardDeviation)
|
|
1773
|
+
|
|
1774
|
+
def __len__(self) -> int:
|
|
1775
|
+
return int(self.net.NumberOfBins)
|
|
1776
|
+
|
|
1777
|
+
def __getitem__(self, index: int) -> HistogramBin:
|
|
1778
|
+
"""Return a copy of the bin at an index, in ascending order (``Histogram[index]``).
|
|
1779
|
+
|
|
1780
|
+
Parameters
|
|
1781
|
+
----------
|
|
1782
|
+
index : int
|
|
1783
|
+
The bin index; negative indices count from the end.
|
|
1784
|
+
|
|
1785
|
+
Returns
|
|
1786
|
+
-------
|
|
1787
|
+
HistogramBin
|
|
1788
|
+
A copy of the bin.
|
|
1789
|
+
|
|
1790
|
+
Raises
|
|
1791
|
+
------
|
|
1792
|
+
IndexError
|
|
1793
|
+
If the index is out of range.
|
|
1794
|
+
"""
|
|
1795
|
+
count = len(self)
|
|
1796
|
+
position = int(index) + count if int(index) < 0 else int(index)
|
|
1797
|
+
if not 0 <= position < count:
|
|
1798
|
+
raise IndexError(f"Bin index {index} is out of range for {count} bins.")
|
|
1799
|
+
return HistogramBin._from_net(self.net[position])
|
|
1800
|
+
|
|
1801
|
+
def bins(self) -> tuple[np.ndarray, np.ndarray, np.ndarray]:
|
|
1802
|
+
"""Return the lower bounds, upper bounds and frequencies of every bin, in ascending order.
|
|
1803
|
+
|
|
1804
|
+
Returns
|
|
1805
|
+
-------
|
|
1806
|
+
lower : numpy.ndarray
|
|
1807
|
+
The lower bounds.
|
|
1808
|
+
upper : numpy.ndarray
|
|
1809
|
+
The upper bounds.
|
|
1810
|
+
frequency : numpy.ndarray
|
|
1811
|
+
The int64 counts.
|
|
1812
|
+
"""
|
|
1813
|
+
items = [self.net[i] for i in range(len(self))]
|
|
1814
|
+
return (np.array([float(b.LowerBound) for b in items]), np.array([float(b.UpperBound) for b in items]),
|
|
1815
|
+
np.array([int(b.Frequency) for b in items], dtype=np.int64))
|
|
1816
|
+
|
|
1817
|
+
def add_bin(self, bin: HistogramBin) -> None:
|
|
1818
|
+
"""Append a bin (``Histogram.AddBin``).
|
|
1819
|
+
|
|
1820
|
+
Parameters
|
|
1821
|
+
----------
|
|
1822
|
+
bin : HistogramBin
|
|
1823
|
+
The bin; it must not overlap an existing one.
|
|
1824
|
+
"""
|
|
1825
|
+
self.net.AddBin(bin.net)
|
|
1826
|
+
|
|
1827
|
+
def add_data(self, values: Any) -> None:
|
|
1828
|
+
"""Count one value or an array in one call (``Histogram.AddData``).
|
|
1829
|
+
|
|
1830
|
+
Parameters
|
|
1831
|
+
----------
|
|
1832
|
+
values : float or array_like
|
|
1833
|
+
The values; one outside the range widens the first or last bin.
|
|
1834
|
+
"""
|
|
1835
|
+
array = np.asarray(values, dtype=np.float64)
|
|
1836
|
+
if array.ndim == 0:
|
|
1837
|
+
self.net.AddData(float(array))
|
|
1838
|
+
else:
|
|
1839
|
+
self.net.AddData(to_net_doubles(array.ravel()))
|
|
1840
|
+
|
|
1841
|
+
def bin_index(self, value: float) -> int:
|
|
1842
|
+
"""Return the index of the bin containing a value (``Histogram.GetBinIndexOf``).
|
|
1843
|
+
|
|
1844
|
+
Parameters
|
|
1845
|
+
----------
|
|
1846
|
+
value : float
|
|
1847
|
+
A value inside the histogram limits.
|
|
1848
|
+
|
|
1849
|
+
Returns
|
|
1850
|
+
-------
|
|
1851
|
+
int
|
|
1852
|
+
The bin index.
|
|
1853
|
+
|
|
1854
|
+
Raises
|
|
1855
|
+
------
|
|
1856
|
+
ValueError
|
|
1857
|
+
If the value lies outside the histogram limits.
|
|
1858
|
+
"""
|
|
1859
|
+
return int(self.net.GetBinIndexOf(float(value)))
|
|
1860
|
+
|
|
1861
|
+
|
|
1862
|
+
class RunningCovarianceMatrix:
|
|
1863
|
+
"""A streaming, identity-regularized covariance matrix (``Numerics.Data.Statistics.RunningCovarianceMatrix``).
|
|
1864
|
+
|
|
1865
|
+
The co-moment matrix starts at the identity, so after N vectors ``covariance`` is ``M2 + I``,
|
|
1866
|
+
``sample_covariance`` is ``(M2 + I) / (N - 1)`` and ``population_covariance`` is
|
|
1867
|
+
``(M2 + I) / N``: the sample statistics shrunk toward the identity with a weight that fades as
|
|
1868
|
+
1 / N. Subtract the identity from ``covariance`` for the plain co-moment matrix.
|
|
1869
|
+
|
|
1870
|
+
Parameters
|
|
1871
|
+
----------
|
|
1872
|
+
size : int
|
|
1873
|
+
The vector length.
|
|
1874
|
+
|
|
1875
|
+
Attributes
|
|
1876
|
+
----------
|
|
1877
|
+
net : Numerics.Data.Statistics.RunningCovarianceMatrix
|
|
1878
|
+
The wrapped .NET object.
|
|
1879
|
+
"""
|
|
1880
|
+
|
|
1881
|
+
def __init__(self, size: int) -> None:
|
|
1882
|
+
self.net = _stats().RunningCovarianceMatrix(int(size))
|
|
1883
|
+
|
|
1884
|
+
def push(self, values: Any) -> None:
|
|
1885
|
+
"""Add one vector, or each row of a 2-D array, with a Welford update (``Push``).
|
|
1886
|
+
|
|
1887
|
+
Numerics takes one vector per call, so a 2-D array crosses once per row.
|
|
1888
|
+
|
|
1889
|
+
Parameters
|
|
1890
|
+
----------
|
|
1891
|
+
values : array_like
|
|
1892
|
+
A vector of length ``size``, or an array of shape ``(m, size)``.
|
|
1893
|
+
|
|
1894
|
+
Raises
|
|
1895
|
+
------
|
|
1896
|
+
ValueError
|
|
1897
|
+
If a vector length differs from ``size``.
|
|
1898
|
+
"""
|
|
1899
|
+
array = np.asarray(values, dtype=np.float64)
|
|
1900
|
+
push = self.net.Push
|
|
1901
|
+
for row in (array,) if array.ndim == 1 else array:
|
|
1902
|
+
push(to_net_doubles(row))
|
|
1903
|
+
|
|
1904
|
+
@property
|
|
1905
|
+
def n(self) -> int:
|
|
1906
|
+
"""Number of vectors pushed."""
|
|
1907
|
+
return int(self.net.N)
|
|
1908
|
+
|
|
1909
|
+
@property
|
|
1910
|
+
def mean(self) -> np.ndarray:
|
|
1911
|
+
"""Mean vector."""
|
|
1912
|
+
return to_numpy_matrix(self.net.Mean.ToArray()).ravel()
|
|
1913
|
+
|
|
1914
|
+
@property
|
|
1915
|
+
def covariance(self) -> np.ndarray:
|
|
1916
|
+
"""Co-moment matrix ``M2 + I``, not divided by the sample size."""
|
|
1917
|
+
return to_numpy_matrix(self.net.Covariance.ToArray())
|
|
1918
|
+
|
|
1919
|
+
@property
|
|
1920
|
+
def sample_covariance(self) -> np.ndarray:
|
|
1921
|
+
"""Regularized sample covariance ``(M2 + I) / (N - 1)``."""
|
|
1922
|
+
return to_numpy_matrix(self.net.SampleCovariance.ToArray())
|
|
1923
|
+
|
|
1924
|
+
@property
|
|
1925
|
+
def population_covariance(self) -> np.ndarray:
|
|
1926
|
+
"""Regularized population covariance ``(M2 + I) / N``."""
|
|
1927
|
+
return to_numpy_matrix(self.net.PopulationCovariance.ToArray())
|
|
1928
|
+
|
|
1929
|
+
@property
|
|
1930
|
+
def sample_correlation(self) -> np.ndarray:
|
|
1931
|
+
"""Correlation matrix of :attr:`sample_covariance`."""
|
|
1932
|
+
return to_numpy_matrix(self.net.SampleCorrelation.ToArray())
|
|
1933
|
+
|
|
1934
|
+
@property
|
|
1935
|
+
def population_correlation(self) -> np.ndarray:
|
|
1936
|
+
"""Correlation matrix of :attr:`population_covariance`."""
|
|
1937
|
+
return to_numpy_matrix(self.net.PopulationCorrelation.ToArray())
|
|
1938
|
+
|
|
1939
|
+
|
|
1940
|
+
__all__ = [
|
|
1941
|
+
"Histogram", "HistogramBin", "RunningCovarianceMatrix", "RunningStatistics", "autocorrelation",
|
|
1942
|
+
"autocorrelation_confidence_interval", "borgonovo_delta", "box_cox_derivative", "box_cox_fit_lambda",
|
|
1943
|
+
"box_cox_inverse_transform", "box_cox_log_jacobian", "box_cox_log_likelihood", "box_cox_transform",
|
|
1944
|
+
"coefficient_of_variation", "column_linear_moments", "column_means", "column_percentiles",
|
|
1945
|
+
"column_standard_deviations", "column_variances", "covariance", "effective_sample_size",
|
|
1946
|
+
"entropy", "first_order_sobol", "five_number_summary", "geometric_mean", "harmonic_mean", "jackknife_sample",
|
|
1947
|
+
"jackknife_standard_error", "kendalls_tau", "kurtosis", "linear_coefficient_of_variation", "linear_moments",
|
|
1948
|
+
"maximum", "mean", "mean_standard_deviation", "mean_variance", "median", "minimum", "parallel_mean", "pawn",
|
|
1949
|
+
"pawn_median",
|
|
1950
|
+
"pearson", "percentile", "plotting_position_alpha", "plotting_position_percentile", "plotting_positions",
|
|
1951
|
+
"population_covariance", "population_standard_deviation", "population_variance", "product_moments", "ranks",
|
|
1952
|
+
"seven_number_summary", "skewness", "spearman", "standard_deviation", "sum",
|
|
1953
|
+
"variance", "weighted_plotting_positions", "wilson_score_interval", "yeo_johnson_derivative",
|
|
1954
|
+
"yeo_johnson_fit_lambda", "yeo_johnson_inverse_transform", "yeo_johnson_log_jacobian",
|
|
1955
|
+
"yeo_johnson_log_likelihood", "yeo_johnson_transform",
|
|
1956
|
+
]
|
|
1957
|
+
|
|
1958
|
+
translate_public(globals())
|