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
|
@@ -0,0 +1,1335 @@
|
|
|
1
|
+
"""Supervised and unsupervised models from ``Numerics.MachineLearning``.
|
|
2
|
+
|
|
3
|
+
Each class wraps one Numerics model and mirrors its members: the constructor takes the training
|
|
4
|
+
data, ``train`` (or ``fit``) runs the Numerics estimator, and ``predict`` and the other queries call
|
|
5
|
+
the Numerics members. Feature matrices cross to .NET once per call as a ``double[,]`` (rows are
|
|
6
|
+
observations, columns are features) and results come back as NumPy arrays. A one-dimensional
|
|
7
|
+
feature array is a single feature column, as in the Numerics ``double[]`` overloads, except where a
|
|
8
|
+
member documents it as one observation. Every estimator, default, seed and tolerance is the Numerics
|
|
9
|
+
one.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
from collections.abc import Callable
|
|
15
|
+
from typing import Any
|
|
16
|
+
|
|
17
|
+
import numpy as np
|
|
18
|
+
|
|
19
|
+
from pynumerics import callbacks
|
|
20
|
+
from pynumerics._util import cached_overload, loop, namespace, net_enum
|
|
21
|
+
from pynumerics.enums import NetEnum
|
|
22
|
+
from pynumerics.errors import translate_public
|
|
23
|
+
from pynumerics.marshal import (
|
|
24
|
+
_numerics_matrix,
|
|
25
|
+
_numerics_vector,
|
|
26
|
+
_optional_doubles,
|
|
27
|
+
to_net_doubles,
|
|
28
|
+
to_net_ints,
|
|
29
|
+
to_net_matrix,
|
|
30
|
+
to_numpy_doubles,
|
|
31
|
+
to_numpy_ints,
|
|
32
|
+
to_numpy_matrix,
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class GaussianProcessKernel(NetEnum):
|
|
37
|
+
"""Covariance functions of Gaussian process regression (``Numerics.MachineLearning.GaussianProcessKernel``)."""
|
|
38
|
+
|
|
39
|
+
SQUARED_EXPONENTIAL = "SquaredExponential"
|
|
40
|
+
MATERN32 = "Matern32"
|
|
41
|
+
MATERN52 = "Matern52"
|
|
42
|
+
EXPONENTIAL = "Exponential"
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class GaussianProcessMean(NetEnum):
|
|
46
|
+
"""Mean functions of Gaussian process regression (``Numerics.MachineLearning.GaussianProcessMean``)."""
|
|
47
|
+
|
|
48
|
+
ZERO = "Zero"
|
|
49
|
+
CONSTANT = "Constant"
|
|
50
|
+
LINEAR = "Linear"
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class VariogramModel(NetEnum):
|
|
54
|
+
"""Isotropic variogram models for kriging (``Numerics.MachineLearning.VariogramModel``)."""
|
|
55
|
+
|
|
56
|
+
SPHERICAL = "Spherical"
|
|
57
|
+
EXPONENTIAL = "Exponential"
|
|
58
|
+
GAUSSIAN = "Gaussian"
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class KrigingType(NetEnum):
|
|
62
|
+
"""Kriging variants (``Numerics.MachineLearning.KrigingType``)."""
|
|
63
|
+
|
|
64
|
+
SIMPLE = "Simple"
|
|
65
|
+
ORDINARY = "Ordinary"
|
|
66
|
+
UNIVERSAL = "Universal"
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
class PrincipalComponentBasis(NetEnum):
|
|
70
|
+
"""Bases of principal component analysis (``Numerics.MachineLearning.PrincipalComponentBasis``)."""
|
|
71
|
+
|
|
72
|
+
COVARIANCE = "Covariance"
|
|
73
|
+
CORRELATION = "Correlation"
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def _net_type(name: str) -> Any:
|
|
77
|
+
"""Return a ``Numerics.MachineLearning`` type by name."""
|
|
78
|
+
return getattr(namespace("Numerics.MachineLearning"), name)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def _columns(x: Any) -> np.ndarray:
|
|
82
|
+
"""Return features as a float64 matrix; a 1-D array becomes one feature column."""
|
|
83
|
+
array = np.asarray(x, dtype=np.float64)
|
|
84
|
+
if array.ndim == 1:
|
|
85
|
+
array = array.reshape(-1, 1)
|
|
86
|
+
if array.ndim != 2:
|
|
87
|
+
raise ValueError(f"Expected a 1-D or 2-D feature array; got shape {array.shape}.")
|
|
88
|
+
return array
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def _net_columns(x: Any) -> Any:
|
|
92
|
+
"""Copy features into a ``System.Double[,]`` (see :func:`_columns`)."""
|
|
93
|
+
return to_net_matrix(_columns(x))
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def _doubles(value: Any) -> np.ndarray | None:
|
|
97
|
+
"""Copy a .NET ``double[]`` or ``Vector`` to NumPy; a null reference gives None."""
|
|
98
|
+
if value is None:
|
|
99
|
+
return None
|
|
100
|
+
return to_numpy_doubles(value.Array if hasattr(value, "Header") else value)
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def _matrix(value: Any) -> np.ndarray | None:
|
|
104
|
+
"""Copy a .NET ``double[,]`` or ``Matrix`` to NumPy; a null reference gives None."""
|
|
105
|
+
if value is None:
|
|
106
|
+
return None
|
|
107
|
+
return to_numpy_matrix(value.Array if hasattr(value, "NumberOfRows") else value)
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def _ints(value: Any) -> np.ndarray | None:
|
|
111
|
+
"""Copy a .NET ``int[]`` to NumPy; a null reference gives None."""
|
|
112
|
+
return None if value is None else to_numpy_ints(value)
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def _pair(result: Any) -> tuple[np.ndarray, np.ndarray]:
|
|
116
|
+
"""Copy a .NET ``(double[] Mean, double[] Variance)`` tuple to two NumPy arrays."""
|
|
117
|
+
return to_numpy_doubles(result.Item1), to_numpy_doubles(result.Item2)
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def _member(name: str, convert: Callable[[Any], Any] | None, doc: str,
|
|
121
|
+
to_net: Callable[[Any], Any] | None = None) -> property:
|
|
122
|
+
"""Return a property reading (and, with ``to_net``, writing) the .NET member ``name`` of ``self.net``."""
|
|
123
|
+
def fget(self: Any) -> Any:
|
|
124
|
+
value = getattr(self.net, name)
|
|
125
|
+
return value if convert is None else convert(value)
|
|
126
|
+
|
|
127
|
+
if to_net is None:
|
|
128
|
+
return property(fget, doc=doc)
|
|
129
|
+
|
|
130
|
+
def fset(self: Any, value: Any) -> None:
|
|
131
|
+
setattr(self.net, name, to_net(value))
|
|
132
|
+
|
|
133
|
+
return property(fget, fset, doc=doc)
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
class _NetModel:
|
|
137
|
+
"""Base of the wrappers: holds the .NET object in ``net`` and wraps an existing one."""
|
|
138
|
+
|
|
139
|
+
net: Any
|
|
140
|
+
|
|
141
|
+
@classmethod
|
|
142
|
+
def _wrap(cls, net: Any) -> Any:
|
|
143
|
+
"""Return a wrapper around an existing .NET object."""
|
|
144
|
+
out = cls.__new__(cls)
|
|
145
|
+
out.net = net
|
|
146
|
+
return out
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
class DecisionNode(_NetModel):
|
|
150
|
+
"""A node of a decision tree (``Numerics.MachineLearning.DecisionNode``).
|
|
151
|
+
|
|
152
|
+
Attributes
|
|
153
|
+
----------
|
|
154
|
+
net : Numerics.MachineLearning.DecisionNode
|
|
155
|
+
The wrapped .NET object.
|
|
156
|
+
"""
|
|
157
|
+
|
|
158
|
+
def __init__(self) -> None:
|
|
159
|
+
self.net = _net_type("DecisionNode")()
|
|
160
|
+
|
|
161
|
+
feature_index = _member("FeatureIndex", int, "Index of the feature the node splits on; -1 for a leaf.", int)
|
|
162
|
+
threshold = _member("Threshold", float, "Split threshold; NaN for a leaf.", float)
|
|
163
|
+
value = _member("Value", float, "Leaf prediction; NaN for an internal node.", float)
|
|
164
|
+
is_leaf_node = _member("IsLeafNode", bool, "Whether the node is a leaf.", bool)
|
|
165
|
+
|
|
166
|
+
@property
|
|
167
|
+
def left(self) -> DecisionNode | None:
|
|
168
|
+
"""Left child, or None."""
|
|
169
|
+
node = self.net.Left
|
|
170
|
+
return None if node is None else DecisionNode._wrap(node)
|
|
171
|
+
|
|
172
|
+
@property
|
|
173
|
+
def right(self) -> DecisionNode | None:
|
|
174
|
+
"""Right child, or None."""
|
|
175
|
+
node = self.net.Right
|
|
176
|
+
return None if node is None else DecisionNode._wrap(node)
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
class DecisionTree(_NetModel):
|
|
180
|
+
"""Classification and regression tree (``Numerics.MachineLearning.DecisionTree``).
|
|
181
|
+
|
|
182
|
+
Parameters
|
|
183
|
+
----------
|
|
184
|
+
x : array_like
|
|
185
|
+
Training features, shape (n, d); a 1-D array is one feature.
|
|
186
|
+
y : array_like
|
|
187
|
+
Training responses (class labels as numbers for classification), length n, at least 10.
|
|
188
|
+
seed : int, optional
|
|
189
|
+
Mersenne Twister seed for the feature subsets; zero or negative seeds from the clock.
|
|
190
|
+
|
|
191
|
+
Attributes
|
|
192
|
+
----------
|
|
193
|
+
net : Numerics.MachineLearning.DecisionTree
|
|
194
|
+
The wrapped .NET object.
|
|
195
|
+
|
|
196
|
+
Notes
|
|
197
|
+
-----
|
|
198
|
+
Set :attr:`is_regression`, :attr:`max_depth`, :attr:`minimum_split_size` and :attr:`features`
|
|
199
|
+
before :meth:`train`. Each split considers :attr:`features` randomly chosen features (default
|
|
200
|
+
``max(1, d - 1)``).
|
|
201
|
+
"""
|
|
202
|
+
|
|
203
|
+
def __init__(self, x: Any, y: Any, seed: int = -1) -> None:
|
|
204
|
+
self.net = _net_type("DecisionTree")(_net_columns(x), to_net_doubles(y), int(seed))
|
|
205
|
+
|
|
206
|
+
def train(self) -> None:
|
|
207
|
+
"""Grow the tree (``Train``)."""
|
|
208
|
+
self.net.Train()
|
|
209
|
+
|
|
210
|
+
def predict(self, x: Any) -> np.ndarray | None:
|
|
211
|
+
"""Return the tree prediction for each row (``Predict``).
|
|
212
|
+
|
|
213
|
+
Parameters
|
|
214
|
+
----------
|
|
215
|
+
x : array_like
|
|
216
|
+
Features, shape (m, d); a 1-D array is one feature.
|
|
217
|
+
|
|
218
|
+
Returns
|
|
219
|
+
-------
|
|
220
|
+
numpy.ndarray or None
|
|
221
|
+
The m predictions, or None when the tree is untrained or ``x`` has a different number of
|
|
222
|
+
columns (the Numerics member returns null).
|
|
223
|
+
"""
|
|
224
|
+
return _doubles(self.net.Predict(_net_columns(x)))
|
|
225
|
+
|
|
226
|
+
minimum_split_size = _member("MinimumSplitSize", int, "Minimum number of rows to split a node (default 2).", int)
|
|
227
|
+
max_depth = _member("MaxDepth", int, "Maximum depth of the tree (default 100).", int)
|
|
228
|
+
features = _member("Features", int, "Number of features considered at each split.", int)
|
|
229
|
+
is_regression = _member("IsRegression", bool, "Regression (True, default) or classification.", bool)
|
|
230
|
+
dimensions = _member("Dimensions", int, "Number of feature columns d.")
|
|
231
|
+
is_trained = _member("IsTrained", bool, "Whether the tree has been trained.")
|
|
232
|
+
x = _member("X", _matrix, "Training features, shape (n, d).")
|
|
233
|
+
y = _member("Y", _doubles, "Training responses.")
|
|
234
|
+
|
|
235
|
+
@property
|
|
236
|
+
def root(self) -> DecisionNode:
|
|
237
|
+
"""Root node of the tree."""
|
|
238
|
+
return DecisionNode._wrap(self.net.Root)
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
class RandomForest(_NetModel):
|
|
242
|
+
"""Random forest of decision trees on bootstrap samples (``Numerics.MachineLearning.RandomForest``).
|
|
243
|
+
|
|
244
|
+
Parameters
|
|
245
|
+
----------
|
|
246
|
+
x : array_like
|
|
247
|
+
Training features, shape (n, d); a 1-D array is one feature.
|
|
248
|
+
y : array_like
|
|
249
|
+
Training responses, length n, at least 10.
|
|
250
|
+
seed : int, optional
|
|
251
|
+
Mersenne Twister seed of the forest; zero or negative seeds from the clock.
|
|
252
|
+
|
|
253
|
+
Attributes
|
|
254
|
+
----------
|
|
255
|
+
net : Numerics.MachineLearning.RandomForest
|
|
256
|
+
The wrapped .NET object.
|
|
257
|
+
|
|
258
|
+
Notes
|
|
259
|
+
-----
|
|
260
|
+
Trees are trained in parallel, each from a seed drawn from the forest generator, so a seeded
|
|
261
|
+
forest is deterministic.
|
|
262
|
+
"""
|
|
263
|
+
|
|
264
|
+
def __init__(self, x: Any, y: Any, seed: int = -1) -> None:
|
|
265
|
+
self.net = _net_type("RandomForest")(_net_columns(x), to_net_doubles(y), int(seed))
|
|
266
|
+
|
|
267
|
+
def train(self) -> None:
|
|
268
|
+
"""Train every tree (``Train``)."""
|
|
269
|
+
self.net.Train()
|
|
270
|
+
|
|
271
|
+
def predict(self, x: Any, alpha: float = 0.1) -> np.ndarray | None:
|
|
272
|
+
"""Return the forest prediction and its interval across trees (``Predict``).
|
|
273
|
+
|
|
274
|
+
Parameters
|
|
275
|
+
----------
|
|
276
|
+
x : array_like
|
|
277
|
+
Features, shape (m, d); a 1-D array is one feature.
|
|
278
|
+
alpha : float, optional
|
|
279
|
+
One minus the interval coverage; default 0.1 (a 90% interval).
|
|
280
|
+
|
|
281
|
+
Returns
|
|
282
|
+
-------
|
|
283
|
+
numpy.ndarray or None
|
|
284
|
+
Shape (m, 4) with columns lower, median, upper and mean of the tree predictions (floored
|
|
285
|
+
for classification), or None when the forest is untrained or ``x`` has a different number
|
|
286
|
+
of columns.
|
|
287
|
+
"""
|
|
288
|
+
return _matrix(self.net.Predict(_net_columns(x), float(alpha)))
|
|
289
|
+
|
|
290
|
+
number_of_trees = _member("NumberOfTrees", int, "Number of trees (default 1000).", int)
|
|
291
|
+
minimum_split_size = _member("MinimumSplitSize", int, "Minimum number of rows to split a node (default 2).", int)
|
|
292
|
+
max_depth = _member("MaxDepth", int, "Maximum depth of each tree (default 100).", int)
|
|
293
|
+
features = _member("Features", int, "Number of features considered at each split.", int)
|
|
294
|
+
is_regression = _member("IsRegression", bool, "Regression (True, default) or classification.", bool)
|
|
295
|
+
dimensions = _member("Dimensions", int, "Number of feature columns d.")
|
|
296
|
+
is_trained = _member("IsTrained", bool, "Whether the forest has been trained.")
|
|
297
|
+
x = _member("X", _matrix, "Training features, shape (n, d).")
|
|
298
|
+
y = _member("Y", _doubles, "Training responses.")
|
|
299
|
+
|
|
300
|
+
@property
|
|
301
|
+
def decision_trees(self) -> list[DecisionTree]:
|
|
302
|
+
"""The trained trees; empty before training."""
|
|
303
|
+
trees = self.net.DecisionTrees
|
|
304
|
+
return [] if trees is None else [DecisionTree._wrap(tree) for tree in trees]
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
class KNearestNeighbors(_NetModel):
|
|
308
|
+
"""The k-nearest neighbors regression and classification (``Numerics.MachineLearning.KNearestNeighbors``).
|
|
309
|
+
|
|
310
|
+
Parameters
|
|
311
|
+
----------
|
|
312
|
+
x : array_like
|
|
313
|
+
Training features, shape (n, d); a 1-D array is one feature.
|
|
314
|
+
y : array_like
|
|
315
|
+
Training responses, length n.
|
|
316
|
+
k : int
|
|
317
|
+
Number of neighbors.
|
|
318
|
+
|
|
319
|
+
Attributes
|
|
320
|
+
----------
|
|
321
|
+
net : Numerics.MachineLearning.KNearestNeighbors
|
|
322
|
+
The wrapped .NET object.
|
|
323
|
+
|
|
324
|
+
Notes
|
|
325
|
+
-----
|
|
326
|
+
Distances are Euclidean, ties broken by the lower training index. Regression averages the
|
|
327
|
+
neighbors with inverse squared distance weights (exact matches take all the weight);
|
|
328
|
+
classification returns the most common neighbor class.
|
|
329
|
+
"""
|
|
330
|
+
|
|
331
|
+
def __init__(self, x: Any, y: Any, k: int) -> None:
|
|
332
|
+
self.net = _net_type("KNearestNeighbors")(_net_columns(x), to_net_doubles(y), int(k))
|
|
333
|
+
|
|
334
|
+
def get_neighbors(self, x: Any) -> np.ndarray | None:
|
|
335
|
+
"""Return the training indexes of the k nearest neighbors of each row (``GetNeighbors``).
|
|
336
|
+
|
|
337
|
+
Parameters
|
|
338
|
+
----------
|
|
339
|
+
x : array_like
|
|
340
|
+
Query features, shape (m, d); a 1-D array is one feature.
|
|
341
|
+
|
|
342
|
+
Returns
|
|
343
|
+
-------
|
|
344
|
+
numpy.ndarray or None
|
|
345
|
+
Shape (m, k) int32, nearest first, or None when ``x`` has a different number of columns.
|
|
346
|
+
"""
|
|
347
|
+
rows = _columns(x)
|
|
348
|
+
found = _ints(self.net.GetNeighbors(to_net_matrix(rows)))
|
|
349
|
+
return None if found is None else found.reshape(rows.shape[0], -1)
|
|
350
|
+
|
|
351
|
+
def predict(self, x: Any) -> np.ndarray | None:
|
|
352
|
+
"""Return the k-nearest-neighbor prediction of each row (``Predict``).
|
|
353
|
+
|
|
354
|
+
Parameters
|
|
355
|
+
----------
|
|
356
|
+
x : array_like
|
|
357
|
+
Query features, shape (m, d); a 1-D array is one feature.
|
|
358
|
+
|
|
359
|
+
Returns
|
|
360
|
+
-------
|
|
361
|
+
numpy.ndarray or None
|
|
362
|
+
The m predictions, or None when ``x`` has a different number of columns.
|
|
363
|
+
"""
|
|
364
|
+
return _doubles(self.net.Predict(_net_columns(x)))
|
|
365
|
+
|
|
366
|
+
def bootstrap_predict(self, x: Any, seed: int = -1) -> np.ndarray | None:
|
|
367
|
+
"""Return the prediction from one bootstrap resample of the training data (``BootstrapPredict``).
|
|
368
|
+
|
|
369
|
+
Parameters
|
|
370
|
+
----------
|
|
371
|
+
x : array_like
|
|
372
|
+
Query features, shape (m, d); a 1-D array is one feature.
|
|
373
|
+
seed : int, optional
|
|
374
|
+
Mersenne Twister seed of the resample; zero or negative seeds from the clock.
|
|
375
|
+
|
|
376
|
+
Returns
|
|
377
|
+
-------
|
|
378
|
+
numpy.ndarray or None
|
|
379
|
+
The m predictions, or None when ``x`` has a different number of columns.
|
|
380
|
+
"""
|
|
381
|
+
return _doubles(self.net.BootstrapPredict(_net_columns(x), int(seed)))
|
|
382
|
+
|
|
383
|
+
def prediction_intervals(self, x: Any, seed: int = -1, realizations: int = 1000,
|
|
384
|
+
alpha: float = 0.1) -> np.ndarray | None:
|
|
385
|
+
"""Return bootstrap prediction intervals (``PredictionIntervals``).
|
|
386
|
+
|
|
387
|
+
Parameters
|
|
388
|
+
----------
|
|
389
|
+
x : array_like
|
|
390
|
+
Query features, shape (m, d); a 1-D array is one feature.
|
|
391
|
+
seed : int, optional
|
|
392
|
+
Mersenne Twister seed; zero or negative seeds from the clock.
|
|
393
|
+
realizations : int, optional
|
|
394
|
+
Number of bootstrap resamples; default 1000.
|
|
395
|
+
alpha : float, optional
|
|
396
|
+
One minus the interval coverage; default 0.1.
|
|
397
|
+
|
|
398
|
+
Returns
|
|
399
|
+
-------
|
|
400
|
+
numpy.ndarray or None
|
|
401
|
+
Shape (m, 4) with columns lower, median, upper and mean.
|
|
402
|
+
"""
|
|
403
|
+
return _matrix(self.net.PredictionIntervals(_net_columns(x), int(seed), int(realizations), float(alpha)))
|
|
404
|
+
|
|
405
|
+
k = _member("K", int, "Number of neighbors.")
|
|
406
|
+
is_regression = _member("IsRegression", bool, "Regression (True, default) or classification.", bool)
|
|
407
|
+
number_of_features = _member("NumberOfFeatures", int, "Number of feature columns d.")
|
|
408
|
+
x = _member("X", _matrix, "Training features, shape (n, d).")
|
|
409
|
+
y = _member("Y", _doubles, "Training responses.")
|
|
410
|
+
|
|
411
|
+
|
|
412
|
+
class NaiveBayes(_NetModel):
|
|
413
|
+
"""Gaussian naive Bayes classifier (``Numerics.MachineLearning.NaiveBayes``).
|
|
414
|
+
|
|
415
|
+
Parameters
|
|
416
|
+
----------
|
|
417
|
+
x : array_like
|
|
418
|
+
Training features, shape (n, d); a 1-D array is one feature.
|
|
419
|
+
y : array_like
|
|
420
|
+
Class labels as numbers, length n.
|
|
421
|
+
|
|
422
|
+
Attributes
|
|
423
|
+
----------
|
|
424
|
+
net : Numerics.MachineLearning.NaiveBayes
|
|
425
|
+
The wrapped .NET object.
|
|
426
|
+
|
|
427
|
+
Notes
|
|
428
|
+
-----
|
|
429
|
+
Class-conditional standard deviations use the n - 1 divisor and are floored at
|
|
430
|
+
``sqrt(1e-9 * max variance)``; priors are the class frequencies.
|
|
431
|
+
"""
|
|
432
|
+
|
|
433
|
+
def __init__(self, x: Any, y: Any) -> None:
|
|
434
|
+
self.net = _net_type("NaiveBayes")(_net_columns(x), to_net_doubles(y))
|
|
435
|
+
|
|
436
|
+
def train(self) -> None:
|
|
437
|
+
"""Estimate the priors and class-conditional normals (``Train``)."""
|
|
438
|
+
self.net.Train()
|
|
439
|
+
|
|
440
|
+
def predict(self, x: Any) -> np.ndarray | None:
|
|
441
|
+
"""Return the maximum a posteriori class of each row (``Predict``).
|
|
442
|
+
|
|
443
|
+
Parameters
|
|
444
|
+
----------
|
|
445
|
+
x : array_like
|
|
446
|
+
Features, shape (m, d); a 1-D array is one feature.
|
|
447
|
+
|
|
448
|
+
Returns
|
|
449
|
+
-------
|
|
450
|
+
numpy.ndarray or None
|
|
451
|
+
The m predicted classes, or None when untrained or ``x`` has a different number of columns.
|
|
452
|
+
"""
|
|
453
|
+
return _doubles(self.net.Predict(_net_columns(x)))
|
|
454
|
+
|
|
455
|
+
classes = _member("Classes", _doubles, "The distinct class labels.")
|
|
456
|
+
means = _member("Means", _matrix, "Class-conditional feature means, shape (classes, d).")
|
|
457
|
+
standard_deviations = _member("StandardDeviations", _matrix,
|
|
458
|
+
"Class-conditional feature standard deviations, shape (classes, d).")
|
|
459
|
+
priors = _member("Priors", _doubles, "Class prior probabilities.")
|
|
460
|
+
is_trained = _member("IsTrained", bool, "Whether the classifier has been trained.")
|
|
461
|
+
x = _member("X", _matrix, "Training features, shape (n, d).")
|
|
462
|
+
y = _member("Y", _doubles, "Training class labels.")
|
|
463
|
+
|
|
464
|
+
|
|
465
|
+
def _glm_predict(arity: int) -> Any:
|
|
466
|
+
"""Return ``GeneralizedLinearModel.Predict(Matrix)`` or ``Predict(Matrix, double)``, bound once."""
|
|
467
|
+
def factory() -> Any:
|
|
468
|
+
import System # noqa: PLC0415 - the runtime is running
|
|
469
|
+
|
|
470
|
+
matrix = namespace("Numerics.Mathematics.LinearAlgebra").Matrix
|
|
471
|
+
signature = (matrix,) if arity == 1 else (matrix, System.Double)
|
|
472
|
+
return _net_type("GeneralizedLinearModel").Predict.Overloads[signature]
|
|
473
|
+
|
|
474
|
+
return cached_overload(f"GeneralizedLinearModel.Predict/{arity}", factory)
|
|
475
|
+
|
|
476
|
+
|
|
477
|
+
class GeneralizedLinearModel(_NetModel):
|
|
478
|
+
"""Generalized linear model fitted by maximum likelihood (``Numerics.MachineLearning.GeneralizedLinearModel``).
|
|
479
|
+
|
|
480
|
+
Parameters
|
|
481
|
+
----------
|
|
482
|
+
x : array_like
|
|
483
|
+
Predictors, shape (n, p); a 1-D array is one predictor.
|
|
484
|
+
y : array_like
|
|
485
|
+
Responses, length n (0/1 for the binary links, counts for the log link).
|
|
486
|
+
has_intercept : bool, optional
|
|
487
|
+
Whether an intercept column is added; default True.
|
|
488
|
+
link : str, optional
|
|
489
|
+
``LinkFunctionType`` member name: ``"identity"`` (normal, default), ``"log"`` (Poisson),
|
|
490
|
+
``"logit"``, ``"probit"`` or ``"complementary_log_log"`` (Bernoulli). With ``link_function``
|
|
491
|
+
it selects the family and the optimizer start.
|
|
492
|
+
link_function : Numerics.Functions.ILinkFunction, optional
|
|
493
|
+
A custom .NET link function instance.
|
|
494
|
+
feature_names : sequence of str, optional
|
|
495
|
+
Predictor names for :meth:`summary` (``Matrix.Header``). With an added intercept column the
|
|
496
|
+
coefficient names are ``"Intercept"`` followed by these names; without names they are
|
|
497
|
+
``β1 ... βp``.
|
|
498
|
+
response_name : str, optional
|
|
499
|
+
Response name for :meth:`summary` (``Vector.Header``).
|
|
500
|
+
|
|
501
|
+
Attributes
|
|
502
|
+
----------
|
|
503
|
+
net : Numerics.MachineLearning.GeneralizedLinearModel
|
|
504
|
+
The wrapped .NET object.
|
|
505
|
+
"""
|
|
506
|
+
|
|
507
|
+
def __init__(self, x: Any, y: Any, has_intercept: bool = True, link: str = "identity",
|
|
508
|
+
link_function: Any = None, feature_names: Any = None, response_name: str | None = None) -> None:
|
|
509
|
+
functions = namespace("Numerics.Functions")
|
|
510
|
+
net_type = _net_type("GeneralizedLinearModel")
|
|
511
|
+
matrix, vector = _numerics_matrix(_columns(x)), _numerics_vector(y)
|
|
512
|
+
if feature_names is not None:
|
|
513
|
+
import System # noqa: PLC0415 - the runtime is running
|
|
514
|
+
|
|
515
|
+
matrix.Header = System.Array[System.String]([str(name) for name in feature_names])
|
|
516
|
+
if response_name is not None:
|
|
517
|
+
vector.Header = str(response_name)
|
|
518
|
+
link_type = net_enum(functions.LinkFunctionType, link)
|
|
519
|
+
if link_function is None:
|
|
520
|
+
self.net = net_type(matrix, vector, bool(has_intercept), link_type)
|
|
521
|
+
else:
|
|
522
|
+
self.net = net_type(matrix, vector, link_function, bool(has_intercept), link_type)
|
|
523
|
+
|
|
524
|
+
def set_optimizer(self, method: str = "NelderMead") -> None:
|
|
525
|
+
"""Choose the local optimizer used by :meth:`train` (``SetOptimizer``).
|
|
526
|
+
|
|
527
|
+
Parameters
|
|
528
|
+
----------
|
|
529
|
+
method : str, optional
|
|
530
|
+
``LocalMethod`` member name; default ``"NelderMead"``.
|
|
531
|
+
"""
|
|
532
|
+
optimization = namespace("Numerics.Mathematics.Optimization")
|
|
533
|
+
self.net.SetOptimizer(net_enum(optimization.LocalMethod, method))
|
|
534
|
+
|
|
535
|
+
def train(self) -> None:
|
|
536
|
+
"""Fit the parameters and compute the diagnostics (``Train``).
|
|
537
|
+
|
|
538
|
+
The optimizer result is kept unless the Fisher scoring estimate has a higher log-likelihood.
|
|
539
|
+
"""
|
|
540
|
+
self.net.Train()
|
|
541
|
+
|
|
542
|
+
def predict(self, x: Any, alpha: float | None = None) -> np.ndarray:
|
|
543
|
+
"""Return the mean response, optionally with a confidence interval (``Predict``).
|
|
544
|
+
|
|
545
|
+
Parameters
|
|
546
|
+
----------
|
|
547
|
+
x : array_like
|
|
548
|
+
Predictors, shape (m, p), or (m, p + 1) with the intercept column already included.
|
|
549
|
+
alpha : float, optional
|
|
550
|
+
When given, one minus the confidence level of the interval for the mean response.
|
|
551
|
+
|
|
552
|
+
Returns
|
|
553
|
+
-------
|
|
554
|
+
numpy.ndarray
|
|
555
|
+
The m mean responses, or with ``alpha`` shape (m, 3) with columns lower, mean and upper
|
|
556
|
+
(formed on the link scale and mapped through the inverse link).
|
|
557
|
+
"""
|
|
558
|
+
matrix = _numerics_matrix(_columns(x))
|
|
559
|
+
if alpha is None:
|
|
560
|
+
return to_numpy_doubles(_glm_predict(1)(self.net, matrix))
|
|
561
|
+
return to_numpy_matrix(_glm_predict(2)(self.net, matrix, float(alpha)))
|
|
562
|
+
|
|
563
|
+
def summary(self) -> list[str]:
|
|
564
|
+
"""Return the text summary table (``Summary``).
|
|
565
|
+
|
|
566
|
+
Returns
|
|
567
|
+
-------
|
|
568
|
+
list of str
|
|
569
|
+
The lines of the report.
|
|
570
|
+
"""
|
|
571
|
+
return [str(line) for line in self.net.Summary()]
|
|
572
|
+
|
|
573
|
+
has_intercept = _member("HasIntercept", bool, "Whether the model has an intercept.")
|
|
574
|
+
use_robust_se = _member("UseRobustSE", bool, "Use HC0 sandwich standard errors (set before training).", bool)
|
|
575
|
+
parameters = _member("Parameters", _doubles, "Fitted coefficients, intercept first; None before training.")
|
|
576
|
+
parameter_standard_errors = _member("ParameterStandardErrors", _doubles, "Coefficient standard errors.")
|
|
577
|
+
parameter_z_scores = _member("ParameterZScores", _doubles, "Coefficient z statistics.")
|
|
578
|
+
parameter_p_values = _member("ParameterPValues", _doubles, "Two-sided normal p-values of the coefficients.")
|
|
579
|
+
covariance = _member("Covariance", _matrix, "Coefficient covariance matrix.")
|
|
580
|
+
residuals = _member("Residuals", _doubles, "Response residuals y - mu.")
|
|
581
|
+
standard_error = _member("StandardError", float, "Residual standard error sqrt(SSE / (n - p)).")
|
|
582
|
+
sample_size = _member("SampleSize", int, "Number of observations n.")
|
|
583
|
+
degrees_of_freedom = _member("DegreesOfFreedom", int, "Residual degrees of freedom n - p.")
|
|
584
|
+
aic = _member("AIC", float, "Akaike information criterion; the normal family evaluates the likelihood at "
|
|
585
|
+
"the maximum likelihood variance SSE / n, as statsmodels GLM does.")
|
|
586
|
+
aicc = _member("AICc", float, "Small-sample corrected AIC.")
|
|
587
|
+
bic = _member("BIC", float, "Bayesian information criterion.")
|
|
588
|
+
x = _member("X", _matrix, "Design matrix, including the intercept column when present.")
|
|
589
|
+
y = _member("Y", _doubles, "Responses.")
|
|
590
|
+
link_type = _member("LinkType", str, "``LinkFunctionType`` member name of the model.")
|
|
591
|
+
link_function = _member("LinkFunction", None, "The .NET ``ILinkFunction`` instance.")
|
|
592
|
+
optimizer = _member("Optimizer", None, "The .NET ``Optimizer`` used by :meth:`train`.")
|
|
593
|
+
|
|
594
|
+
@property
|
|
595
|
+
def parameter_names(self) -> list[str]:
|
|
596
|
+
"""Coefficient names, ``"Intercept"`` first when present."""
|
|
597
|
+
names = self.net.ParameterNames
|
|
598
|
+
return [] if names is None else [str(name) for name in names]
|
|
599
|
+
|
|
600
|
+
|
|
601
|
+
class ElasticNetRegression(_NetModel):
|
|
602
|
+
"""Elastic net regression path by coordinate descent (``Numerics.MachineLearning.ElasticNetRegression``).
|
|
603
|
+
|
|
604
|
+
Parameters
|
|
605
|
+
----------
|
|
606
|
+
x : array_like
|
|
607
|
+
Predictors, shape (n, p); a 1-D array is one predictor.
|
|
608
|
+
y : array_like
|
|
609
|
+
Responses, length n.
|
|
610
|
+
|
|
611
|
+
Attributes
|
|
612
|
+
----------
|
|
613
|
+
net : Numerics.MachineLearning.ElasticNetRegression
|
|
614
|
+
The wrapped .NET object.
|
|
615
|
+
|
|
616
|
+
Notes
|
|
617
|
+
-----
|
|
618
|
+
Follows glmnet: for each penalty lambda the method minimizes
|
|
619
|
+
``1/(2n) sum (y - b0 - x b)**2 + lambda sum v_j ((1 - alpha)/2 b_j**2 + alpha |b_j|)`` with the
|
|
620
|
+
predictors and the response standardized. Set the options before :meth:`fit`.
|
|
621
|
+
"""
|
|
622
|
+
|
|
623
|
+
def __init__(self, x: Any, y: Any) -> None:
|
|
624
|
+
self.net = _net_type("ElasticNetRegression")(_net_columns(x), to_net_doubles(y))
|
|
625
|
+
|
|
626
|
+
def fit(self) -> None:
|
|
627
|
+
"""Fit the coefficient path (``Fit``)."""
|
|
628
|
+
self.net.Fit()
|
|
629
|
+
|
|
630
|
+
def cross_validate(self, folds: int = 10, seed: int = 12345, fold_ids: Any = None) -> None:
|
|
631
|
+
"""Run k-fold cross-validation over the path, fitting it first if needed (``CrossValidate``).
|
|
632
|
+
|
|
633
|
+
Parameters
|
|
634
|
+
----------
|
|
635
|
+
folds : int, optional
|
|
636
|
+
Number of folds, at least 3; default 10. Ignored with ``fold_ids``.
|
|
637
|
+
seed : int, optional
|
|
638
|
+
Seed of the random fold assignment; default 12345. Ignored with ``fold_ids``.
|
|
639
|
+
fold_ids : array_like of int, optional
|
|
640
|
+
The fold label of each observation, at least three distinct labels.
|
|
641
|
+
"""
|
|
642
|
+
if fold_ids is None:
|
|
643
|
+
self.net.CrossValidate(int(folds), int(seed))
|
|
644
|
+
else:
|
|
645
|
+
self.net.CrossValidate(to_net_ints(fold_ids))
|
|
646
|
+
|
|
647
|
+
def get_coefficients(self, index: int) -> np.ndarray:
|
|
648
|
+
"""Return the coefficients, without the intercept, at a penalty on the path (``GetCoefficients``).
|
|
649
|
+
|
|
650
|
+
Parameters
|
|
651
|
+
----------
|
|
652
|
+
index : int
|
|
653
|
+
Penalty index.
|
|
654
|
+
|
|
655
|
+
Returns
|
|
656
|
+
-------
|
|
657
|
+
numpy.ndarray
|
|
658
|
+
The p coefficients on the original scale.
|
|
659
|
+
"""
|
|
660
|
+
return to_numpy_doubles(self.net.GetCoefficients(int(index)))
|
|
661
|
+
|
|
662
|
+
def selected_variables(self, index: int) -> np.ndarray:
|
|
663
|
+
"""Return the indexes of the nonzero coefficients at a penalty (``SelectedVariables``).
|
|
664
|
+
|
|
665
|
+
Parameters
|
|
666
|
+
----------
|
|
667
|
+
index : int
|
|
668
|
+
Penalty index.
|
|
669
|
+
|
|
670
|
+
Returns
|
|
671
|
+
-------
|
|
672
|
+
numpy.ndarray
|
|
673
|
+
Predictor indexes in increasing order, int32.
|
|
674
|
+
"""
|
|
675
|
+
return to_numpy_ints(self.net.SelectedVariables(int(index)))
|
|
676
|
+
|
|
677
|
+
def predict(self, x: Any, index: int) -> np.ndarray | float:
|
|
678
|
+
"""Return the prediction at a penalty on the path (``Predict``).
|
|
679
|
+
|
|
680
|
+
Parameters
|
|
681
|
+
----------
|
|
682
|
+
x : array_like
|
|
683
|
+
Predictors, shape (m, p), or a 1-D array of the p values of one observation.
|
|
684
|
+
index : int
|
|
685
|
+
Penalty index.
|
|
686
|
+
|
|
687
|
+
Returns
|
|
688
|
+
-------
|
|
689
|
+
numpy.ndarray or float
|
|
690
|
+
The m predictions, or one prediction for a 1-D ``x``.
|
|
691
|
+
"""
|
|
692
|
+
array = np.asarray(x, dtype=np.float64)
|
|
693
|
+
if array.ndim == 1:
|
|
694
|
+
return float(self.net.Predict(to_net_doubles(array), int(index)))
|
|
695
|
+
return to_numpy_doubles(self.net.Predict(to_net_matrix(array), int(index)))
|
|
696
|
+
|
|
697
|
+
alpha = _member("Alpha", float, "Mixing parameter in [0, 1]: 1 is the lasso (default), 0 ridge.", float)
|
|
698
|
+
number_of_lambdas = _member("NumberOfLambdas", int, "Number of penalties on the default path (100).", int)
|
|
699
|
+
lambda_min_ratio = _member("LambdaMinRatio", float,
|
|
700
|
+
"Smallest penalty as a fraction of lambda_max; NaN selects the glmnet default.", float)
|
|
701
|
+
user_lambdas = _member("UserLambdas", _doubles, "User penalty sequence, or None for the default path.",
|
|
702
|
+
_optional_doubles)
|
|
703
|
+
standardize = _member("Standardize", bool, "Whether the predictors are standardized (default True).", bool)
|
|
704
|
+
has_intercept = _member("HasIntercept", bool, "Whether an intercept is fitted (default True).", bool)
|
|
705
|
+
tolerance = _member("Tolerance", float, "Coordinate descent convergence tolerance (default 1e-7).", float)
|
|
706
|
+
max_iterations = _member("MaxIterations", int, "Maximum number of coordinate passes (default 100000).", int)
|
|
707
|
+
penalty_factors = _member("PenaltyFactors", _doubles, "Per-predictor penalty factors, or None for ones.",
|
|
708
|
+
_optional_doubles)
|
|
709
|
+
sample_size = _member("SampleSize", int, "Number of observations n.")
|
|
710
|
+
number_of_predictors = _member("NumberOfPredictors", int, "Number of predictors p.")
|
|
711
|
+
is_fitted = _member("IsFitted", bool, "Whether the path has been fitted.")
|
|
712
|
+
converged = _member("Converged", bool, "Whether every penalty converged.")
|
|
713
|
+
iterations = _member("Iterations", int, "Total number of coordinate passes.")
|
|
714
|
+
lambdas = _member("Lambdas", _doubles, "Penalties on the fitted path.")
|
|
715
|
+
intercepts = _member("Intercepts", _doubles, "Intercept at each penalty.")
|
|
716
|
+
coefficients = _member("Coefficients", _matrix, "Coefficients on the original scale, shape (penalties, p).")
|
|
717
|
+
deviance_ratio = _member("DevianceRatio", _doubles, "Fraction of deviance explained at each penalty.")
|
|
718
|
+
nonzero_count = _member("NonzeroCount", _ints, "Number of nonzero coefficients at each penalty.")
|
|
719
|
+
is_cross_validated = _member("IsCrossValidated", bool, "Whether cross-validation has run.")
|
|
720
|
+
fold_ids = _member("FoldIds", _ints, "Fold label of each observation used by cross-validation.")
|
|
721
|
+
cross_validation_error = _member("CrossValidationError", _doubles, "Mean squared prediction error per penalty.")
|
|
722
|
+
cross_validation_standard_error = _member("CrossValidationStandardError", _doubles,
|
|
723
|
+
"Standard error of the cross-validation error per penalty.")
|
|
724
|
+
lambda_min_index = _member("LambdaMinIndex", int, "Index of the penalty with the smallest error; -1 before.")
|
|
725
|
+
lambda_one_standard_error_index = _member("LambdaOneStandardErrorIndex", int,
|
|
726
|
+
"Index of the largest penalty within one standard error; -1 before.")
|
|
727
|
+
lambda_min = _member("LambdaMin", float, "Penalty with the smallest cross-validation error.")
|
|
728
|
+
lambda_one_standard_error = _member("LambdaOneStandardError", float,
|
|
729
|
+
"Largest penalty within one standard error of the minimum.")
|
|
730
|
+
x = _member("X", _matrix, "Predictors, shape (n, p).")
|
|
731
|
+
y = _member("Y", _doubles, "Responses.")
|
|
732
|
+
|
|
733
|
+
|
|
734
|
+
def _gpr_predict_interval() -> Any:
|
|
735
|
+
"""Return ``GaussianProcessRegression.Predict(Matrix, double, bool)``, bound once."""
|
|
736
|
+
def factory() -> Any:
|
|
737
|
+
import System # noqa: PLC0415 - the runtime is running
|
|
738
|
+
|
|
739
|
+
matrix = namespace("Numerics.Mathematics.LinearAlgebra").Matrix
|
|
740
|
+
signature = (matrix, System.Double, System.Boolean)
|
|
741
|
+
return _net_type("GaussianProcessRegression").Predict.Overloads[signature]
|
|
742
|
+
|
|
743
|
+
return cached_overload("GaussianProcessRegression.Predict(Matrix, double, bool)", factory)
|
|
744
|
+
|
|
745
|
+
|
|
746
|
+
class GaussianProcessRegression(_NetModel):
|
|
747
|
+
"""Exact Gaussian process regression (``Numerics.MachineLearning.GaussianProcessRegression``).
|
|
748
|
+
|
|
749
|
+
Parameters
|
|
750
|
+
----------
|
|
751
|
+
x : array_like
|
|
752
|
+
Training features, shape (n, d); a 1-D array is one feature.
|
|
753
|
+
y : array_like
|
|
754
|
+
Training responses, length n.
|
|
755
|
+
kernel : GaussianProcessKernel or str, optional
|
|
756
|
+
Covariance function; default Matern 5/2.
|
|
757
|
+
mean : GaussianProcessMean or str, optional
|
|
758
|
+
Mean function, estimated by generalized least squares; default constant.
|
|
759
|
+
|
|
760
|
+
Attributes
|
|
761
|
+
----------
|
|
762
|
+
net : Numerics.MachineLearning.GaussianProcessRegression
|
|
763
|
+
The wrapped .NET object.
|
|
764
|
+
|
|
765
|
+
Notes
|
|
766
|
+
-----
|
|
767
|
+
The covariance is ``signal_variance * rho(r) + noise_variance * I`` with the scaled distance
|
|
768
|
+
``r`` (one length scale per feature when :attr:`use_ard`). :meth:`train` maximizes the log
|
|
769
|
+
marginal likelihood with L-BFGS-B; :meth:`set_hyperparameters` conditions on fixed values.
|
|
770
|
+
"""
|
|
771
|
+
|
|
772
|
+
def __init__(self, x: Any, y: Any, kernel: GaussianProcessKernel | str = GaussianProcessKernel.MATERN52,
|
|
773
|
+
mean: GaussianProcessMean | str = GaussianProcessMean.CONSTANT) -> None:
|
|
774
|
+
net_type = _net_type("GaussianProcessRegression")
|
|
775
|
+
ml = namespace("Numerics.MachineLearning")
|
|
776
|
+
self.net = net_type(_net_columns(x), to_net_doubles(y), net_enum(ml.GaussianProcessKernel, kernel),
|
|
777
|
+
net_enum(ml.GaussianProcessMean, mean))
|
|
778
|
+
|
|
779
|
+
def train(self, noise_variance: float | None = None) -> None:
|
|
780
|
+
"""Estimate the hyperparameters by maximum marginal likelihood (``Train``).
|
|
781
|
+
|
|
782
|
+
Parameters
|
|
783
|
+
----------
|
|
784
|
+
noise_variance : float, optional
|
|
785
|
+
When given, the noise variance is held at this value (zero interpolates); otherwise it is
|
|
786
|
+
estimated with the other hyperparameters.
|
|
787
|
+
"""
|
|
788
|
+
if noise_variance is None:
|
|
789
|
+
self.net.Train()
|
|
790
|
+
else:
|
|
791
|
+
self.net.Train(float(noise_variance))
|
|
792
|
+
|
|
793
|
+
def set_hyperparameters(self, signal_variance: float, length_scales: Any, noise_variance: float) -> None:
|
|
794
|
+
"""Set the hyperparameters without optimization and condition on the data (``SetHyperparameters``).
|
|
795
|
+
|
|
796
|
+
Parameters
|
|
797
|
+
----------
|
|
798
|
+
signal_variance : float
|
|
799
|
+
Signal variance, positive.
|
|
800
|
+
length_scales : float or array_like
|
|
801
|
+
One shared length scale, or one per feature (which turns :attr:`use_ard` on).
|
|
802
|
+
noise_variance : float
|
|
803
|
+
Noise variance, non-negative.
|
|
804
|
+
"""
|
|
805
|
+
self.net.SetHyperparameters(float(signal_variance), to_net_doubles(length_scales), float(noise_variance))
|
|
806
|
+
|
|
807
|
+
def evaluate_log_marginal_likelihood(self, theta: Any, gradient: bool = False) -> float | tuple[float, np.ndarray]:
|
|
808
|
+
"""Return the log marginal likelihood at log hyperparameters (``EvaluateLogMarginalLikelihood``).
|
|
809
|
+
|
|
810
|
+
Parameters
|
|
811
|
+
----------
|
|
812
|
+
theta : array_like
|
|
813
|
+
``(ln signal_variance, ln l_1, ..., ln l_q, ln noise_variance)`` with q = d under ARD, else 1.
|
|
814
|
+
gradient : bool, optional
|
|
815
|
+
Whether to also return the gradient.
|
|
816
|
+
|
|
817
|
+
Returns
|
|
818
|
+
-------
|
|
819
|
+
float or tuple of (float, numpy.ndarray)
|
|
820
|
+
The log marginal likelihood (NaN when the covariance cannot be factored), and with
|
|
821
|
+
``gradient`` its gradient with respect to ``theta``.
|
|
822
|
+
"""
|
|
823
|
+
net_theta = to_net_doubles(theta)
|
|
824
|
+
if not gradient:
|
|
825
|
+
return float(self.net.EvaluateLogMarginalLikelihood(net_theta, None))
|
|
826
|
+
import System # noqa: PLC0415 - the runtime is running
|
|
827
|
+
|
|
828
|
+
out = System.Array[System.Double](int(net_theta.Length))
|
|
829
|
+
value = float(self.net.EvaluateLogMarginalLikelihood(net_theta, out))
|
|
830
|
+
return value, to_numpy_doubles(out)
|
|
831
|
+
|
|
832
|
+
def predict(self, x: Any, alpha: float | None = None, include_noise: bool = False) -> np.ndarray:
|
|
833
|
+
"""Return the predictive mean, optionally with a central interval (``Predict``).
|
|
834
|
+
|
|
835
|
+
Parameters
|
|
836
|
+
----------
|
|
837
|
+
x : array_like
|
|
838
|
+
Prediction points, shape (m, d); a 1-D array is one feature.
|
|
839
|
+
alpha : float, optional
|
|
840
|
+
When given, one minus the interval coverage.
|
|
841
|
+
include_noise : bool, optional
|
|
842
|
+
With ``alpha``, whether the interval covers a new noisy observation; default False.
|
|
843
|
+
|
|
844
|
+
Returns
|
|
845
|
+
-------
|
|
846
|
+
numpy.ndarray
|
|
847
|
+
The m means, or with ``alpha`` shape (m, 3) with columns lower, mean and upper.
|
|
848
|
+
"""
|
|
849
|
+
if alpha is None:
|
|
850
|
+
return to_numpy_doubles(self.net.Predict(_net_columns(x)))
|
|
851
|
+
matrix = _numerics_matrix(_columns(x))
|
|
852
|
+
return to_numpy_matrix(_gpr_predict_interval()(self.net, matrix, float(alpha), bool(include_noise)))
|
|
853
|
+
|
|
854
|
+
def predict_with_variance(self, x: Any, include_noise: bool = False) -> tuple[np.ndarray, np.ndarray]:
|
|
855
|
+
"""Return the predictive mean and variance (``PredictWithVariance``).
|
|
856
|
+
|
|
857
|
+
Parameters
|
|
858
|
+
----------
|
|
859
|
+
x : array_like
|
|
860
|
+
Prediction points, shape (m, d); a 1-D array is one feature.
|
|
861
|
+
include_noise : bool, optional
|
|
862
|
+
Whether the variance is that of a new observation (True) or of the latent function.
|
|
863
|
+
|
|
864
|
+
Returns
|
|
865
|
+
-------
|
|
866
|
+
tuple of numpy.ndarray
|
|
867
|
+
The m means and the m variances.
|
|
868
|
+
"""
|
|
869
|
+
return _pair(self.net.PredictWithVariance(_net_columns(x), bool(include_noise)))
|
|
870
|
+
|
|
871
|
+
def leave_one_out(self) -> tuple[np.ndarray, np.ndarray]:
|
|
872
|
+
"""Return the leave-one-out predictive mean and variance of each response (``LeaveOneOut``).
|
|
873
|
+
|
|
874
|
+
Returns
|
|
875
|
+
-------
|
|
876
|
+
tuple of numpy.ndarray
|
|
877
|
+
The n means and the n variances (the variances include the noise).
|
|
878
|
+
"""
|
|
879
|
+
return _pair(self.net.LeaveOneOut())
|
|
880
|
+
|
|
881
|
+
use_ard = _member("UseARD", bool, "One length scale per feature (default True).", bool)
|
|
882
|
+
number_of_restarts = _member("NumberOfRestarts", int, "Random optimizer restarts beyond the two data starts.", int)
|
|
883
|
+
prng_seed = _member("PRNGSeed", int, "Seed of the random restarts (default 12345).", int)
|
|
884
|
+
max_iterations = _member("MaxIterations", int, "Maximum optimizer iterations per start (default 200).", int)
|
|
885
|
+
tolerance = _member("Tolerance", float, "Projected gradient tolerance (default 1e-5).", float)
|
|
886
|
+
sample_size = _member("SampleSize", int, "Number of observations n.")
|
|
887
|
+
number_of_features = _member("NumberOfFeatures", int, "Number of features d.")
|
|
888
|
+
signal_variance = _member("SignalVariance", float, "Signal variance.")
|
|
889
|
+
length_scales = _member("LengthScales", _doubles, "Length scales.")
|
|
890
|
+
noise_variance = _member("NoiseVariance", float, "Noise variance.")
|
|
891
|
+
jitter = _member("Jitter", float, "Diagonal jitter added to factor the covariance.")
|
|
892
|
+
mean_coefficients = _member("MeanCoefficients", _doubles, "Generalized least squares mean coefficients.")
|
|
893
|
+
log_marginal_likelihood = _member("LogMarginalLikelihood", float, "Log marginal likelihood after training.")
|
|
894
|
+
status = _member("Status", str, "``OptimizationStatus`` member name of the last training.")
|
|
895
|
+
is_trained = _member("IsTrained", bool, "Whether the model is conditioned on the data.")
|
|
896
|
+
|
|
897
|
+
@property
|
|
898
|
+
def kernel(self) -> GaussianProcessKernel:
|
|
899
|
+
"""Covariance function."""
|
|
900
|
+
return GaussianProcessKernel(str(self.net.Kernel))
|
|
901
|
+
|
|
902
|
+
@property
|
|
903
|
+
def mean_function(self) -> GaussianProcessMean:
|
|
904
|
+
"""Mean function."""
|
|
905
|
+
return GaussianProcessMean(str(self.net.MeanFunction))
|
|
906
|
+
|
|
907
|
+
|
|
908
|
+
class Kriging(_NetModel):
|
|
909
|
+
"""Simple, ordinary and universal kriging with a variogram model (``Numerics.MachineLearning.Kriging``).
|
|
910
|
+
|
|
911
|
+
Parameters
|
|
912
|
+
----------
|
|
913
|
+
coordinates : array_like
|
|
914
|
+
Observation locations, shape (n, d); a 1-D array is one coordinate.
|
|
915
|
+
values : array_like
|
|
916
|
+
Observed values, length n.
|
|
917
|
+
model : VariogramModel or str
|
|
918
|
+
Variogram model.
|
|
919
|
+
nugget : float
|
|
920
|
+
Nugget c0, non-negative.
|
|
921
|
+
partial_sill : float
|
|
922
|
+
Partial sill c, positive.
|
|
923
|
+
range : float
|
|
924
|
+
Range parameter a (gstat ``vgm`` convention), positive.
|
|
925
|
+
kriging_type : KrigingType or str, optional
|
|
926
|
+
Kriging variant; default ordinary.
|
|
927
|
+
mean : float, optional
|
|
928
|
+
Known mean for simple kriging; default 0.
|
|
929
|
+
distance : callable, str or System.Delegate, optional
|
|
930
|
+
Distance between two locations, ``distance(a, b) -> float``, as a Python callable, C# source
|
|
931
|
+
or a ``Func<double[], double[], double>``; default Euclidean.
|
|
932
|
+
|
|
933
|
+
Attributes
|
|
934
|
+
----------
|
|
935
|
+
net : Numerics.MachineLearning.Kriging
|
|
936
|
+
The wrapped .NET object.
|
|
937
|
+
"""
|
|
938
|
+
|
|
939
|
+
def __init__(self, coordinates: Any, values: Any, model: VariogramModel | str, nugget: float,
|
|
940
|
+
partial_sill: float, range: float, kriging_type: KrigingType | str = KrigingType.ORDINARY,
|
|
941
|
+
mean: float = 0.0, distance: Any = None) -> None:
|
|
942
|
+
net_type = _net_type("Kriging")
|
|
943
|
+
ml = namespace("Numerics.MachineLearning")
|
|
944
|
+
head = (_net_columns(coordinates), to_net_doubles(values), net_enum(ml.VariogramModel, model),
|
|
945
|
+
float(nugget), float(partial_sill), float(range))
|
|
946
|
+
tail = (net_enum(ml.KrigingType, kriging_type), float(mean))
|
|
947
|
+
if distance is None:
|
|
948
|
+
self.net = net_type(*head, *tail)
|
|
949
|
+
else:
|
|
950
|
+
function = callbacks.to_delegate(distance, "Func<double[],double[],double>")
|
|
951
|
+
self.net = net_type(*head, function, *tail)
|
|
952
|
+
callbacks.apply_parallel_policy(self.net, function)
|
|
953
|
+
|
|
954
|
+
def semivariance(self, h: Any) -> Any:
|
|
955
|
+
"""Return the variogram at lag distance ``h`` (``Semivariance``).
|
|
956
|
+
|
|
957
|
+
Parameters
|
|
958
|
+
----------
|
|
959
|
+
h : float or array_like
|
|
960
|
+
Lag distances, non-negative.
|
|
961
|
+
|
|
962
|
+
Returns
|
|
963
|
+
-------
|
|
964
|
+
float or numpy.ndarray
|
|
965
|
+
``gamma(h)``, zero at h = 0.
|
|
966
|
+
"""
|
|
967
|
+
return loop(h, self.net.Semivariance)
|
|
968
|
+
|
|
969
|
+
def covariance(self, h: Any) -> Any:
|
|
970
|
+
"""Return the covariance at lag distance ``h`` (``Covariance``).
|
|
971
|
+
|
|
972
|
+
Parameters
|
|
973
|
+
----------
|
|
974
|
+
h : float or array_like
|
|
975
|
+
Lag distances, non-negative.
|
|
976
|
+
|
|
977
|
+
Returns
|
|
978
|
+
-------
|
|
979
|
+
float or numpy.ndarray
|
|
980
|
+
``C(h)``, the sill at h = 0.
|
|
981
|
+
"""
|
|
982
|
+
return loop(h, self.net.Covariance)
|
|
983
|
+
|
|
984
|
+
def predict(self, x: Any) -> np.ndarray:
|
|
985
|
+
"""Return the kriging predictor at each location (``Predict``).
|
|
986
|
+
|
|
987
|
+
Parameters
|
|
988
|
+
----------
|
|
989
|
+
x : array_like
|
|
990
|
+
Locations, shape (m, d); a 1-D array is one coordinate.
|
|
991
|
+
|
|
992
|
+
Returns
|
|
993
|
+
-------
|
|
994
|
+
numpy.ndarray
|
|
995
|
+
The m predictions.
|
|
996
|
+
"""
|
|
997
|
+
return to_numpy_doubles(self.net.Predict(_net_columns(x)))
|
|
998
|
+
|
|
999
|
+
def predict_with_variance(self, x: Any) -> tuple[np.ndarray, np.ndarray] | tuple[float, float]:
|
|
1000
|
+
"""Return the kriging predictor and kriging variance (``PredictWithVariance``).
|
|
1001
|
+
|
|
1002
|
+
Parameters
|
|
1003
|
+
----------
|
|
1004
|
+
x : array_like
|
|
1005
|
+
Locations, shape (m, d), or a 1-D array holding the d coordinates of one location.
|
|
1006
|
+
|
|
1007
|
+
Returns
|
|
1008
|
+
-------
|
|
1009
|
+
tuple
|
|
1010
|
+
The m predictions and m variances, or a (mean, variance) pair of floats for one location.
|
|
1011
|
+
"""
|
|
1012
|
+
array = np.asarray(x, dtype=np.float64)
|
|
1013
|
+
if array.ndim == 1:
|
|
1014
|
+
result = self.net.PredictWithVariance(to_net_doubles(array))
|
|
1015
|
+
return float(result.Item1), float(result.Item2)
|
|
1016
|
+
return _pair(self.net.PredictWithVariance(to_net_matrix(array)))
|
|
1017
|
+
|
|
1018
|
+
def cross_validate(self) -> tuple[np.ndarray, np.ndarray]:
|
|
1019
|
+
"""Return the leave-one-out prediction and variance at each observation (``CrossValidate``).
|
|
1020
|
+
|
|
1021
|
+
Returns
|
|
1022
|
+
-------
|
|
1023
|
+
tuple of numpy.ndarray
|
|
1024
|
+
The n predictions and the n variances.
|
|
1025
|
+
"""
|
|
1026
|
+
return _pair(self.net.CrossValidate())
|
|
1027
|
+
|
|
1028
|
+
nugget = _member("Nugget", float, "Nugget c0.")
|
|
1029
|
+
partial_sill = _member("PartialSill", float, "Partial sill c.")
|
|
1030
|
+
sill = _member("Sill", float, "Sill c0 + c.")
|
|
1031
|
+
range = _member("Range", float, "Range parameter a.")
|
|
1032
|
+
known_mean = _member("KnownMean", float, "Known mean of simple kriging; NaN otherwise.")
|
|
1033
|
+
sample_size = _member("SampleSize", int, "Number of observations n.")
|
|
1034
|
+
number_of_dimensions = _member("NumberOfDimensions", int, "Number of coordinates d.")
|
|
1035
|
+
trend_coefficients = _member("TrendCoefficients", _doubles, "Estimated trend coefficients (empty for simple).")
|
|
1036
|
+
|
|
1037
|
+
@property
|
|
1038
|
+
def model(self) -> VariogramModel:
|
|
1039
|
+
"""Variogram model."""
|
|
1040
|
+
return VariogramModel(str(self.net.Model))
|
|
1041
|
+
|
|
1042
|
+
@property
|
|
1043
|
+
def kriging_type(self) -> KrigingType:
|
|
1044
|
+
"""Kriging variant."""
|
|
1045
|
+
return KrigingType(str(self.net.Type))
|
|
1046
|
+
|
|
1047
|
+
|
|
1048
|
+
class KMeans(_NetModel):
|
|
1049
|
+
"""The k-means clustering by Lloyd iterations (``Numerics.MachineLearning.KMeans``).
|
|
1050
|
+
|
|
1051
|
+
Parameters
|
|
1052
|
+
----------
|
|
1053
|
+
x : array_like
|
|
1054
|
+
Data, shape (n, d); a 1-D array is one feature.
|
|
1055
|
+
k : int
|
|
1056
|
+
Number of clusters.
|
|
1057
|
+
|
|
1058
|
+
Attributes
|
|
1059
|
+
----------
|
|
1060
|
+
net : Numerics.MachineLearning.KMeans
|
|
1061
|
+
The wrapped .NET object.
|
|
1062
|
+
"""
|
|
1063
|
+
|
|
1064
|
+
def __init__(self, x: Any, k: int) -> None:
|
|
1065
|
+
self.net = _net_type("KMeans")(_net_columns(x), int(k))
|
|
1066
|
+
|
|
1067
|
+
def train(self, seed: int = -1, k_means_plus_plus: bool = True) -> None:
|
|
1068
|
+
"""Cluster the data (``Train``); iterations stop when no label changes.
|
|
1069
|
+
|
|
1070
|
+
Parameters
|
|
1071
|
+
----------
|
|
1072
|
+
seed : int, optional
|
|
1073
|
+
Mersenne Twister seed of the initialization; zero or negative seeds from the clock.
|
|
1074
|
+
k_means_plus_plus : bool, optional
|
|
1075
|
+
The k-means++ seeding (default) or k distinct random rows.
|
|
1076
|
+
"""
|
|
1077
|
+
self.net.Train(int(seed), bool(k_means_plus_plus))
|
|
1078
|
+
|
|
1079
|
+
@staticmethod
|
|
1080
|
+
def initialize(x: Any, k: int, seed: int = -1, k_means_plus_plus: bool = True) -> np.ndarray:
|
|
1081
|
+
"""Return the initial centroids :meth:`train` starts from (``Initialize``).
|
|
1082
|
+
|
|
1083
|
+
Parameters
|
|
1084
|
+
----------
|
|
1085
|
+
x : array_like
|
|
1086
|
+
Data, shape (n, d); a 1-D array is one feature.
|
|
1087
|
+
k : int
|
|
1088
|
+
Number of clusters.
|
|
1089
|
+
seed : int, optional
|
|
1090
|
+
Mersenne Twister seed; zero or negative seeds from the clock.
|
|
1091
|
+
k_means_plus_plus : bool, optional
|
|
1092
|
+
The k-means++ seeding (default) or k distinct random rows.
|
|
1093
|
+
|
|
1094
|
+
Returns
|
|
1095
|
+
-------
|
|
1096
|
+
numpy.ndarray
|
|
1097
|
+
Shape (k, d).
|
|
1098
|
+
"""
|
|
1099
|
+
net_type = _net_type("KMeans")
|
|
1100
|
+
matrix = _numerics_matrix(_columns(x))
|
|
1101
|
+
return to_numpy_matrix(net_type.Initialize(matrix, int(k), int(seed), bool(k_means_plus_plus)))
|
|
1102
|
+
|
|
1103
|
+
k = _member("K", int, "Number of clusters.")
|
|
1104
|
+
dimension = _member("Dimension", int, "Number of features d.")
|
|
1105
|
+
max_iterations = _member("MaxIterations", int, "Maximum number of iterations (default 1000).", int)
|
|
1106
|
+
iterations = _member("Iterations", int, "Number of iterations of the last training.")
|
|
1107
|
+
means = _member("Means", _matrix, "Cluster centroids, shape (k, d).")
|
|
1108
|
+
labels = _member("Labels", _ints, "Cluster label of each row.")
|
|
1109
|
+
x = _member("X", _matrix, "Data, shape (n, d).")
|
|
1110
|
+
|
|
1111
|
+
|
|
1112
|
+
class GaussianMixtureModel(_NetModel):
|
|
1113
|
+
"""Gaussian mixture model fitted by expectation maximization (``Numerics.MachineLearning.GaussianMixtureModel``).
|
|
1114
|
+
|
|
1115
|
+
Parameters
|
|
1116
|
+
----------
|
|
1117
|
+
x : array_like
|
|
1118
|
+
Data, shape (n, d); a 1-D array is one feature.
|
|
1119
|
+
k : int
|
|
1120
|
+
Number of components.
|
|
1121
|
+
|
|
1122
|
+
Attributes
|
|
1123
|
+
----------
|
|
1124
|
+
net : Numerics.MachineLearning.GaussianMixtureModel
|
|
1125
|
+
The wrapped .NET object.
|
|
1126
|
+
|
|
1127
|
+
Notes
|
|
1128
|
+
-----
|
|
1129
|
+
The components start from a k-means fit with the same seed, with full covariance matrices.
|
|
1130
|
+
"""
|
|
1131
|
+
|
|
1132
|
+
def __init__(self, x: Any, k: int) -> None:
|
|
1133
|
+
self.net = _net_type("GaussianMixtureModel")(_net_columns(x), int(k))
|
|
1134
|
+
|
|
1135
|
+
def train(self, seed: int = -1, k_means_plus_plus: bool = True) -> None:
|
|
1136
|
+
"""Fit the mixture (``Train``).
|
|
1137
|
+
|
|
1138
|
+
Parameters
|
|
1139
|
+
----------
|
|
1140
|
+
seed : int, optional
|
|
1141
|
+
Seed of the k-means initialization; zero or negative seeds from the clock.
|
|
1142
|
+
k_means_plus_plus : bool, optional
|
|
1143
|
+
The k-means++ seeding (default) or random rows.
|
|
1144
|
+
"""
|
|
1145
|
+
self.net.Train(int(seed), bool(k_means_plus_plus))
|
|
1146
|
+
|
|
1147
|
+
@property
|
|
1148
|
+
def sigmas(self) -> np.ndarray | None:
|
|
1149
|
+
"""Component covariance matrices, shape (k, d, d)."""
|
|
1150
|
+
sigmas = self.net.Sigmas
|
|
1151
|
+
return None if sigmas is None else np.stack([to_numpy_matrix(s.Array) for s in sigmas])
|
|
1152
|
+
|
|
1153
|
+
k = _member("K", int, "Number of components.")
|
|
1154
|
+
dimension = _member("Dimension", int, "Number of features d.")
|
|
1155
|
+
max_iterations = _member("MaxIterations", int, "Maximum number of EM iterations (default 1000).", int)
|
|
1156
|
+
tolerance = _member("Tolerance", float, "Log-likelihood convergence tolerance (default 1e-8).", float)
|
|
1157
|
+
iterations = _member("Iterations", int, "Number of EM iterations of the last training.")
|
|
1158
|
+
means = _member("Means", _matrix, "Component means, shape (k, d).")
|
|
1159
|
+
weights = _member("Weights", _doubles, "Component weights.")
|
|
1160
|
+
labels = _member("Labels", _ints, "Most likely component of each row.")
|
|
1161
|
+
likelihood_matrix = _member("LikelihoodMatrix", _matrix, "Component membership probabilities, shape (n, k).")
|
|
1162
|
+
log_likelihood = _member("LogLikelihood", float, "Log-likelihood of the fitted mixture.")
|
|
1163
|
+
x = _member("X", _matrix, "Data, shape (n, d).")
|
|
1164
|
+
|
|
1165
|
+
|
|
1166
|
+
class JenksCluster(_NetModel):
|
|
1167
|
+
"""One class of a Jenks natural breaks classification (``Numerics.MachineLearning.JenksCluster``).
|
|
1168
|
+
|
|
1169
|
+
Parameters
|
|
1170
|
+
----------
|
|
1171
|
+
data : array_like
|
|
1172
|
+
Sorted data.
|
|
1173
|
+
start_index : int
|
|
1174
|
+
Index of the first value of the cluster.
|
|
1175
|
+
end_index : int
|
|
1176
|
+
Index of the last value of the cluster (inclusive).
|
|
1177
|
+
|
|
1178
|
+
Attributes
|
|
1179
|
+
----------
|
|
1180
|
+
net : Numerics.MachineLearning.JenksCluster
|
|
1181
|
+
The wrapped .NET object.
|
|
1182
|
+
"""
|
|
1183
|
+
|
|
1184
|
+
def __init__(self, data: Any, start_index: int, end_index: int) -> None:
|
|
1185
|
+
self.net = _net_type("JenksCluster")(to_net_doubles(data), int(start_index), int(end_index))
|
|
1186
|
+
|
|
1187
|
+
start_index = _member("StartIndex", int, "Index of the first value.")
|
|
1188
|
+
end_index = _member("EndIndex", int, "Index of the last value (inclusive).")
|
|
1189
|
+
count = _member("Count", int, "Number of values.")
|
|
1190
|
+
min_value = _member("MinValue", float, "Smallest value.")
|
|
1191
|
+
max_value = _member("MaxValue", float, "Largest value.")
|
|
1192
|
+
sum = _member("Sum", float, "Sum of the values.")
|
|
1193
|
+
average = _member("Average", float, "Mean of the values.")
|
|
1194
|
+
variance = _member("Variance", float, "Sample variance (n - 1 divisor; zero for one value).")
|
|
1195
|
+
sum_of_squared_deviations = _member("SumOfSquaredDeviations", float, "Sum of squared deviations from the mean.")
|
|
1196
|
+
|
|
1197
|
+
|
|
1198
|
+
class JenksNaturalBreaks(_NetModel):
|
|
1199
|
+
"""Jenks natural breaks optimization (``Numerics.MachineLearning.JenksNaturalBreaks``).
|
|
1200
|
+
|
|
1201
|
+
Parameters
|
|
1202
|
+
----------
|
|
1203
|
+
data : array_like
|
|
1204
|
+
Values to classify.
|
|
1205
|
+
number_of_clusters : int
|
|
1206
|
+
Number of classes.
|
|
1207
|
+
is_data_sorted : bool, optional
|
|
1208
|
+
Whether ``data`` is already sorted ascending; default False.
|
|
1209
|
+
|
|
1210
|
+
Attributes
|
|
1211
|
+
----------
|
|
1212
|
+
net : Numerics.MachineLearning.JenksNaturalBreaks
|
|
1213
|
+
The wrapped .NET object.
|
|
1214
|
+
|
|
1215
|
+
Notes
|
|
1216
|
+
-----
|
|
1217
|
+
The classification is computed by the constructor: it minimizes the total within-class sum of
|
|
1218
|
+
squared deviations over contiguous classes of the sorted data.
|
|
1219
|
+
"""
|
|
1220
|
+
|
|
1221
|
+
def __init__(self, data: Any, number_of_clusters: int, is_data_sorted: bool = False) -> None:
|
|
1222
|
+
self.net = _net_type("JenksNaturalBreaks")(to_net_doubles(data), int(number_of_clusters), bool(is_data_sorted))
|
|
1223
|
+
|
|
1224
|
+
sorted_data = _member("SortedData", _doubles, "The data sorted ascending.")
|
|
1225
|
+
number_of_clusters = _member("NumberOfClusters", int, "Number of classes.")
|
|
1226
|
+
breaks = _member("Breaks", _doubles, "Break points.")
|
|
1227
|
+
goodness_of_variance_fit = _member("GoodnessOfVarianceFit", float,
|
|
1228
|
+
"Goodness of variance fit, 1 - SDCM / SDAM; closer to 1 is better.")
|
|
1229
|
+
|
|
1230
|
+
@property
|
|
1231
|
+
def clusters(self) -> list[JenksCluster]:
|
|
1232
|
+
"""The classes, in ascending order."""
|
|
1233
|
+
clusters = self.net.Clusters
|
|
1234
|
+
return [] if clusters is None else [JenksCluster._wrap(cluster) for cluster in clusters]
|
|
1235
|
+
|
|
1236
|
+
|
|
1237
|
+
class PrincipalComponentAnalysis(_NetModel):
|
|
1238
|
+
"""Principal component analysis (``Numerics.MachineLearning.PrincipalComponentAnalysis``).
|
|
1239
|
+
|
|
1240
|
+
Parameters
|
|
1241
|
+
----------
|
|
1242
|
+
x : array_like
|
|
1243
|
+
Data, shape (n, p), observations in rows.
|
|
1244
|
+
basis : PrincipalComponentBasis or str, optional
|
|
1245
|
+
Covariance (default, centered) or correlation (centered and scaled) basis.
|
|
1246
|
+
number_of_components : int, optional
|
|
1247
|
+
Components to retain; zero or negative (default) retains min(n, p).
|
|
1248
|
+
|
|
1249
|
+
Attributes
|
|
1250
|
+
----------
|
|
1251
|
+
net : Numerics.MachineLearning.PrincipalComponentAnalysis
|
|
1252
|
+
The wrapped .NET object.
|
|
1253
|
+
|
|
1254
|
+
Notes
|
|
1255
|
+
-----
|
|
1256
|
+
Each principal axis is oriented so that its element of largest magnitude is positive, the
|
|
1257
|
+
scikit-learn convention. Variances use the n - 1 divisor.
|
|
1258
|
+
"""
|
|
1259
|
+
|
|
1260
|
+
def __init__(self, x: Any, basis: PrincipalComponentBasis | str = PrincipalComponentBasis.COVARIANCE,
|
|
1261
|
+
number_of_components: int = 0) -> None:
|
|
1262
|
+
net_type = _net_type("PrincipalComponentAnalysis")
|
|
1263
|
+
ml = namespace("Numerics.MachineLearning")
|
|
1264
|
+
self.net = net_type(_net_columns(x), net_enum(ml.PrincipalComponentBasis, basis), int(number_of_components))
|
|
1265
|
+
|
|
1266
|
+
def train(self) -> None:
|
|
1267
|
+
"""Compute the principal components (``Train``)."""
|
|
1268
|
+
self.net.Train()
|
|
1269
|
+
|
|
1270
|
+
def transform(self, x: Any) -> np.ndarray:
|
|
1271
|
+
"""Project data onto the retained components (``Transform``).
|
|
1272
|
+
|
|
1273
|
+
Parameters
|
|
1274
|
+
----------
|
|
1275
|
+
x : array_like
|
|
1276
|
+
Data, shape (m, p), or a 1-D array holding the p values of one observation.
|
|
1277
|
+
|
|
1278
|
+
Returns
|
|
1279
|
+
-------
|
|
1280
|
+
numpy.ndarray
|
|
1281
|
+
Scores, shape (m, k), or length k for one observation.
|
|
1282
|
+
"""
|
|
1283
|
+
array = np.asarray(x, dtype=np.float64)
|
|
1284
|
+
if array.ndim == 1:
|
|
1285
|
+
return to_numpy_doubles(self.net.Transform(to_net_doubles(array)))
|
|
1286
|
+
return to_numpy_matrix(self.net.Transform(to_net_matrix(array)))
|
|
1287
|
+
|
|
1288
|
+
def inverse_transform(self, scores: Any) -> np.ndarray:
|
|
1289
|
+
"""Map component scores back to the data space (``InverseTransform``).
|
|
1290
|
+
|
|
1291
|
+
Parameters
|
|
1292
|
+
----------
|
|
1293
|
+
scores : array_like
|
|
1294
|
+
Scores, shape (m, k), or a 1-D array holding the k scores of one observation.
|
|
1295
|
+
|
|
1296
|
+
Returns
|
|
1297
|
+
-------
|
|
1298
|
+
numpy.ndarray
|
|
1299
|
+
Reconstructed data, shape (m, p), or length p for one observation.
|
|
1300
|
+
"""
|
|
1301
|
+
array = np.asarray(scores, dtype=np.float64)
|
|
1302
|
+
if array.ndim == 1:
|
|
1303
|
+
return to_numpy_doubles(self.net.InverseTransform(to_net_doubles(array)))
|
|
1304
|
+
return to_numpy_matrix(self.net.InverseTransform(to_net_matrix(array)))
|
|
1305
|
+
|
|
1306
|
+
@property
|
|
1307
|
+
def basis(self) -> PrincipalComponentBasis:
|
|
1308
|
+
"""Covariance or correlation basis."""
|
|
1309
|
+
return PrincipalComponentBasis(str(self.net.Basis))
|
|
1310
|
+
|
|
1311
|
+
number_of_samples = _member("NumberOfSamples", int, "Number of observations n.")
|
|
1312
|
+
number_of_features = _member("NumberOfFeatures", int, "Number of variables p.")
|
|
1313
|
+
number_of_components = _member("NumberOfComponents", int, "Number of retained components k.")
|
|
1314
|
+
is_trained = _member("IsTrained", bool, "Whether the analysis has been trained.")
|
|
1315
|
+
means = _member("Means", _doubles, "Column means of the training data.")
|
|
1316
|
+
scales = _member("Scales", _doubles, "Column scales: standard deviations (correlation basis) or ones.")
|
|
1317
|
+
components = _member("Components", _matrix, "Principal axes, shape (k, p); row i is component i.")
|
|
1318
|
+
loadings = _member("Loadings", _matrix, "Loadings, shape (p, k): axes times the square root of the variance.")
|
|
1319
|
+
explained_variance = _member("ExplainedVariance", _doubles, "Variance explained by each component.")
|
|
1320
|
+
explained_variance_ratio = _member("ExplainedVarianceRatio", _doubles, "Fraction of the total variance.")
|
|
1321
|
+
cumulative_explained_variance_ratio = _member("CumulativeExplainedVarianceRatio", _doubles,
|
|
1322
|
+
"Cumulative fraction of the total variance.")
|
|
1323
|
+
singular_values = _member("SingularValues", _doubles, "Singular values of the centered (scaled) data.")
|
|
1324
|
+
total_variance = _member("TotalVariance", float, "Trace of the covariance or correlation matrix.")
|
|
1325
|
+
scores = _member("Scores", _matrix, "Component scores of the training data, shape (n, k).")
|
|
1326
|
+
|
|
1327
|
+
|
|
1328
|
+
__all__ = [
|
|
1329
|
+
"DecisionNode", "DecisionTree", "ElasticNetRegression", "GaussianMixtureModel", "GaussianProcessKernel",
|
|
1330
|
+
"GaussianProcessMean", "GaussianProcessRegression", "GeneralizedLinearModel", "JenksCluster",
|
|
1331
|
+
"JenksNaturalBreaks", "KMeans", "KNearestNeighbors", "Kriging", "KrigingType", "NaiveBayes",
|
|
1332
|
+
"PrincipalComponentAnalysis", "PrincipalComponentBasis", "RandomForest", "VariogramModel",
|
|
1333
|
+
]
|
|
1334
|
+
|
|
1335
|
+
translate_public(globals())
|