nnetsauce

 1from .base.base import Base
 2from .base.baseRegressor import BaseRegressor
 3from .boosting.adaBoostClassifier import AdaBoostClassifier
 4from .custom.customClassifier import CustomClassifier
 5from .custom.customRegressor import CustomRegressor
 6from .datasets import Downloader
 7from .deep.deepClassifier import DeepClassifier
 8from .deep.deepRegressor import DeepRegressor
 9from .deep.deepMTS import DeepMTS
10from .glm.glmClassifier import GLMClassifier
11from .glm.glmRegressor import GLMRegressor
12from .lazypredict.lazydeepClassifier import LazyDeepClassifier, LazyClassifier
13from .lazypredict.lazydeepRegressor import LazyDeepRegressor, LazyRegressor
14from .lazypredict.lazydeepClassifier import LazyDeepClassifier
15from .lazypredict.lazydeepRegressor import LazyDeepRegressor
16from .lazypredict.lazydeepMTS import LazyDeepMTS, LazyMTS
17from .mts.mts import MTS
18from .mts.classical import ClassicalMTS
19from .multitask.multitaskClassifier import MultitaskClassifier
20from .multitask.simplemultitaskClassifier import SimpleMultitaskClassifier
21from .optimizers.optimizer import Optimizer
22from .predictioninterval import PredictionInterval
23from .randombag.randomBagClassifier import RandomBagClassifier
24from .randombag.randomBagRegressor import RandomBagRegressor
25from .ridge2.ridge2Classifier import Ridge2Classifier
26from .ridge2.ridge2Regressor import Ridge2Regressor
27from .ridge2.ridge2MultitaskClassifier import Ridge2MultitaskClassifier
28from .rvfl.bayesianrvflRegressor import BayesianRVFLRegressor
29from .rvfl.bayesianrvfl2Regressor import BayesianRVFL2Regressor
30from .sampling import SubSampler
31from .updater import RegressorUpdater, ClassifierUpdater
32from .votingregressor import MedianVotingRegressor
33
34__all__ = [
35    "AdaBoostClassifier",
36    "Base",
37    "BaseRegressor",
38    "BayesianRVFLRegressor",
39    "BayesianRVFL2Regressor",
40    "ClassicalMTS",
41    "CustomClassifier",
42    "CustomRegressor",
43    "DeepClassifier",
44    "DeepRegressor",
45    "DeepMTS",
46    "Downloader",
47    "GLMClassifier",
48    "GLMRegressor",
49    "LazyClassifier",
50    "LazyRegressor",
51    "LazyDeepClassifier",
52    "LazyDeepRegressor",
53    "LazyMTS",
54    "LazyDeepMTS",
55    "MedianVotingRegressor",
56    "MTS",
57    "MultitaskClassifier",
58    "PredictionInterval",
59    "SimpleMultitaskClassifier",
60    "Optimizer",
61    "RandomBagRegressor",
62    "RandomBagClassifier",
63    "RegressorUpdater",
64    "ClassifierUpdater",
65    "Ridge2Regressor",
66    "Ridge2Classifier",
67    "Ridge2MultitaskClassifier",
68    "SubSampler",
69]
class AdaBoostClassifier(nnetsauce.boosting.bst.Boosting, sklearn.base.ClassifierMixin):
 21class AdaBoostClassifier(Boosting, ClassifierMixin):
 22    """AdaBoost Classification (SAMME) model class derived from class Boosting
 23
 24    Parameters:
 25
 26        obj: object
 27            any object containing a method fit (obj.fit()) and a method predict
 28            (obj.predict())
 29
 30        n_estimators: int
 31            number of boosting iterations
 32
 33        learning_rate: float
 34            learning rate of the boosting procedure
 35
 36        n_hidden_features: int
 37            number of nodes in the hidden layer
 38
 39        reg_lambda: float
 40            regularization parameter for weights
 41
 42        reg_alpha: float
 43            controls compromize between l1 and l2 norm of weights
 44
 45        activation_name: str
 46            activation function: 'relu', 'tanh', 'sigmoid', 'prelu' or 'elu'
 47
 48        a: float
 49            hyperparameter for 'prelu' or 'elu' activation function
 50
 51        nodes_sim: str
 52            type of simulation for the nodes: 'sobol', 'hammersley', 'halton',
 53            'uniform'
 54
 55        bias: boolean
 56            indicates if the hidden layer contains a bias term (True) or not
 57            (False)
 58
 59        dropout: float
 60            regularization parameter; (random) percentage of nodes dropped out
 61            of the training
 62
 63        direct_link: boolean
 64            indicates if the original predictors are included (True) in model's
 65            fitting or not (False)
 66
 67        n_clusters: int
 68            number of clusters for 'kmeans' or 'gmm' clustering (could be 0:
 69                no clustering)
 70
 71        cluster_encode: bool
 72            defines how the variable containing clusters is treated (default is one-hot)
 73            if `False`, then labels are used, without one-hot encoding
 74
 75        type_clust: str
 76            type of clustering method: currently k-means ('kmeans') or Gaussian
 77            Mixture Model ('gmm')
 78
 79        type_scaling: a tuple of 3 strings
 80            scaling methods for inputs, hidden layer, and clustering respectively
 81            (and when relevant).
 82            Currently available: standardization ('std') or MinMax scaling ('minmax')
 83
 84        col_sample: float
 85            percentage of covariates randomly chosen for training
 86
 87        row_sample: float
 88            percentage of rows chosen for training, by stratified bootstrapping
 89
 90        seed: int
 91            reproducibility seed for nodes_sim=='uniform'
 92
 93        verbose: int
 94            0 for no output, 1 for a progress bar (default is 1)
 95
 96        method: str
 97            type of Adaboost method, 'SAMME' (discrete) or 'SAMME.R' (real)
 98
 99        backend: str
100            "cpu" or "gpu" or "tpu"
101
102    Attributes:
103
104        alpha_: list
105            AdaBoost coefficients alpha_m
106
107        base_learners_: dict
108            a dictionary containing the base learners
109
110    Examples:
111
112    See also [https://github.com/Techtonique/nnetsauce/blob/master/examples/adaboost_classification.py](https://github.com/Techtonique/nnetsauce/blob/master/examples/adaboost_classification.py)
113
114    ```python
115    import nnetsauce as ns
116    import numpy as np
117    from sklearn.datasets import load_breast_cancer
118    from sklearn.linear_model import LogisticRegression
119    from sklearn.model_selection import train_test_split
120    from sklearn import metrics
121    from time import time
122
123    breast_cancer = load_breast_cancer()
124    Z = breast_cancer.data
125    t = breast_cancer.target
126    np.random.seed(123)
127    X_train, X_test, y_train, y_test = train_test_split(Z, t, test_size=0.2)
128
129    # SAMME.R
130    clf = LogisticRegression(solver='liblinear', multi_class = 'ovr',
131                            random_state=123)
132    fit_obj = ns.AdaBoostClassifier(clf,
133                                    n_hidden_features=int(11.22338867),
134                                    direct_link=True,
135                                    n_estimators=250, learning_rate=0.01126343,
136                                    col_sample=0.72684326, row_sample=0.86429443,
137                                    dropout=0.63078613, n_clusters=2,
138                                    type_clust="gmm",
139                                    verbose=1, seed = 123,
140                                    method="SAMME.R")
141
142    start = time()
143    fit_obj.fit(X_train, y_train)
144    print(f"Elapsed {time() - start}")
145
146    start = time()
147    print(fit_obj.score(X_test, y_test))
148    print(f"Elapsed {time() - start}")
149
150    preds = fit_obj.predict(X_test)
151
152    print(metrics.classification_report(preds, y_test))
153
154    ```
155
156    """
157
158    # construct the object -----
159
160    def __init__(
161        self,
162        obj,
163        n_estimators=10,
164        learning_rate=0.1,
165        n_hidden_features=1,
166        reg_lambda=0,
167        reg_alpha=0.5,
168        activation_name="relu",
169        a=0.01,
170        nodes_sim="sobol",
171        bias=True,
172        dropout=0,
173        direct_link=False,
174        n_clusters=2,
175        cluster_encode=True,
176        type_clust="kmeans",
177        type_scaling=("std", "std", "std"),
178        col_sample=1,
179        row_sample=1,
180        seed=123,
181        verbose=1,
182        method="SAMME",
183        backend="cpu",
184    ):
185        self.type_fit = "classification"
186        self.verbose = verbose
187        self.method = method
188        self.reg_lambda = reg_lambda
189        self.reg_alpha = reg_alpha
190
191        super().__init__(
192            obj=obj,
193            n_estimators=n_estimators,
194            learning_rate=learning_rate,
195            n_hidden_features=n_hidden_features,
196            activation_name=activation_name,
197            a=a,
198            nodes_sim=nodes_sim,
199            bias=bias,
200            dropout=dropout,
201            direct_link=direct_link,
202            n_clusters=n_clusters,
203            cluster_encode=cluster_encode,
204            type_clust=type_clust,
205            type_scaling=type_scaling,
206            col_sample=col_sample,
207            row_sample=row_sample,
208            seed=seed,
209            backend=backend,
210        )
211
212        self.alpha_ = []
213        self.base_learners_ = dict.fromkeys(range(n_estimators))
214
215    def fit(self, X, y, sample_weight=None, **kwargs):
216        """Fit Boosting model to training data (X, y).
217
218        Parameters:
219
220            X: {array-like}, shape = [n_samples, n_features]
221                Training vectors, where n_samples is the number
222                of samples and n_features is the number of features.
223
224            y: array-like, shape = [n_samples]
225                Target values.
226
227            **kwargs: additional parameters to be passed to
228                    self.cook_training_set or self.obj.fit
229
230        Returns:
231
232             self: object
233        """
234
235        assert mx.is_factor(y), "y must contain only integers"
236
237        assert self.method in (
238            "SAMME",
239            "SAMME.R",
240        ), "`method` must be either 'SAMME' or 'SAMME.R'"
241
242        assert (self.reg_lambda <= 1) & (
243            self.reg_lambda >= 0
244        ), "must have self.reg_lambda <= 1 &  self.reg_lambda >= 0"
245
246        assert (self.reg_alpha <= 1) & (
247            self.reg_alpha >= 0
248        ), "must have self.reg_alpha <= 1 &  self.reg_alpha >= 0"
249
250        # training
251        n, p = X.shape
252        self.n_classes = len(np.unique(y))
253        self.classes_ = np.unique(y)  # for compatibility with sklearn
254        self.n_classes_ = len(self.classes_)  # for compatibility with sklearn
255
256        if sample_weight is None:
257            w_m = np.repeat(1.0 / n, n)
258        else:
259            w_m = np.asarray(sample_weight)
260
261        base_learner = CustomClassifier(
262            self.obj,
263            n_hidden_features=self.n_hidden_features,
264            activation_name=self.activation_name,
265            a=self.a,
266            nodes_sim=self.nodes_sim,
267            bias=self.bias,
268            dropout=self.dropout,
269            direct_link=self.direct_link,
270            n_clusters=self.n_clusters,
271            type_clust=self.type_clust,
272            type_scaling=self.type_scaling,
273            col_sample=self.col_sample,
274            row_sample=self.row_sample,
275            seed=self.seed,
276        )
277
278        if self.verbose == 1:
279            pbar = Progbar(self.n_estimators)
280
281        if self.method == "SAMME":
282            err_m = 1e6
283            err_bound = 1 - 1 / self.n_classes
284            self.alpha_.append(1.0)
285            x_range_n = range(n)
286
287            for m in range(self.n_estimators):
288                preds = base_learner.fit(
289                    X, y, sample_weight=w_m.ravel(), **kwargs
290                ).predict(X)
291
292                self.base_learners_.update({m: deepcopy(base_learner)})
293
294                cond = [y[i] != preds[i] for i in x_range_n]
295
296                err_m = max(
297                    sum([elt[0] * elt[1] for elt in zip(cond, w_m)]),
298                    2.220446049250313e-16,
299                )  # sum(w_m) == 1
300
301                if self.reg_lambda > 0:
302                    err_m += self.reg_lambda * (
303                        (1 - self.reg_alpha) * 0.5 * sum([x**2 for x in w_m])
304                        + self.reg_alpha * sum([abs(x) for x in w_m])
305                    )
306
307                err_m = min(err_m, err_bound)
308
309                alpha_m = self.learning_rate * log(
310                    (self.n_classes - 1) * (1 - err_m) / err_m
311                )
312
313                self.alpha_.append(alpha_m)
314
315                w_m_temp = [exp(alpha_m * cond[i]) for i in x_range_n]
316
317                sum_w_m = sum(w_m_temp)
318
319                w_m = np.asarray([w_m_temp[i] / sum_w_m for i in x_range_n])
320
321                base_learner.set_params(seed=self.seed + (m + 1) * 1000)
322
323                if self.verbose == 1:
324                    pbar.update(m)
325
326            if self.verbose == 1:
327                pbar.update(self.n_estimators)
328
329            self.n_estimators = len(self.base_learners_)
330            self.classes_ = np.unique(y)
331
332            return self
333
334        if self.method == "SAMME.R":
335            Y = mo.one_hot_encode2(y, self.n_classes)
336
337            if sample_weight is None:
338                w_m = np.repeat(1.0 / n, n)  # (N, 1)
339
340            else:
341                w_m = np.asarray(sample_weight)
342
343            for m in range(self.n_estimators):
344                probs = base_learner.fit(
345                    X, y, sample_weight=w_m.ravel(), **kwargs
346                ).predict_proba(X)
347
348                np.clip(
349                    a=probs, a_min=2.220446049250313e-16, a_max=1.0, out=probs
350                )
351
352                self.base_learners_.update({m: deepcopy(base_learner)})
353
354                w_m *= np.exp(
355                    -1.0
356                    * self.learning_rate
357                    * (1.0 - 1.0 / self.n_classes)
358                    * xlogy(Y, probs).sum(axis=1)
359                )
360
361                w_m /= np.sum(w_m)
362
363                base_learner.set_params(seed=self.seed + (m + 1) * 1000)
364
365                if self.verbose == 1:
366                    pbar.update(m)
367
368            if self.verbose == 1:
369                pbar.update(self.n_estimators)
370
371            self.n_estimators = len(self.base_learners_)
372            self.classes_ = np.unique(y)
373
374            return self
375
376    def predict(self, X, **kwargs):
377        """Predict test data X.
378
379        Parameters:
380
381            X: {array-like}, shape = [n_samples, n_features]
382                Training vectors, where n_samples is the number
383                of samples and n_features is the number of features.
384
385            **kwargs: additional parameters to be passed to
386                  self.cook_test_set
387
388        Returns:
389
390            model predictions: {array-like}
391        """
392        return self.predict_proba(X, **kwargs).argmax(axis=1)
393
394    def predict_proba(self, X, **kwargs):
395        """Predict probabilities for test data X.
396
397        Parameters:
398
399            X: {array-like}, shape = [n_samples, n_features]
400                Training vectors, where n_samples is the number
401                of samples and n_features is the number of features.
402
403            **kwargs: additional parameters to be passed to
404                  self.cook_test_set
405
406        Returns:
407
408            probability estimates for test data: {array-like}
409
410        """
411
412        n_iter = len(self.base_learners_)
413
414        if self.method == "SAMME":
415            ensemble_learner = np.zeros((X.shape[0], self.n_classes))
416
417            # if self.verbose == 1:
418            #    pbar = Progbar(n_iter)
419
420            for idx, base_learner in self.base_learners_.items():
421                preds = base_learner.predict(X, **kwargs)
422
423                ensemble_learner += self.alpha_[idx] * mo.one_hot_encode2(
424                    preds, self.n_classes
425                )
426
427                # if self.verbose == 1:
428                #    pbar.update(idx)
429
430            # if self.verbose == 1:
431            #    pbar.update(n_iter)
432
433            expit_ensemble_learner = expit(ensemble_learner)
434
435            sum_ensemble = expit_ensemble_learner.sum(axis=1)
436
437            return expit_ensemble_learner / sum_ensemble[:, None]
438
439        # if self.method == "SAMME.R":
440        ensemble_learner = 0
441
442        # if self.verbose == 1:
443        #    pbar = Progbar(n_iter)
444
445        for idx, base_learner in self.base_learners_.items():
446            probs = base_learner.predict_proba(X, **kwargs)
447
448            np.clip(a=probs, a_min=2.220446049250313e-16, a_max=1.0, out=probs)
449
450            log_preds_proba = np.log(probs)
451
452            ensemble_learner += (
453                log_preds_proba - log_preds_proba.mean(axis=1)[:, None]
454            )
455
456            # if self.verbose == 1:
457            #    pbar.update(idx)
458
459        ensemble_learner *= self.n_classes - 1
460
461        # if self.verbose == 1:
462        #    pbar.update(n_iter)
463
464        expit_ensemble_learner = expit(ensemble_learner)
465
466        sum_ensemble = expit_ensemble_learner.sum(axis=1)
467
468        return expit_ensemble_learner / sum_ensemble[:, None]

AdaBoost Classification (SAMME) model class derived from class Boosting

Parameters:

obj: object
    any object containing a method fit (obj.fit()) and a method predict
    (obj.predict())

n_estimators: int
    number of boosting iterations

learning_rate: float
    learning rate of the boosting procedure

n_hidden_features: int
    number of nodes in the hidden layer

reg_lambda: float
    regularization parameter for weights

reg_alpha: float
    controls compromize between l1 and l2 norm of weights

activation_name: str
    activation function: 'relu', 'tanh', 'sigmoid', 'prelu' or 'elu'

a: float
    hyperparameter for 'prelu' or 'elu' activation function

nodes_sim: str
    type of simulation for the nodes: 'sobol', 'hammersley', 'halton',
    'uniform'

bias: boolean
    indicates if the hidden layer contains a bias term (True) or not
    (False)

dropout: float
    regularization parameter; (random) percentage of nodes dropped out
    of the training

direct_link: boolean
    indicates if the original predictors are included (True) in model's
    fitting or not (False)

n_clusters: int
    number of clusters for 'kmeans' or 'gmm' clustering (could be 0:
        no clustering)

cluster_encode: bool
    defines how the variable containing clusters is treated (default is one-hot)
    if `False`, then labels are used, without one-hot encoding

type_clust: str
    type of clustering method: currently k-means ('kmeans') or Gaussian
    Mixture Model ('gmm')

type_scaling: a tuple of 3 strings
    scaling methods for inputs, hidden layer, and clustering respectively
    (and when relevant).
    Currently available: standardization ('std') or MinMax scaling ('minmax')

col_sample: float
    percentage of covariates randomly chosen for training

row_sample: float
    percentage of rows chosen for training, by stratified bootstrapping

seed: int
    reproducibility seed for nodes_sim=='uniform'

verbose: int
    0 for no output, 1 for a progress bar (default is 1)

method: str
    type of Adaboost method, 'SAMME' (discrete) or 'SAMME.R' (real)

backend: str
    "cpu" or "gpu" or "tpu"

Attributes:

alpha_: list
    AdaBoost coefficients alpha_m

base_learners_: dict
    a dictionary containing the base learners

Examples:

See also https://github.com/Techtonique/nnetsauce/blob/master/examples/adaboost_classification.py

import nnetsauce as ns
import numpy as np
from sklearn.datasets import load_breast_cancer
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn import metrics
from time import time

breast_cancer = load_breast_cancer()
Z = breast_cancer.data
t = breast_cancer.target
np.random.seed(123)
X_train, X_test, y_train, y_test = train_test_split(Z, t, test_size=0.2)

# SAMME.R
clf = LogisticRegression(solver='liblinear', multi_class = 'ovr',
                        random_state=123)
fit_obj = ns.AdaBoostClassifier(clf,
                                n_hidden_features=int(11.22338867),
                                direct_link=True,
                                n_estimators=250, learning_rate=0.01126343,
                                col_sample=0.72684326, row_sample=0.86429443,
                                dropout=0.63078613, n_clusters=2,
                                type_clust="gmm",
                                verbose=1, seed = 123,
                                method="SAMME.R")

start = time()
fit_obj.fit(X_train, y_train)
print(f"Elapsed {time() - start}")

start = time()
print(fit_obj.score(X_test, y_test))
print(f"Elapsed {time() - start}")

preds = fit_obj.predict(X_test)

print(metrics.classification_report(preds, y_test))
def fit(self, X, y, sample_weight=None, **kwargs):
215    def fit(self, X, y, sample_weight=None, **kwargs):
216        """Fit Boosting model to training data (X, y).
217
218        Parameters:
219
220            X: {array-like}, shape = [n_samples, n_features]
221                Training vectors, where n_samples is the number
222                of samples and n_features is the number of features.
223
224            y: array-like, shape = [n_samples]
225                Target values.
226
227            **kwargs: additional parameters to be passed to
228                    self.cook_training_set or self.obj.fit
229
230        Returns:
231
232             self: object
233        """
234
235        assert mx.is_factor(y), "y must contain only integers"
236
237        assert self.method in (
238            "SAMME",
239            "SAMME.R",
240        ), "`method` must be either 'SAMME' or 'SAMME.R'"
241
242        assert (self.reg_lambda <= 1) & (
243            self.reg_lambda >= 0
244        ), "must have self.reg_lambda <= 1 &  self.reg_lambda >= 0"
245
246        assert (self.reg_alpha <= 1) & (
247            self.reg_alpha >= 0
248        ), "must have self.reg_alpha <= 1 &  self.reg_alpha >= 0"
249
250        # training
251        n, p = X.shape
252        self.n_classes = len(np.unique(y))
253        self.classes_ = np.unique(y)  # for compatibility with sklearn
254        self.n_classes_ = len(self.classes_)  # for compatibility with sklearn
255
256        if sample_weight is None:
257            w_m = np.repeat(1.0 / n, n)
258        else:
259            w_m = np.asarray(sample_weight)
260
261        base_learner = CustomClassifier(
262            self.obj,
263            n_hidden_features=self.n_hidden_features,
264            activation_name=self.activation_name,
265            a=self.a,
266            nodes_sim=self.nodes_sim,
267            bias=self.bias,
268            dropout=self.dropout,
269            direct_link=self.direct_link,
270            n_clusters=self.n_clusters,
271            type_clust=self.type_clust,
272            type_scaling=self.type_scaling,
273            col_sample=self.col_sample,
274            row_sample=self.row_sample,
275            seed=self.seed,
276        )
277
278        if self.verbose == 1:
279            pbar = Progbar(self.n_estimators)
280
281        if self.method == "SAMME":
282            err_m = 1e6
283            err_bound = 1 - 1 / self.n_classes
284            self.alpha_.append(1.0)
285            x_range_n = range(n)
286
287            for m in range(self.n_estimators):
288                preds = base_learner.fit(
289                    X, y, sample_weight=w_m.ravel(), **kwargs
290                ).predict(X)
291
292                self.base_learners_.update({m: deepcopy(base_learner)})
293
294                cond = [y[i] != preds[i] for i in x_range_n]
295
296                err_m = max(
297                    sum([elt[0] * elt[1] for elt in zip(cond, w_m)]),
298                    2.220446049250313e-16,
299                )  # sum(w_m) == 1
300
301                if self.reg_lambda > 0:
302                    err_m += self.reg_lambda * (
303                        (1 - self.reg_alpha) * 0.5 * sum([x**2 for x in w_m])
304                        + self.reg_alpha * sum([abs(x) for x in w_m])
305                    )
306
307                err_m = min(err_m, err_bound)
308
309                alpha_m = self.learning_rate * log(
310                    (self.n_classes - 1) * (1 - err_m) / err_m
311                )
312
313                self.alpha_.append(alpha_m)
314
315                w_m_temp = [exp(alpha_m * cond[i]) for i in x_range_n]
316
317                sum_w_m = sum(w_m_temp)
318
319                w_m = np.asarray([w_m_temp[i] / sum_w_m for i in x_range_n])
320
321                base_learner.set_params(seed=self.seed + (m + 1) * 1000)
322
323                if self.verbose == 1:
324                    pbar.update(m)
325
326            if self.verbose == 1:
327                pbar.update(self.n_estimators)
328
329            self.n_estimators = len(self.base_learners_)
330            self.classes_ = np.unique(y)
331
332            return self
333
334        if self.method == "SAMME.R":
335            Y = mo.one_hot_encode2(y, self.n_classes)
336
337            if sample_weight is None:
338                w_m = np.repeat(1.0 / n, n)  # (N, 1)
339
340            else:
341                w_m = np.asarray(sample_weight)
342
343            for m in range(self.n_estimators):
344                probs = base_learner.fit(
345                    X, y, sample_weight=w_m.ravel(), **kwargs
346                ).predict_proba(X)
347
348                np.clip(
349                    a=probs, a_min=2.220446049250313e-16, a_max=1.0, out=probs
350                )
351
352                self.base_learners_.update({m: deepcopy(base_learner)})
353
354                w_m *= np.exp(
355                    -1.0
356                    * self.learning_rate
357                    * (1.0 - 1.0 / self.n_classes)
358                    * xlogy(Y, probs).sum(axis=1)
359                )
360
361                w_m /= np.sum(w_m)
362
363                base_learner.set_params(seed=self.seed + (m + 1) * 1000)
364
365                if self.verbose == 1:
366                    pbar.update(m)
367
368            if self.verbose == 1:
369                pbar.update(self.n_estimators)
370
371            self.n_estimators = len(self.base_learners_)
372            self.classes_ = np.unique(y)
373
374            return self

Fit Boosting model to training data (X, y).

Parameters:

X: {array-like}, shape = [n_samples, n_features]
    Training vectors, where n_samples is the number
    of samples and n_features is the number of features.

y: array-like, shape = [n_samples]
    Target values.

**kwargs: additional parameters to be passed to
        self.cook_training_set or self.obj.fit

Returns:

 self: object
def predict(self, X, **kwargs):
376    def predict(self, X, **kwargs):
377        """Predict test data X.
378
379        Parameters:
380
381            X: {array-like}, shape = [n_samples, n_features]
382                Training vectors, where n_samples is the number
383                of samples and n_features is the number of features.
384
385            **kwargs: additional parameters to be passed to
386                  self.cook_test_set
387
388        Returns:
389
390            model predictions: {array-like}
391        """
392        return self.predict_proba(X, **kwargs).argmax(axis=1)

Predict test data X.

Parameters:

X: {array-like}, shape = [n_samples, n_features]
    Training vectors, where n_samples is the number
    of samples and n_features is the number of features.

**kwargs: additional parameters to be passed to
      self.cook_test_set

Returns:

model predictions: {array-like}
def predict_proba(self, X, **kwargs):
394    def predict_proba(self, X, **kwargs):
395        """Predict probabilities for test data X.
396
397        Parameters:
398
399            X: {array-like}, shape = [n_samples, n_features]
400                Training vectors, where n_samples is the number
401                of samples and n_features is the number of features.
402
403            **kwargs: additional parameters to be passed to
404                  self.cook_test_set
405
406        Returns:
407
408            probability estimates for test data: {array-like}
409
410        """
411
412        n_iter = len(self.base_learners_)
413
414        if self.method == "SAMME":
415            ensemble_learner = np.zeros((X.shape[0], self.n_classes))
416
417            # if self.verbose == 1:
418            #    pbar = Progbar(n_iter)
419
420            for idx, base_learner in self.base_learners_.items():
421                preds = base_learner.predict(X, **kwargs)
422
423                ensemble_learner += self.alpha_[idx] * mo.one_hot_encode2(
424                    preds, self.n_classes
425                )
426
427                # if self.verbose == 1:
428                #    pbar.update(idx)
429
430            # if self.verbose == 1:
431            #    pbar.update(n_iter)
432
433            expit_ensemble_learner = expit(ensemble_learner)
434
435            sum_ensemble = expit_ensemble_learner.sum(axis=1)
436
437            return expit_ensemble_learner / sum_ensemble[:, None]
438
439        # if self.method == "SAMME.R":
440        ensemble_learner = 0
441
442        # if self.verbose == 1:
443        #    pbar = Progbar(n_iter)
444
445        for idx, base_learner in self.base_learners_.items():
446            probs = base_learner.predict_proba(X, **kwargs)
447
448            np.clip(a=probs, a_min=2.220446049250313e-16, a_max=1.0, out=probs)
449
450            log_preds_proba = np.log(probs)
451
452            ensemble_learner += (
453                log_preds_proba - log_preds_proba.mean(axis=1)[:, None]
454            )
455
456            # if self.verbose == 1:
457            #    pbar.update(idx)
458
459        ensemble_learner *= self.n_classes - 1
460
461        # if self.verbose == 1:
462        #    pbar.update(n_iter)
463
464        expit_ensemble_learner = expit(ensemble_learner)
465
466        sum_ensemble = expit_ensemble_learner.sum(axis=1)
467
468        return expit_ensemble_learner / sum_ensemble[:, None]

Predict probabilities for test data X.

Parameters:

X: {array-like}, shape = [n_samples, n_features]
    Training vectors, where n_samples is the number
    of samples and n_features is the number of features.

**kwargs: additional parameters to be passed to
      self.cook_test_set

Returns:

probability estimates for test data: {array-like}
class Base(sklearn.base.BaseEstimator):
 46class Base(BaseEstimator):
 47    """Base model from which all the other classes inherit.
 48
 49    This class contains the most important data preprocessing/feature engineering methods.
 50
 51    Parameters:
 52
 53        n_hidden_features: int
 54            number of nodes in the hidden layer
 55
 56        activation_name: str
 57            activation function: 'relu', 'tanh', 'sigmoid', 'prelu' or 'elu'
 58
 59        a: float
 60            hyperparameter for 'prelu' or 'elu' activation function
 61
 62        nodes_sim: str
 63            type of simulation for hidden layer nodes: 'sobol', 'hammersley', 'halton',
 64            'uniform'
 65
 66        bias: boolean
 67            indicates if the hidden layer contains a bias term (True) or
 68            not (False)
 69
 70        dropout: float
 71            regularization parameter; (random) percentage of nodes dropped out
 72            of the training
 73
 74        direct_link: boolean
 75            indicates if the original features are included (True) in model's
 76            fitting or not (False)
 77
 78        n_clusters: int
 79            number of clusters for type_clust='kmeans' or type_clust='gmm'
 80            clustering (could be 0: no clustering)
 81
 82        cluster_encode: bool
 83            defines how the variable containing clusters is treated (default is one-hot);
 84            if `False`, then labels are used, without one-hot encoding
 85
 86        type_clust: str
 87            type of clustering method: currently k-means ('kmeans') or Gaussian
 88            Mixture Model ('gmm')
 89
 90        type_scaling: a tuple of 3 strings
 91            scaling methods for inputs, hidden layer, and clustering respectively
 92            (and when relevant).
 93            Currently available: standardization ('std') or MinMax scaling ('minmax') or robust scaling ('robust') or  max absolute scaling ('maxabs')
 94
 95        col_sample: float
 96            percentage of features randomly chosen for training
 97
 98        row_sample: float
 99            percentage of rows chosen for training, by stratified bootstrapping
100
101        seed: int
102            reproducibility seed for nodes_sim=='uniform', clustering and dropout
103
104        backend: str
105            "cpu" or "gpu" or "tpu"
106
107    """
108
109    # construct the object -----
110
111    def __init__(
112        self,
113        n_hidden_features=5,
114        activation_name="relu",
115        a=0.01,
116        nodes_sim="sobol",
117        bias=True,
118        dropout=0,
119        direct_link=True,
120        n_clusters=2,
121        cluster_encode=True,
122        type_clust="kmeans",
123        type_scaling=("std", "std", "std"),
124        col_sample=1,
125        row_sample=1,
126        seed=123,
127        backend="cpu",
128    ):
129        # input checks -----
130
131        sys_platform = platform.system()
132
133        if (sys_platform == "Windows") and (backend in ("gpu", "tpu")):
134            warnings.warn(
135                "No GPU/TPU computing on Windows yet, backend set to 'cpu'"
136            )
137            backend = "cpu"
138
139        assert activation_name in (
140            "relu",
141            "tanh",
142            "sigmoid",
143            "prelu",
144            "elu",
145        ), "'activation_name' must be in ('relu', 'tanh', 'sigmoid','prelu', 'elu')"
146
147        assert nodes_sim in (
148            "sobol",
149            "hammersley",
150            "uniform",
151            "halton",
152        ), "'nodes_sim' must be in ('sobol', 'hammersley', 'uniform', 'halton')"
153
154        assert type_clust in (
155            "kmeans",
156            "gmm",
157        ), "'type_clust' must be in ('kmeans', 'gmm')"
158
159        assert (len(type_scaling) == 3) & all(
160            type_scaling[i] in ("minmax", "std", "robust", "maxabs")
161            for i in range(len(type_scaling))
162        ), "'type_scaling' must have length 3, and available scaling methods are 'minmax' scaling, standardization ('std'), robust scaling ('robust') and max absolute ('maxabs')"
163
164        assert (col_sample >= 0) & (
165            col_sample <= 1
166        ), "'col_sample' must be comprised between 0 and 1 (both included)"
167
168        assert backend in (
169            "cpu",
170            "gpu",
171            "tpu",
172        ), "must have 'backend' in ('cpu', 'gpu', 'tpu')"
173
174        self.n_hidden_features = n_hidden_features
175        self.activation_name = activation_name
176        self.a = a
177        self.nodes_sim = nodes_sim
178        self.bias = bias
179        self.seed = seed
180        self.backend = backend
181        self.dropout = dropout
182        self.direct_link = direct_link
183        self.cluster_encode = cluster_encode
184        self.type_clust = type_clust
185        self.type_scaling = type_scaling
186        self.col_sample = col_sample
187        self.row_sample = row_sample
188        self.n_clusters = n_clusters
189        if isinstance(self, RegressorMixin):
190            self.type_fit = "regression"
191        elif isinstance(self, ClassifierMixin):
192            self.type_fit = "classification"
193        self.subsampler_ = None
194        self.index_col_ = None
195        self.index_row_ = True
196        self.clustering_obj_ = None
197        self.clustering_scaler_ = None
198        self.nn_scaler_ = None
199        self.scaler_ = None
200        self.encoder_ = None
201        self.W_ = None
202        self.X_ = None
203        self.y_ = None
204        self.y_mean_ = None
205        self.beta_ = None
206
207        # activation function -----
208        if sys_platform in ("Linux", "Darwin"):
209            activation_options = {
210                "relu": ac.relu if (self.backend == "cpu") else jnn.relu,
211                "tanh": np.tanh if (self.backend == "cpu") else jnp.tanh,
212                "sigmoid": (
213                    ac.sigmoid if (self.backend == "cpu") else jnn.sigmoid
214                ),
215                "prelu": partial(ac.prelu, a=a),
216                "elu": (
217                    partial(ac.elu, a=a)
218                    if (self.backend == "cpu")
219                    else partial(jnn.elu, a=a)
220                ),
221            }
222        else:  # on Windows currently, no JAX
223            activation_options = {
224                "relu": (
225                    ac.relu if (self.backend == "cpu") else NotImplementedError
226                ),
227                "tanh": (
228                    np.tanh if (self.backend == "cpu") else NotImplementedError
229                ),
230                "sigmoid": (
231                    ac.sigmoid
232                    if (self.backend == "cpu")
233                    else NotImplementedError
234                ),
235                "prelu": partial(ac.prelu, a=a),
236                "elu": (
237                    partial(ac.elu, a=a)
238                    if (self.backend == "cpu")
239                    else NotImplementedError
240                ),
241            }
242        self.activation_func = activation_options[activation_name]
243
244    # "preprocessing" methods to be inherited -----
245
246    def encode_clusters(self, X=None, predict=False, scaler=None, **kwargs):  #
247        """Create new covariates with kmeans or GMM clustering
248
249        Parameters:
250
251            X: {array-like}, shape = [n_samples, n_features]
252                Training vectors, where n_samples is the number
253                of samples and n_features is the number of features.
254
255            predict: boolean
256                is False on training set and True on test set
257
258            scaler: {object} of class StandardScaler, MinMaxScaler, RobustScaler or MaxAbsScaler
259                if scaler has already been fitted on training data (online training), it can be passed here
260
261            **kwargs:
262                additional parameters to be passed to the
263                clustering method
264
265        Returns:
266
267            Clusters' matrix, one-hot encoded: {array-like}
268
269        """
270
271        np.random.seed(self.seed)
272
273        if X is None:
274            X = self.X_
275
276        if isinstance(X, pd.DataFrame):
277            X = copy.deepcopy(X.values.astype(float))
278
279        if len(X.shape) == 1:
280            X = X.reshape(1, -1)
281
282        if predict is False:  # encode training set
283
284            # scale input data before clustering
285            self.clustering_scaler_, scaled_X = mo.scale_covariates(
286                X, choice=self.type_scaling[2], scaler=self.clustering_scaler_
287            )
288
289            self.clustering_obj_, X_clustered = mo.cluster_covariates(
290                scaled_X,
291                self.n_clusters,
292                self.seed,
293                type_clust=self.type_clust,
294                **kwargs
295            )
296
297            if self.cluster_encode == True:
298                return mo.one_hot_encode(X_clustered, self.n_clusters).astype(
299                    np.float16
300                )
301
302            return X_clustered.astype(np.float16)
303
304        # if predict == True, encode test set
305        X_clustered = self.clustering_obj_.predict(
306            self.clustering_scaler_.transform(X)
307        )
308
309        if self.cluster_encode == True:
310            return mo.one_hot_encode(X_clustered, self.n_clusters).astype(
311                np.float16
312            )
313
314        return X_clustered.astype(np.float16)
315
316    def create_layer(self, scaled_X, W=None):
317        """Create hidden layer.
318
319        Parameters:
320
321            scaled_X: {array-like}, shape = [n_samples, n_features]
322                Training vectors, where n_samples is the number
323                of samples and n_features is the number of features
324
325            W: {array-like}, shape = [n_features, hidden_features]
326                if provided, constructs the hidden layer with W; otherwise computed internally
327
328        Returns:
329
330            Hidden layer matrix: {array-like}
331
332        """
333
334        n_features = scaled_X.shape[1]
335
336        # hash_sim = {
337        #         "sobol": generate_sobol,
338        #         "hammersley": generate_hammersley,
339        #         "uniform": generate_uniform,
340        #         "halton": generate_halton
341        #     }
342
343        if self.bias is False:  # no bias term in the hidden layer
344            if W is None:
345                if self.nodes_sim == "sobol":
346                    self.W_ = generate_sobol(
347                        n_dims=n_features,
348                        n_points=self.n_hidden_features,
349                        seed=self.seed,
350                    )
351                elif self.nodes_sim == "hammersley":
352                    self.W_ = generate_hammersley(
353                        n_dims=n_features,
354                        n_points=self.n_hidden_features,
355                        seed=self.seed,
356                    )
357                elif self.nodes_sim == "uniform":
358                    self.W_ = generate_uniform(
359                        n_dims=n_features,
360                        n_points=self.n_hidden_features,
361                        seed=self.seed,
362                    )
363                else:
364                    self.W_ = generate_halton(
365                        n_dims=n_features,
366                        n_points=self.n_hidden_features,
367                        seed=self.seed,
368                    )
369
370                # self.W_ = hash_sim[self.nodes_sim](
371                #             n_dims=n_features,
372                #             n_points=self.n_hidden_features,
373                #             seed=self.seed,
374                #         )
375
376                assert (
377                    scaled_X.shape[1] == self.W_.shape[0]
378                ), "check dimensions of covariates X and matrix W"
379
380                return mo.dropout(
381                    x=self.activation_func(
382                        mo.safe_sparse_dot(
383                            a=scaled_X, b=self.W_, backend=self.backend
384                        )
385                    ),
386                    drop_prob=self.dropout,
387                    seed=self.seed,
388                )
389
390            # W is not none
391            assert (
392                scaled_X.shape[1] == W.shape[0]
393            ), "check dimensions of covariates X and matrix W"
394
395            # self.W_ = W
396            return mo.dropout(
397                x=self.activation_func(
398                    mo.safe_sparse_dot(a=scaled_X, b=W, backend=self.backend)
399                ),
400                drop_prob=self.dropout,
401                seed=self.seed,
402            )
403
404        # with bias term in the hidden layer
405        if W is None:
406            n_features_1 = n_features + 1
407
408            if self.nodes_sim == "sobol":
409                self.W_ = generate_sobol(
410                    n_dims=n_features_1,
411                    n_points=self.n_hidden_features,
412                    seed=self.seed,
413                )
414            elif self.nodes_sim == "hammersley":
415                self.W_ = generate_hammersley(
416                    n_dims=n_features_1,
417                    n_points=self.n_hidden_features,
418                    seed=self.seed,
419                )
420            elif self.nodes_sim == "uniform":
421                self.W_ = generate_uniform(
422                    n_dims=n_features_1,
423                    n_points=self.n_hidden_features,
424                    seed=self.seed,
425                )
426            else:
427                self.W_ = generate_halton(
428                    n_dims=n_features_1,
429                    n_points=self.n_hidden_features,
430                    seed=self.seed,
431                )
432
433            # self.W_ = hash_sim[self.nodes_sim](
434            #         n_dims=n_features_1,
435            #         n_points=self.n_hidden_features,
436            #         seed=self.seed,
437            #     )
438
439            return mo.dropout(
440                x=self.activation_func(
441                    mo.safe_sparse_dot(
442                        a=mo.cbind(
443                            np.ones(scaled_X.shape[0]),
444                            scaled_X,
445                            backend=self.backend,
446                        ),
447                        b=self.W_,
448                        backend=self.backend,
449                    )
450                ),
451                drop_prob=self.dropout,
452                seed=self.seed,
453            )
454
455        # W is not None
456        # self.W_ = W
457        return mo.dropout(
458            x=self.activation_func(
459                mo.safe_sparse_dot(
460                    a=mo.cbind(
461                        np.ones(scaled_X.shape[0]),
462                        scaled_X,
463                        backend=self.backend,
464                    ),
465                    b=W,
466                    backend=self.backend,
467                )
468            ),
469            drop_prob=self.dropout,
470            seed=self.seed,
471        )
472
473    def cook_training_set(self, y=None, X=None, W=None, **kwargs):
474        """Create new hidden features for training set, with hidden layer, center the response.
475
476        Parameters:
477
478            y: array-like, shape = [n_samples]
479                Target values
480
481            X: {array-like}, shape = [n_samples, n_features]
482                Training vectors, where n_samples is the number
483                of samples and n_features is the number of features
484
485            W: {array-like}, shape = [n_features, hidden_features]
486                if provided, constructs the hidden layer via W
487
488        Returns:
489
490            (centered response, direct link + hidden layer matrix): {tuple}
491
492        """
493
494        # either X and y are stored or not
495        # assert ((y is None) & (X is None)) | ((y is not None) & (X is not None))
496        if self.n_hidden_features > 0:  # has a hidden layer
497            assert (
498                len(self.type_scaling) >= 2
499            ), "must have len(self.type_scaling) >= 2 when self.n_hidden_features > 0"
500
501        if X is None:
502
503            if self.col_sample == 1:
504                input_X = self.X_
505            else:
506                n_features = self.X_.shape[1]
507                new_n_features = int(np.ceil(n_features * self.col_sample))
508                assert (
509                    new_n_features >= 1
510                ), "check class attribute 'col_sample' and the number of covariates provided for X"
511                np.random.seed(self.seed)
512                index_col = np.random.choice(
513                    range(n_features), size=new_n_features, replace=False
514                )
515                self.index_col_ = index_col
516                input_X = self.X_[:, self.index_col_]
517
518        else:  # X is not None # keep X vs self.X_
519
520            if isinstance(X, pd.DataFrame):
521                X = copy.deepcopy(X.values.astype(float))
522
523            if self.col_sample == 1:
524                input_X = X
525            else:
526                n_features = X.shape[1]
527                new_n_features = int(np.ceil(n_features * self.col_sample))
528                assert (
529                    new_n_features >= 1
530                ), "check class attribute 'col_sample' and the number of covariates provided for X"
531                np.random.seed(self.seed)
532                index_col = np.random.choice(
533                    range(n_features), size=new_n_features, replace=False
534                )
535                self.index_col_ = index_col
536                input_X = X[:, self.index_col_]
537
538        if self.n_clusters <= 0:
539            # data without any clustering: self.n_clusters is None -----
540
541            if self.n_hidden_features > 0:  # with hidden layer
542
543                self.nn_scaler_, scaled_X = mo.scale_covariates(
544                    input_X, choice=self.type_scaling[1], scaler=self.nn_scaler_
545                )
546                Phi_X = (
547                    self.create_layer(scaled_X)
548                    if W is None
549                    else self.create_layer(scaled_X, W=W)
550                )
551                Z = (
552                    mo.cbind(input_X, Phi_X, backend=self.backend)
553                    if self.direct_link is True
554                    else Phi_X
555                )
556                self.scaler_, scaled_Z = mo.scale_covariates(
557                    Z, choice=self.type_scaling[0], scaler=self.scaler_
558                )
559            else:  # no hidden layer
560                Z = input_X
561                self.scaler_, scaled_Z = mo.scale_covariates(
562                    Z, choice=self.type_scaling[0], scaler=self.scaler_
563                )
564
565        else:
566
567            # data with clustering: self.n_clusters is not None ----- # keep
568
569            augmented_X = mo.cbind(
570                input_X,
571                self.encode_clusters(input_X, **kwargs),
572                backend=self.backend,
573            )
574
575            if self.n_hidden_features > 0:  # with hidden layer
576
577                self.nn_scaler_, scaled_X = mo.scale_covariates(
578                    augmented_X,
579                    choice=self.type_scaling[1],
580                    scaler=self.nn_scaler_,
581                )
582                Phi_X = (
583                    self.create_layer(scaled_X)
584                    if W is None
585                    else self.create_layer(scaled_X, W=W)
586                )
587                Z = (
588                    mo.cbind(augmented_X, Phi_X, backend=self.backend)
589                    if self.direct_link is True
590                    else Phi_X
591                )
592                self.scaler_, scaled_Z = mo.scale_covariates(
593                    Z, choice=self.type_scaling[0], scaler=self.scaler_
594                )
595            else:  # no hidden layer
596                Z = augmented_X
597                self.scaler_, scaled_Z = mo.scale_covariates(
598                    Z, choice=self.type_scaling[0], scaler=self.scaler_
599                )
600
601        # Returning model inputs -----
602        if mx.is_factor(y) is False:  # regression
603            # center y
604            if y is None:
605                self.y_mean_, centered_y = mo.center_response(self.y_)
606            else:
607                self.y_mean_, centered_y = mo.center_response(y)
608
609            # y is subsampled
610            if self.row_sample < 1:
611                n, p = Z.shape
612
613                self.subsampler_ = (
614                    SubSampler(
615                        y=self.y_, row_sample=self.row_sample, seed=self.seed
616                    )
617                    if y is None
618                    else SubSampler(
619                        y=y, row_sample=self.row_sample, seed=self.seed
620                    )
621                )
622
623                self.index_row_ = self.subsampler_.subsample()
624
625                n_row_sample = len(self.index_row_)
626                # regression
627                return (
628                    centered_y[self.index_row_].reshape(n_row_sample),
629                    self.scaler_.transform(
630                        Z[self.index_row_, :].reshape(n_row_sample, p)
631                    ),
632                )
633            # y is not subsampled
634            # regression
635            return (centered_y, self.scaler_.transform(Z))
636
637        # classification
638        # y is subsampled
639        if self.row_sample < 1:
640            n, p = Z.shape
641
642            self.subsampler_ = (
643                SubSampler(
644                    y=self.y_, row_sample=self.row_sample, seed=self.seed
645                )
646                if y is None
647                else SubSampler(y=y, row_sample=self.row_sample, seed=self.seed)
648            )
649
650            self.index_row_ = self.subsampler_.subsample()
651
652            n_row_sample = len(self.index_row_)
653            # classification
654            return (
655                y[self.index_row_].reshape(n_row_sample),
656                self.scaler_.transform(
657                    Z[self.index_row_, :].reshape(n_row_sample, p)
658                ),
659            )
660        # y is not subsampled
661        # classification
662        return (y, self.scaler_.transform(Z))
663
664    def cook_test_set(self, X, **kwargs):
665        """Transform data from test set, with hidden layer.
666
667        Parameters:
668
669            X: {array-like}, shape = [n_samples, n_features]
670                Training vectors, where n_samples is the number
671                of samples and n_features is the number of features
672
673            **kwargs: additional parameters to be passed to self.encode_cluster
674
675        Returns:
676
677            Transformed test set : {array-like}
678        """
679
680        if isinstance(X, pd.DataFrame):
681            X = copy.deepcopy(X.values.astype(float))
682
683        if len(X.shape) == 1:
684            X = X.reshape(1, -1)
685
686        if (
687            self.n_clusters == 0
688        ):  # data without clustering: self.n_clusters is None -----
689            if self.n_hidden_features > 0:
690                # if hidden layer
691                scaled_X = (
692                    self.nn_scaler_.transform(X)
693                    if (self.col_sample == 1)
694                    else self.nn_scaler_.transform(X[:, self.index_col_])
695                )
696                Phi_X = self.create_layer(scaled_X, self.W_)
697                if self.direct_link == True:
698                    return self.scaler_.transform(
699                        mo.cbind(scaled_X, Phi_X, backend=self.backend)
700                    )
701                # when self.direct_link == False
702                return self.scaler_.transform(Phi_X)
703            # if no hidden layer # self.n_hidden_features == 0
704            return self.scaler_.transform(X)
705
706        # data with clustering: self.n_clusters > 0 -----
707        if self.col_sample == 1:
708            predicted_clusters = self.encode_clusters(
709                X=X, predict=True, **kwargs
710            )
711            augmented_X = mo.cbind(X, predicted_clusters, backend=self.backend)
712        else:
713            predicted_clusters = self.encode_clusters(
714                X=X[:, self.index_col_], predict=True, **kwargs
715            )
716            augmented_X = mo.cbind(
717                X[:, self.index_col_], predicted_clusters, backend=self.backend
718            )
719
720        if self.n_hidden_features > 0:  # if hidden layer
721            scaled_X = self.nn_scaler_.transform(augmented_X)
722            Phi_X = self.create_layer(scaled_X, self.W_)
723            if self.direct_link == True:
724                return self.scaler_.transform(
725                    mo.cbind(augmented_X, Phi_X, backend=self.backend)
726                )
727            return self.scaler_.transform(Phi_X)
728
729        # if no hidden layer
730        return self.scaler_.transform(augmented_X)
731
732    def cross_val_score(
733        self,
734        X,
735        y,
736        cv=5,
737        scoring="accuracy",
738        random_state=42,
739        n_jobs=-1,
740        epsilon=0.5,
741        penalized=True,
742        objective="abs",
743        **kwargs
744    ):
745        """
746        Penalized Cross-validation score for a model.
747
748        Parameters:
749
750            X: {array-like}, shape = [n_samples, n_features]
751                Training vectors, where n_samples is the number
752                of samples and n_features is the number of features
753
754            y: array-like, shape = [n_samples]
755                Target values
756
757            X_test: {array-like}, shape = [n_samples, n_features]
758                Test vectors, where n_samples is the number
759                of samples and n_features is the number of features
760
761            y_test: array-like, shape = [n_samples]
762                Target values
763
764            cv: int
765                Number of folds
766
767            scoring: str
768                Scoring metric
769
770            random_state: int
771                Random state
772
773            n_jobs: int
774                Number of jobs to run in parallel
775
776            epsilon: float
777                Penalty parameter
778
779            penalized: bool
780                Whether to obtain penalized cross-validation score or not
781
782            objective: str
783                'abs': Minimize the absolute difference between cross-validation score and validation score
784                'relative': Minimize the relative difference between cross-validation score and validation score
785        Returns:
786
787            A namedtuple with the following fields:
788                - cv_score: float
789                    cross-validation score
790                - val_score: float
791                    validation score
792                - penalized_score: float
793                    penalized cross-validation score: cv_score / val_score + epsilon*(1/val_score + 1/cv_score)
794                    If higher scoring metric is better, minimize the function result.
795                    If lower scoring metric is better, maximize the function result.
796        """
797        if scoring == "accuracy":
798            scoring_func = accuracy_score
799        elif scoring == "balanced_accuracy":
800            scoring_func = balanced_accuracy_score
801        elif scoring == "f1":
802            scoring_func = f1_score
803        elif scoring == "roc_auc":
804            scoring_func = roc_auc_score
805        elif scoring == "r2":
806            scoring_func = r2_score
807        elif scoring == "mse":
808            scoring_func = mean_squared_error
809        elif scoring == "mae":
810            scoring_func = mean_absolute_error
811        elif scoring == "mape":
812            scoring_func = mean_absolute_percentage_error
813        elif scoring == "rmse":
814
815            def scoring_func(y_true, y_pred):
816                return np.sqrt(mean_squared_error(y_true, y_pred))
817
818        X_train, X_val, y_train, y_val = train_test_split(
819            X, y, test_size=0.2, random_state=random_state
820        )
821
822        res = cross_val_score(
823            self, X_train, y_train, cv=cv, scoring=scoring, n_jobs=n_jobs
824        )  # cross-validation error
825
826        if penalized == False:
827            return res
828
829        DescribeResult = namedtuple(
830            "DescribeResult", ["cv_score", "val_score", "penalized_score"]
831        )
832
833        numerator = res.mean()
834
835        # Evaluate on the (cv+1)-th fold
836        preds_val = self.fit(X_train, y_train).predict(X_val)
837        try:
838            denominator = scoring(y_val, preds_val)  # validation error
839        except Exception as e:
840            denominator = scoring_func(y_val, preds_val)
841
842        # if higher is better
843        if objective == "abs":
844            penalized_score = np.abs(numerator - denominator) + epsilon * (
845                1 / denominator + 1 / numerator
846            )
847        elif objective == "relative":
848            ratio = numerator / denominator
849            penalized_score = np.abs(ratio - 1) + epsilon * (
850                1 / denominator + 1 / numerator
851            )
852
853        return DescribeResult(
854            cv_score=numerator,
855            val_score=denominator,
856            penalized_score=penalized_score,
857        )

Base model from which all the other classes inherit.

This class contains the most important data preprocessing/feature engineering methods.

Parameters:

n_hidden_features: int
    number of nodes in the hidden layer

activation_name: str
    activation function: 'relu', 'tanh', 'sigmoid', 'prelu' or 'elu'

a: float
    hyperparameter for 'prelu' or 'elu' activation function

nodes_sim: str
    type of simulation for hidden layer nodes: 'sobol', 'hammersley', 'halton',
    'uniform'

bias: boolean
    indicates if the hidden layer contains a bias term (True) or
    not (False)

dropout: float
    regularization parameter; (random) percentage of nodes dropped out
    of the training

direct_link: boolean
    indicates if the original features are included (True) in model's
    fitting or not (False)

n_clusters: int
    number of clusters for type_clust='kmeans' or type_clust='gmm'
    clustering (could be 0: no clustering)

cluster_encode: bool
    defines how the variable containing clusters is treated (default is one-hot);
    if `False`, then labels are used, without one-hot encoding

type_clust: str
    type of clustering method: currently k-means ('kmeans') or Gaussian
    Mixture Model ('gmm')

type_scaling: a tuple of 3 strings
    scaling methods for inputs, hidden layer, and clustering respectively
    (and when relevant).
    Currently available: standardization ('std') or MinMax scaling ('minmax') or robust scaling ('robust') or  max absolute scaling ('maxabs')

col_sample: float
    percentage of features randomly chosen for training

row_sample: float
    percentage of rows chosen for training, by stratified bootstrapping

seed: int
    reproducibility seed for nodes_sim=='uniform', clustering and dropout

backend: str
    "cpu" or "gpu" or "tpu"
def encode_clusters(self, X=None, predict=False, scaler=None, **kwargs):
246    def encode_clusters(self, X=None, predict=False, scaler=None, **kwargs):  #
247        """Create new covariates with kmeans or GMM clustering
248
249        Parameters:
250
251            X: {array-like}, shape = [n_samples, n_features]
252                Training vectors, where n_samples is the number
253                of samples and n_features is the number of features.
254
255            predict: boolean
256                is False on training set and True on test set
257
258            scaler: {object} of class StandardScaler, MinMaxScaler, RobustScaler or MaxAbsScaler
259                if scaler has already been fitted on training data (online training), it can be passed here
260
261            **kwargs:
262                additional parameters to be passed to the
263                clustering method
264
265        Returns:
266
267            Clusters' matrix, one-hot encoded: {array-like}
268
269        """
270
271        np.random.seed(self.seed)
272
273        if X is None:
274            X = self.X_
275
276        if isinstance(X, pd.DataFrame):
277            X = copy.deepcopy(X.values.astype(float))
278
279        if len(X.shape) == 1:
280            X = X.reshape(1, -1)
281
282        if predict is False:  # encode training set
283
284            # scale input data before clustering
285            self.clustering_scaler_, scaled_X = mo.scale_covariates(
286                X, choice=self.type_scaling[2], scaler=self.clustering_scaler_
287            )
288
289            self.clustering_obj_, X_clustered = mo.cluster_covariates(
290                scaled_X,
291                self.n_clusters,
292                self.seed,
293                type_clust=self.type_clust,
294                **kwargs
295            )
296
297            if self.cluster_encode == True:
298                return mo.one_hot_encode(X_clustered, self.n_clusters).astype(
299                    np.float16
300                )
301
302            return X_clustered.astype(np.float16)
303
304        # if predict == True, encode test set
305        X_clustered = self.clustering_obj_.predict(
306            self.clustering_scaler_.transform(X)
307        )
308
309        if self.cluster_encode == True:
310            return mo.one_hot_encode(X_clustered, self.n_clusters).astype(
311                np.float16
312            )
313
314        return X_clustered.astype(np.float16)

Create new covariates with kmeans or GMM clustering

Parameters:

X: {array-like}, shape = [n_samples, n_features]
    Training vectors, where n_samples is the number
    of samples and n_features is the number of features.

predict: boolean
    is False on training set and True on test set

scaler: {object} of class StandardScaler, MinMaxScaler, RobustScaler or MaxAbsScaler
    if scaler has already been fitted on training data (online training), it can be passed here

**kwargs:
    additional parameters to be passed to the
    clustering method

Returns:

Clusters' matrix, one-hot encoded: {array-like}
def create_layer(self, scaled_X, W=None):
316    def create_layer(self, scaled_X, W=None):
317        """Create hidden layer.
318
319        Parameters:
320
321            scaled_X: {array-like}, shape = [n_samples, n_features]
322                Training vectors, where n_samples is the number
323                of samples and n_features is the number of features
324
325            W: {array-like}, shape = [n_features, hidden_features]
326                if provided, constructs the hidden layer with W; otherwise computed internally
327
328        Returns:
329
330            Hidden layer matrix: {array-like}
331
332        """
333
334        n_features = scaled_X.shape[1]
335
336        # hash_sim = {
337        #         "sobol": generate_sobol,
338        #         "hammersley": generate_hammersley,
339        #         "uniform": generate_uniform,
340        #         "halton": generate_halton
341        #     }
342
343        if self.bias is False:  # no bias term in the hidden layer
344            if W is None:
345                if self.nodes_sim == "sobol":
346                    self.W_ = generate_sobol(
347                        n_dims=n_features,
348                        n_points=self.n_hidden_features,
349                        seed=self.seed,
350                    )
351                elif self.nodes_sim == "hammersley":
352                    self.W_ = generate_hammersley(
353                        n_dims=n_features,
354                        n_points=self.n_hidden_features,
355                        seed=self.seed,
356                    )
357                elif self.nodes_sim == "uniform":
358                    self.W_ = generate_uniform(
359                        n_dims=n_features,
360                        n_points=self.n_hidden_features,
361                        seed=self.seed,
362                    )
363                else:
364                    self.W_ = generate_halton(
365                        n_dims=n_features,
366                        n_points=self.n_hidden_features,
367                        seed=self.seed,
368                    )
369
370                # self.W_ = hash_sim[self.nodes_sim](
371                #             n_dims=n_features,
372                #             n_points=self.n_hidden_features,
373                #             seed=self.seed,
374                #         )
375
376                assert (
377                    scaled_X.shape[1] == self.W_.shape[0]
378                ), "check dimensions of covariates X and matrix W"
379
380                return mo.dropout(
381                    x=self.activation_func(
382                        mo.safe_sparse_dot(
383                            a=scaled_X, b=self.W_, backend=self.backend
384                        )
385                    ),
386                    drop_prob=self.dropout,
387                    seed=self.seed,
388                )
389
390            # W is not none
391            assert (
392                scaled_X.shape[1] == W.shape[0]
393            ), "check dimensions of covariates X and matrix W"
394
395            # self.W_ = W
396            return mo.dropout(
397                x=self.activation_func(
398                    mo.safe_sparse_dot(a=scaled_X, b=W, backend=self.backend)
399                ),
400                drop_prob=self.dropout,
401                seed=self.seed,
402            )
403
404        # with bias term in the hidden layer
405        if W is None:
406            n_features_1 = n_features + 1
407
408            if self.nodes_sim == "sobol":
409                self.W_ = generate_sobol(
410                    n_dims=n_features_1,
411                    n_points=self.n_hidden_features,
412                    seed=self.seed,
413                )
414            elif self.nodes_sim == "hammersley":
415                self.W_ = generate_hammersley(
416                    n_dims=n_features_1,
417                    n_points=self.n_hidden_features,
418                    seed=self.seed,
419                )
420            elif self.nodes_sim == "uniform":
421                self.W_ = generate_uniform(
422                    n_dims=n_features_1,
423                    n_points=self.n_hidden_features,
424                    seed=self.seed,
425                )
426            else:
427                self.W_ = generate_halton(
428                    n_dims=n_features_1,
429                    n_points=self.n_hidden_features,
430                    seed=self.seed,
431                )
432
433            # self.W_ = hash_sim[self.nodes_sim](
434            #         n_dims=n_features_1,
435            #         n_points=self.n_hidden_features,
436            #         seed=self.seed,
437            #     )
438
439            return mo.dropout(
440                x=self.activation_func(
441                    mo.safe_sparse_dot(
442                        a=mo.cbind(
443                            np.ones(scaled_X.shape[0]),
444                            scaled_X,
445                            backend=self.backend,
446                        ),
447                        b=self.W_,
448                        backend=self.backend,
449                    )
450                ),
451                drop_prob=self.dropout,
452                seed=self.seed,
453            )
454
455        # W is not None
456        # self.W_ = W
457        return mo.dropout(
458            x=self.activation_func(
459                mo.safe_sparse_dot(
460                    a=mo.cbind(
461                        np.ones(scaled_X.shape[0]),
462                        scaled_X,
463                        backend=self.backend,
464                    ),
465                    b=W,
466                    backend=self.backend,
467                )
468            ),
469            drop_prob=self.dropout,
470            seed=self.seed,
471        )

Create hidden layer.

Parameters:

scaled_X: {array-like}, shape = [n_samples, n_features]
    Training vectors, where n_samples is the number
    of samples and n_features is the number of features

W: {array-like}, shape = [n_features, hidden_features]
    if provided, constructs the hidden layer with W; otherwise computed internally

Returns:

Hidden layer matrix: {array-like}
def cook_training_set(self, y=None, X=None, W=None, **kwargs):
473    def cook_training_set(self, y=None, X=None, W=None, **kwargs):
474        """Create new hidden features for training set, with hidden layer, center the response.
475
476        Parameters:
477
478            y: array-like, shape = [n_samples]
479                Target values
480
481            X: {array-like}, shape = [n_samples, n_features]
482                Training vectors, where n_samples is the number
483                of samples and n_features is the number of features
484
485            W: {array-like}, shape = [n_features, hidden_features]
486                if provided, constructs the hidden layer via W
487
488        Returns:
489
490            (centered response, direct link + hidden layer matrix): {tuple}
491
492        """
493
494        # either X and y are stored or not
495        # assert ((y is None) & (X is None)) | ((y is not None) & (X is not None))
496        if self.n_hidden_features > 0:  # has a hidden layer
497            assert (
498                len(self.type_scaling) >= 2
499            ), "must have len(self.type_scaling) >= 2 when self.n_hidden_features > 0"
500
501        if X is None:
502
503            if self.col_sample == 1:
504                input_X = self.X_
505            else:
506                n_features = self.X_.shape[1]
507                new_n_features = int(np.ceil(n_features * self.col_sample))
508                assert (
509                    new_n_features >= 1
510                ), "check class attribute 'col_sample' and the number of covariates provided for X"
511                np.random.seed(self.seed)
512                index_col = np.random.choice(
513                    range(n_features), size=new_n_features, replace=False
514                )
515                self.index_col_ = index_col
516                input_X = self.X_[:, self.index_col_]
517
518        else:  # X is not None # keep X vs self.X_
519
520            if isinstance(X, pd.DataFrame):
521                X = copy.deepcopy(X.values.astype(float))
522
523            if self.col_sample == 1:
524                input_X = X
525            else:
526                n_features = X.shape[1]
527                new_n_features = int(np.ceil(n_features * self.col_sample))
528                assert (
529                    new_n_features >= 1
530                ), "check class attribute 'col_sample' and the number of covariates provided for X"
531                np.random.seed(self.seed)
532                index_col = np.random.choice(
533                    range(n_features), size=new_n_features, replace=False
534                )
535                self.index_col_ = index_col
536                input_X = X[:, self.index_col_]
537
538        if self.n_clusters <= 0:
539            # data without any clustering: self.n_clusters is None -----
540
541            if self.n_hidden_features > 0:  # with hidden layer
542
543                self.nn_scaler_, scaled_X = mo.scale_covariates(
544                    input_X, choice=self.type_scaling[1], scaler=self.nn_scaler_
545                )
546                Phi_X = (
547                    self.create_layer(scaled_X)
548                    if W is None
549                    else self.create_layer(scaled_X, W=W)
550                )
551                Z = (
552                    mo.cbind(input_X, Phi_X, backend=self.backend)
553                    if self.direct_link is True
554                    else Phi_X
555                )
556                self.scaler_, scaled_Z = mo.scale_covariates(
557                    Z, choice=self.type_scaling[0], scaler=self.scaler_
558                )
559            else:  # no hidden layer
560                Z = input_X
561                self.scaler_, scaled_Z = mo.scale_covariates(
562                    Z, choice=self.type_scaling[0], scaler=self.scaler_
563                )
564
565        else:
566
567            # data with clustering: self.n_clusters is not None ----- # keep
568
569            augmented_X = mo.cbind(
570                input_X,
571                self.encode_clusters(input_X, **kwargs),
572                backend=self.backend,
573            )
574
575            if self.n_hidden_features > 0:  # with hidden layer
576
577                self.nn_scaler_, scaled_X = mo.scale_covariates(
578                    augmented_X,
579                    choice=self.type_scaling[1],
580                    scaler=self.nn_scaler_,
581                )
582                Phi_X = (
583                    self.create_layer(scaled_X)
584                    if W is None
585                    else self.create_layer(scaled_X, W=W)
586                )
587                Z = (
588                    mo.cbind(augmented_X, Phi_X, backend=self.backend)
589                    if self.direct_link is True
590                    else Phi_X
591                )
592                self.scaler_, scaled_Z = mo.scale_covariates(
593                    Z, choice=self.type_scaling[0], scaler=self.scaler_
594                )
595            else:  # no hidden layer
596                Z = augmented_X
597                self.scaler_, scaled_Z = mo.scale_covariates(
598                    Z, choice=self.type_scaling[0], scaler=self.scaler_
599                )
600
601        # Returning model inputs -----
602        if mx.is_factor(y) is False:  # regression
603            # center y
604            if y is None:
605                self.y_mean_, centered_y = mo.center_response(self.y_)
606            else:
607                self.y_mean_, centered_y = mo.center_response(y)
608
609            # y is subsampled
610            if self.row_sample < 1:
611                n, p = Z.shape
612
613                self.subsampler_ = (
614                    SubSampler(
615                        y=self.y_, row_sample=self.row_sample, seed=self.seed
616                    )
617                    if y is None
618                    else SubSampler(
619                        y=y, row_sample=self.row_sample, seed=self.seed
620                    )
621                )
622
623                self.index_row_ = self.subsampler_.subsample()
624
625                n_row_sample = len(self.index_row_)
626                # regression
627                return (
628                    centered_y[self.index_row_].reshape(n_row_sample),
629                    self.scaler_.transform(
630                        Z[self.index_row_, :].reshape(n_row_sample, p)
631                    ),
632                )
633            # y is not subsampled
634            # regression
635            return (centered_y, self.scaler_.transform(Z))
636
637        # classification
638        # y is subsampled
639        if self.row_sample < 1:
640            n, p = Z.shape
641
642            self.subsampler_ = (
643                SubSampler(
644                    y=self.y_, row_sample=self.row_sample, seed=self.seed
645                )
646                if y is None
647                else SubSampler(y=y, row_sample=self.row_sample, seed=self.seed)
648            )
649
650            self.index_row_ = self.subsampler_.subsample()
651
652            n_row_sample = len(self.index_row_)
653            # classification
654            return (
655                y[self.index_row_].reshape(n_row_sample),
656                self.scaler_.transform(
657                    Z[self.index_row_, :].reshape(n_row_sample, p)
658                ),
659            )
660        # y is not subsampled
661        # classification
662        return (y, self.scaler_.transform(Z))

Create new hidden features for training set, with hidden layer, center the response.

Parameters:

y: array-like, shape = [n_samples]
    Target values

X: {array-like}, shape = [n_samples, n_features]
    Training vectors, where n_samples is the number
    of samples and n_features is the number of features

W: {array-like}, shape = [n_features, hidden_features]
    if provided, constructs the hidden layer via W

Returns:

(centered response, direct link + hidden layer matrix): {tuple}
def cook_test_set(self, X, **kwargs):
664    def cook_test_set(self, X, **kwargs):
665        """Transform data from test set, with hidden layer.
666
667        Parameters:
668
669            X: {array-like}, shape = [n_samples, n_features]
670                Training vectors, where n_samples is the number
671                of samples and n_features is the number of features
672
673            **kwargs: additional parameters to be passed to self.encode_cluster
674
675        Returns:
676
677            Transformed test set : {array-like}
678        """
679
680        if isinstance(X, pd.DataFrame):
681            X = copy.deepcopy(X.values.astype(float))
682
683        if len(X.shape) == 1:
684            X = X.reshape(1, -1)
685
686        if (
687            self.n_clusters == 0
688        ):  # data without clustering: self.n_clusters is None -----
689            if self.n_hidden_features > 0:
690                # if hidden layer
691                scaled_X = (
692                    self.nn_scaler_.transform(X)
693                    if (self.col_sample == 1)
694                    else self.nn_scaler_.transform(X[:, self.index_col_])
695                )
696                Phi_X = self.create_layer(scaled_X, self.W_)
697                if self.direct_link == True:
698                    return self.scaler_.transform(
699                        mo.cbind(scaled_X, Phi_X, backend=self.backend)
700                    )
701                # when self.direct_link == False
702                return self.scaler_.transform(Phi_X)
703            # if no hidden layer # self.n_hidden_features == 0
704            return self.scaler_.transform(X)
705
706        # data with clustering: self.n_clusters > 0 -----
707        if self.col_sample == 1:
708            predicted_clusters = self.encode_clusters(
709                X=X, predict=True, **kwargs
710            )
711            augmented_X = mo.cbind(X, predicted_clusters, backend=self.backend)
712        else:
713            predicted_clusters = self.encode_clusters(
714                X=X[:, self.index_col_], predict=True, **kwargs
715            )
716            augmented_X = mo.cbind(
717                X[:, self.index_col_], predicted_clusters, backend=self.backend
718            )
719
720        if self.n_hidden_features > 0:  # if hidden layer
721            scaled_X = self.nn_scaler_.transform(augmented_X)
722            Phi_X = self.create_layer(scaled_X, self.W_)
723            if self.direct_link == True:
724                return self.scaler_.transform(
725                    mo.cbind(augmented_X, Phi_X, backend=self.backend)
726                )
727            return self.scaler_.transform(Phi_X)
728
729        # if no hidden layer
730        return self.scaler_.transform(augmented_X)

Transform data from test set, with hidden layer.

Parameters:

X: {array-like}, shape = [n_samples, n_features]
    Training vectors, where n_samples is the number
    of samples and n_features is the number of features

**kwargs: additional parameters to be passed to self.encode_cluster

Returns:

Transformed test set : {array-like}
class BaseRegressor(nnetsauce.Base, sklearn.base.RegressorMixin):
 15class BaseRegressor(Base, RegressorMixin):
 16    """Random Vector Functional Link Network regression without shrinkage
 17
 18    Parameters:
 19
 20        n_hidden_features: int
 21            number of nodes in the hidden layer
 22
 23        activation_name: str
 24            activation function: 'relu', 'tanh', 'sigmoid', 'prelu' or 'elu'
 25
 26        a: float
 27            hyperparameter for 'prelu' or 'elu' activation function
 28
 29        nodes_sim: str
 30            type of simulation for hidden layer nodes: 'sobol', 'hammersley', 'halton',
 31            'uniform'
 32
 33        bias: boolean
 34            indicates if the hidden layer contains a bias term (True) or
 35            not (False)
 36
 37        dropout: float
 38            regularization parameter; (random) percentage of nodes dropped out
 39            of the training
 40
 41        direct_link: boolean
 42            indicates if the original features are included (True) in model's
 43            fitting or not (False)
 44
 45        n_clusters: int
 46            number of clusters for type_clust='kmeans' or type_clust='gmm'
 47            clustering (could be 0: no clustering)
 48
 49        cluster_encode: bool
 50            defines how the variable containing clusters is treated (default is one-hot);
 51            if `False`, then labels are used, without one-hot encoding
 52
 53        type_clust: str
 54            type of clustering method: currently k-means ('kmeans') or Gaussian
 55            Mixture Model ('gmm')
 56
 57        type_scaling: a tuple of 3 strings
 58            scaling methods for inputs, hidden layer, and clustering respectively
 59            (and when relevant).
 60            Currently available: standardization ('std') or MinMax scaling ('minmax')
 61
 62        col_sample: float
 63            percentage of features randomly chosen for training
 64
 65        row_sample: float
 66            percentage of rows chosen for training, by stratified bootstrapping
 67
 68        seed: int
 69            reproducibility seed for nodes_sim=='uniform', clustering and dropout
 70
 71        backend: str
 72            "cpu" or "gpu" or "tpu"
 73
 74    Attributes:
 75
 76        beta_: vector
 77            regression coefficients
 78
 79        GCV_: float
 80            Generalized Cross-Validation error
 81
 82    """
 83
 84    # construct the object -----
 85
 86    def __init__(
 87        self,
 88        n_hidden_features=5,
 89        activation_name="relu",
 90        a=0.01,
 91        nodes_sim="sobol",
 92        bias=True,
 93        dropout=0,
 94        direct_link=True,
 95        n_clusters=2,
 96        cluster_encode=True,
 97        type_clust="kmeans",
 98        type_scaling=("std", "std", "std"),
 99        col_sample=1,
100        row_sample=1,
101        seed=123,
102        backend="cpu",
103    ):
104        super().__init__(
105            n_hidden_features=n_hidden_features,
106            activation_name=activation_name,
107            a=a,
108            nodes_sim=nodes_sim,
109            bias=bias,
110            dropout=dropout,
111            direct_link=direct_link,
112            n_clusters=n_clusters,
113            cluster_encode=cluster_encode,
114            type_clust=type_clust,
115            type_scaling=type_scaling,
116            col_sample=col_sample,
117            row_sample=row_sample,
118            seed=seed,
119            backend=backend,
120        )
121
122    def fit(self, X, y, **kwargs):
123        """Fit BaseRegressor to training data (X, y)
124
125        Parameters:
126
127            X: {array-like}, shape = [n_samples, n_features]
128                Training vectors, where n_samples is the number
129                of samples and n_features is the number of features
130
131            y: array-like, shape = [n_samples]
132                Target values
133
134            **kwargs: additional parameters to be passed to self.cook_training_set
135
136        Returns:
137
138            self: object
139        """
140
141        centered_y, scaled_Z = self.cook_training_set(y=y, X=X, **kwargs)
142
143        fit_obj = lmf.beta_Sigma_hat(
144            X=scaled_Z, y=centered_y, backend=self.backend
145        )
146
147        self.beta_ = fit_obj["beta_hat"]
148
149        self.GCV_ = fit_obj["GCV"]
150
151        return self
152
153    def predict(self, X, **kwargs):
154        """Predict test data X.
155
156        Parameters:
157
158            X: {array-like}, shape = [n_samples, n_features]
159                Training vectors, where n_samples is the number
160                of samples and n_features is the number of features
161
162            **kwargs: additional parameters to be passed to self.cook_test_set
163
164        Returns:
165
166            model predictions: {array-like}
167        """
168
169        if len(X.shape) == 1:
170            n_features = X.shape[0]
171            new_X = mo.rbind(
172                X.reshape(1, n_features),
173                np.ones(n_features).reshape(1, n_features),
174            )
175
176            return (
177                self.y_mean_
178                + mo.safe_sparse_dot(
179                    a=self.cook_test_set(new_X, **kwargs),
180                    b=self.beta_,
181                    backend=self.backend,
182                )
183            )[0]
184
185        return self.y_mean_ + mo.safe_sparse_dot(
186            a=self.cook_test_set(X, **kwargs),
187            b=self.beta_,
188            backend=self.backend,
189        )

Random Vector Functional Link Network regression without shrinkage

Parameters:

n_hidden_features: int
    number of nodes in the hidden layer

activation_name: str
    activation function: 'relu', 'tanh', 'sigmoid', 'prelu' or 'elu'

a: float
    hyperparameter for 'prelu' or 'elu' activation function

nodes_sim: str
    type of simulation for hidden layer nodes: 'sobol', 'hammersley', 'halton',
    'uniform'

bias: boolean
    indicates if the hidden layer contains a bias term (True) or
    not (False)

dropout: float
    regularization parameter; (random) percentage of nodes dropped out
    of the training

direct_link: boolean
    indicates if the original features are included (True) in model's
    fitting or not (False)

n_clusters: int
    number of clusters for type_clust='kmeans' or type_clust='gmm'
    clustering (could be 0: no clustering)

cluster_encode: bool
    defines how the variable containing clusters is treated (default is one-hot);
    if `False`, then labels are used, without one-hot encoding

type_clust: str
    type of clustering method: currently k-means ('kmeans') or Gaussian
    Mixture Model ('gmm')

type_scaling: a tuple of 3 strings
    scaling methods for inputs, hidden layer, and clustering respectively
    (and when relevant).
    Currently available: standardization ('std') or MinMax scaling ('minmax')

col_sample: float
    percentage of features randomly chosen for training

row_sample: float
    percentage of rows chosen for training, by stratified bootstrapping

seed: int
    reproducibility seed for nodes_sim=='uniform', clustering and dropout

backend: str
    "cpu" or "gpu" or "tpu"

Attributes:

beta_: vector
    regression coefficients

GCV_: float
    Generalized Cross-Validation error
def fit(self, X, y, **kwargs):
122    def fit(self, X, y, **kwargs):
123        """Fit BaseRegressor to training data (X, y)
124
125        Parameters:
126
127            X: {array-like}, shape = [n_samples, n_features]
128                Training vectors, where n_samples is the number
129                of samples and n_features is the number of features
130
131            y: array-like, shape = [n_samples]
132                Target values
133
134            **kwargs: additional parameters to be passed to self.cook_training_set
135
136        Returns:
137
138            self: object
139        """
140
141        centered_y, scaled_Z = self.cook_training_set(y=y, X=X, **kwargs)
142
143        fit_obj = lmf.beta_Sigma_hat(
144            X=scaled_Z, y=centered_y, backend=self.backend
145        )
146
147        self.beta_ = fit_obj["beta_hat"]
148
149        self.GCV_ = fit_obj["GCV"]
150
151        return self

Fit BaseRegressor to training data (X, y)

Parameters:

X: {array-like}, shape = [n_samples, n_features]
    Training vectors, where n_samples is the number
    of samples and n_features is the number of features

y: array-like, shape = [n_samples]
    Target values

**kwargs: additional parameters to be passed to self.cook_training_set

Returns:

self: object
def predict(self, X, **kwargs):
153    def predict(self, X, **kwargs):
154        """Predict test data X.
155
156        Parameters:
157
158            X: {array-like}, shape = [n_samples, n_features]
159                Training vectors, where n_samples is the number
160                of samples and n_features is the number of features
161
162            **kwargs: additional parameters to be passed to self.cook_test_set
163
164        Returns:
165
166            model predictions: {array-like}
167        """
168
169        if len(X.shape) == 1:
170            n_features = X.shape[0]
171            new_X = mo.rbind(
172                X.reshape(1, n_features),
173                np.ones(n_features).reshape(1, n_features),
174            )
175
176            return (
177                self.y_mean_
178                + mo.safe_sparse_dot(
179                    a=self.cook_test_set(new_X, **kwargs),
180                    b=self.beta_,
181                    backend=self.backend,
182                )
183            )[0]
184
185        return self.y_mean_ + mo.safe_sparse_dot(
186            a=self.cook_test_set(X, **kwargs),
187            b=self.beta_,
188            backend=self.backend,
189        )

Predict test data X.

Parameters:

X: {array-like}, shape = [n_samples, n_features]
    Training vectors, where n_samples is the number
    of samples and n_features is the number of features

**kwargs: additional parameters to be passed to self.cook_test_set

Returns:

model predictions: {array-like}
class BayesianRVFLRegressor(nnetsauce.Base, sklearn.base.RegressorMixin):
 15class BayesianRVFLRegressor(Base, RegressorMixin):
 16    """Bayesian Random Vector Functional Link Network regression with one prior
 17
 18    Parameters:
 19
 20        n_hidden_features: int
 21            number of nodes in the hidden layer
 22
 23        activation_name: str
 24            activation function: 'relu', 'tanh', 'sigmoid', 'prelu' or 'elu'
 25
 26        a: float
 27            hyperparameter for 'prelu' or 'elu' activation function
 28
 29        nodes_sim: str
 30            type of simulation for the nodes: 'sobol', 'hammersley', 'halton', 'uniform'
 31
 32        bias: boolean
 33            indicates if the hidden layer contains a bias term (True) or not (False)
 34
 35        dropout: float
 36            regularization parameter; (random) percentage of nodes dropped out
 37            of the training
 38
 39        direct_link: boolean
 40            indicates if the original features are included (True) in model''s fitting or not (False)
 41
 42        n_clusters: int
 43            number of clusters for 'kmeans' or 'gmm' clustering (could be 0: no clustering)
 44
 45        cluster_encode: bool
 46            defines how the variable containing clusters is treated (default is one-hot)
 47            if `False`, then labels are used, without one-hot encoding
 48
 49        type_clust: str
 50            type of clustering method: currently k-means ('kmeans') or Gaussian Mixture Model ('gmm')
 51
 52        type_scaling: a tuple of 3 strings
 53            scaling methods for inputs, hidden layer, and clustering respectively
 54            (and when relevant).
 55            Currently available: standardization ('std') or MinMax scaling ('minmax')
 56
 57        seed: int
 58            reproducibility seed for nodes_sim=='uniform'
 59
 60        s: float
 61            std. dev. of regression parameters in Bayesian Ridge Regression
 62
 63        sigma: float
 64            std. dev. of residuals in Bayesian Ridge Regression
 65
 66        return_std: boolean
 67            if True, uncertainty around predictions is evaluated
 68
 69        backend: str
 70            "cpu" or "gpu" or "tpu"
 71
 72    Attributes:
 73
 74        beta_: array-like
 75            regression''s coefficients
 76
 77        Sigma_: array-like
 78            covariance of the distribution of fitted parameters
 79
 80        GCV_: float
 81            Generalized cross-validation error
 82
 83        y_mean_: float
 84            average response
 85
 86    Examples:
 87
 88    ```python
 89    TBD
 90    ```
 91
 92    """
 93
 94    # construct the object -----
 95
 96    def __init__(
 97        self,
 98        n_hidden_features=5,
 99        activation_name="relu",
100        a=0.01,
101        nodes_sim="sobol",
102        bias=True,
103        dropout=0,
104        direct_link=True,
105        n_clusters=2,
106        cluster_encode=True,
107        type_clust="kmeans",
108        type_scaling=("std", "std", "std"),
109        seed=123,
110        s=0.1,
111        sigma=0.05,
112        return_std=True,
113        backend="cpu",
114    ):
115        super().__init__(
116            n_hidden_features=n_hidden_features,
117            activation_name=activation_name,
118            a=a,
119            nodes_sim=nodes_sim,
120            bias=bias,
121            dropout=dropout,
122            direct_link=direct_link,
123            n_clusters=n_clusters,
124            cluster_encode=cluster_encode,
125            type_clust=type_clust,
126            type_scaling=type_scaling,
127            seed=seed,
128            backend=backend,
129        )
130        self.s = s
131        self.sigma = sigma
132        self.beta_ = None
133        self.Sigma_ = None
134        self.GCV_ = None
135        self.return_std = return_std
136
137    def fit(self, X, y, **kwargs):
138        """Fit BayesianRVFLRegressor to training data (X, y).
139
140        Parameters:
141
142            X: {array-like}, shape = [n_samples, n_features]
143                Training vectors, where n_samples is the number
144                of samples and n_features is the number of features.
145
146            y: array-like, shape = [n_samples]
147                Target values.
148
149            **kwargs: additional parameters to be passed to
150                    self.cook_training_set
151
152        Returns:
153
154            self: object
155
156        """
157
158        centered_y, scaled_Z = self.cook_training_set(y=y, X=X, **kwargs)
159
160        fit_obj = lmf.beta_Sigma_hat_rvfl(
161            X=scaled_Z,
162            y=centered_y,
163            s=self.s,
164            sigma=self.sigma,
165            fit_intercept=False,
166            return_cov=self.return_std,
167            backend=self.backend,
168        )
169
170        self.beta_ = fit_obj["beta_hat"]
171
172        if self.return_std == True:
173            self.Sigma_ = fit_obj["Sigma_hat"]
174
175        self.GCV_ = fit_obj["GCV"]
176
177        return self
178
179    def predict(self, X, return_std=False, **kwargs):
180        """Predict test data X.
181
182        Parameters:
183
184            X: {array-like}, shape = [n_samples, n_features]
185                Training vectors, where n_samples is the number
186                of samples and n_features is the number of features.
187
188            return_std: {boolean}, standard dev. is returned or not
189
190            **kwargs: additional parameters to be passed to
191                    self.cook_test_set
192
193        Returns:
194
195            model predictions: {array-like}
196
197        """
198
199        if len(X.shape) == 1:  # one observation in the test set only
200            n_features = X.shape[0]
201            new_X = mo.rbind(
202                x=X.reshape(1, n_features),
203                y=np.ones(n_features).reshape(1, n_features),
204                backend=self.backend,
205            )
206
207        self.return_std = return_std
208
209        if self.return_std == False:
210            if len(X.shape) == 1:
211                return (
212                    self.y_mean_
213                    + mo.safe_sparse_dot(
214                        a=self.cook_test_set(new_X, **kwargs),
215                        b=self.beta_,
216                        backend=self.backend,
217                    )
218                )[0]
219
220            return self.y_mean_ + mo.safe_sparse_dot(
221                a=self.cook_test_set(X, **kwargs),
222                b=self.beta_,
223                backend=self.backend,
224            )
225
226        else:  # confidence interval required for preds?
227            if len(X.shape) == 1:
228                Z = self.cook_test_set(new_X, **kwargs)
229
230                pred_obj = lmf.beta_Sigma_hat_rvfl(
231                    s=self.s,
232                    sigma=self.sigma,
233                    X_star=Z,
234                    return_cov=True,
235                    beta_hat_=self.beta_,
236                    Sigma_hat_=self.Sigma_,
237                    backend=self.backend,
238                )
239
240                return (
241                    self.y_mean_ + pred_obj["preds"][0],
242                    pred_obj["preds_std"][0],
243                )
244
245            Z = self.cook_test_set(X, **kwargs)
246
247            pred_obj = lmf.beta_Sigma_hat_rvfl(
248                s=self.s,
249                sigma=self.sigma,
250                X_star=Z,
251                return_cov=True,
252                beta_hat_=self.beta_,
253                Sigma_hat_=self.Sigma_,
254                backend=self.backend,
255            )
256
257            return (self.y_mean_ + pred_obj["preds"], pred_obj["preds_std"])

Bayesian Random Vector Functional Link Network regression with one prior

Parameters:

n_hidden_features: int
    number of nodes in the hidden layer

activation_name: str
    activation function: 'relu', 'tanh', 'sigmoid', 'prelu' or 'elu'

a: float
    hyperparameter for 'prelu' or 'elu' activation function

nodes_sim: str
    type of simulation for the nodes: 'sobol', 'hammersley', 'halton', 'uniform'

bias: boolean
    indicates if the hidden layer contains a bias term (True) or not (False)

dropout: float
    regularization parameter; (random) percentage of nodes dropped out
    of the training

direct_link: boolean
    indicates if the original features are included (True) in model''s fitting or not (False)

n_clusters: int
    number of clusters for 'kmeans' or 'gmm' clustering (could be 0: no clustering)

cluster_encode: bool
    defines how the variable containing clusters is treated (default is one-hot)
    if `False`, then labels are used, without one-hot encoding

type_clust: str
    type of clustering method: currently k-means ('kmeans') or Gaussian Mixture Model ('gmm')

type_scaling: a tuple of 3 strings
    scaling methods for inputs, hidden layer, and clustering respectively
    (and when relevant).
    Currently available: standardization ('std') or MinMax scaling ('minmax')

seed: int
    reproducibility seed for nodes_sim=='uniform'

s: float
    std. dev. of regression parameters in Bayesian Ridge Regression

sigma: float
    std. dev. of residuals in Bayesian Ridge Regression

return_std: boolean
    if True, uncertainty around predictions is evaluated

backend: str
    "cpu" or "gpu" or "tpu"

Attributes:

beta_: array-like
    regression''s coefficients

Sigma_: array-like
    covariance of the distribution of fitted parameters

GCV_: float
    Generalized cross-validation error

y_mean_: float
    average response

Examples:

TBD
def fit(self, X, y, **kwargs):
137    def fit(self, X, y, **kwargs):
138        """Fit BayesianRVFLRegressor to training data (X, y).
139
140        Parameters:
141
142            X: {array-like}, shape = [n_samples, n_features]
143                Training vectors, where n_samples is the number
144                of samples and n_features is the number of features.
145
146            y: array-like, shape = [n_samples]
147                Target values.
148
149            **kwargs: additional parameters to be passed to
150                    self.cook_training_set
151
152        Returns:
153
154            self: object
155
156        """
157
158        centered_y, scaled_Z = self.cook_training_set(y=y, X=X, **kwargs)
159
160        fit_obj = lmf.beta_Sigma_hat_rvfl(
161            X=scaled_Z,
162            y=centered_y,
163            s=self.s,
164            sigma=self.sigma,
165            fit_intercept=False,
166            return_cov=self.return_std,
167            backend=self.backend,
168        )
169
170        self.beta_ = fit_obj["beta_hat"]
171
172        if self.return_std == True:
173            self.Sigma_ = fit_obj["Sigma_hat"]
174
175        self.GCV_ = fit_obj["GCV"]
176
177        return self

Fit BayesianRVFLRegressor to training data (X, y).

Parameters:

X: {array-like}, shape = [n_samples, n_features]
    Training vectors, where n_samples is the number
    of samples and n_features is the number of features.

y: array-like, shape = [n_samples]
    Target values.

**kwargs: additional parameters to be passed to
        self.cook_training_set

Returns:

self: object
def predict(self, X, return_std=False, **kwargs):
179    def predict(self, X, return_std=False, **kwargs):
180        """Predict test data X.
181
182        Parameters:
183
184            X: {array-like}, shape = [n_samples, n_features]
185                Training vectors, where n_samples is the number
186                of samples and n_features is the number of features.
187
188            return_std: {boolean}, standard dev. is returned or not
189
190            **kwargs: additional parameters to be passed to
191                    self.cook_test_set
192
193        Returns:
194
195            model predictions: {array-like}
196
197        """
198
199        if len(X.shape) == 1:  # one observation in the test set only
200            n_features = X.shape[0]
201            new_X = mo.rbind(
202                x=X.reshape(1, n_features),
203                y=np.ones(n_features).reshape(1, n_features),
204                backend=self.backend,
205            )
206
207        self.return_std = return_std
208
209        if self.return_std == False:
210            if len(X.shape) == 1:
211                return (
212                    self.y_mean_
213                    + mo.safe_sparse_dot(
214                        a=self.cook_test_set(new_X, **kwargs),
215                        b=self.beta_,
216                        backend=self.backend,
217                    )
218                )[0]
219
220            return self.y_mean_ + mo.safe_sparse_dot(
221                a=self.cook_test_set(X, **kwargs),
222                b=self.beta_,
223                backend=self.backend,
224            )
225
226        else:  # confidence interval required for preds?
227            if len(X.shape) == 1:
228                Z = self.cook_test_set(new_X, **kwargs)
229
230                pred_obj = lmf.beta_Sigma_hat_rvfl(
231                    s=self.s,
232                    sigma=self.sigma,
233                    X_star=Z,
234                    return_cov=True,
235                    beta_hat_=self.beta_,
236                    Sigma_hat_=self.Sigma_,
237                    backend=self.backend,
238                )
239
240                return (
241                    self.y_mean_ + pred_obj["preds"][0],
242                    pred_obj["preds_std"][0],
243                )
244
245            Z = self.cook_test_set(X, **kwargs)
246
247            pred_obj = lmf.beta_Sigma_hat_rvfl(
248                s=self.s,
249                sigma=self.sigma,
250                X_star=Z,
251                return_cov=True,
252                beta_hat_=self.beta_,
253                Sigma_hat_=self.Sigma_,
254                backend=self.backend,
255            )
256
257            return (self.y_mean_ + pred_obj["preds"], pred_obj["preds_std"])

Predict test data X.

Parameters:

X: {array-like}, shape = [n_samples, n_features]
    Training vectors, where n_samples is the number
    of samples and n_features is the number of features.

return_std: {boolean}, standard dev. is returned or not

**kwargs: additional parameters to be passed to
        self.cook_test_set

Returns:

model predictions: {array-like}
class BayesianRVFL2Regressor(nnetsauce.Base, sklearn.base.RegressorMixin):
 15class BayesianRVFL2Regressor(Base, RegressorMixin):
 16    """Bayesian Random Vector Functional Link Network regression with two priors
 17
 18    Parameters:
 19
 20        n_hidden_features: int
 21            number of nodes in the hidden layer
 22
 23        activation_name: str
 24            activation function: 'relu', 'tanh', 'sigmoid', 'prelu' or 'elu'
 25
 26        a: float
 27            hyperparameter for 'prelu' or 'elu' activation function
 28
 29        nodes_sim: str
 30            type of simulation for the nodes: 'sobol', 'hammersley', 'halton', 'uniform'
 31
 32        bias: boolean
 33            indicates if the hidden layer contains a bias term (True) or not (False)
 34
 35        dropout: float
 36            regularization parameter; (random) percentage of nodes dropped out
 37            of the training
 38
 39        direct_link: boolean
 40            indicates if the original features are included (True) in model''s fitting or not (False)
 41
 42        n_clusters: int
 43            number of clusters for 'kmeans' or 'gmm' clustering (could be 0: no clustering)
 44
 45        cluster_encode: bool
 46            defines how the variable containing clusters is treated (default is one-hot)
 47            if `False`, then labels are used, without one-hot encoding
 48
 49        type_clust: str
 50            type of clustering method: currently k-means ('kmeans') or Gaussian Mixture Model ('gmm')
 51
 52        type_scaling: a tuple of 3 strings
 53            scaling methods for inputs, hidden layer, and clustering respectively
 54            (and when relevant).
 55            Currently available: standardization ('std') or MinMax scaling ('minmax')
 56
 57        seed: int
 58            reproducibility seed for nodes_sim=='uniform'
 59
 60        s1: float
 61            std. dev. of init. regression parameters in Bayesian Ridge Regression
 62
 63        s2: float
 64            std. dev. of augmented regression parameters in Bayesian Ridge Regression
 65
 66        sigma: float
 67            std. dev. of residuals in Bayesian Ridge Regression
 68
 69        return_std: boolean
 70            if True, uncertainty around predictions is evaluated
 71
 72        backend: str
 73            "cpu" or "gpu" or "tpu"
 74
 75    Attributes:
 76
 77        beta_: array-like
 78            regression''s coefficients
 79
 80        Sigma_: array-like
 81            covariance of the distribution of fitted parameters
 82
 83        GCV_: float
 84            Generalized cross-validation error
 85
 86        y_mean_: float
 87            average response
 88
 89    Examples:
 90
 91    ```python
 92    TBD
 93    ```
 94
 95    """
 96
 97    # construct the object -----
 98
 99    def __init__(
100        self,
101        n_hidden_features=5,
102        activation_name="relu",
103        a=0.01,
104        nodes_sim="sobol",
105        bias=True,
106        dropout=0,
107        direct_link=True,
108        n_clusters=0,
109        cluster_encode=True,
110        type_clust="kmeans",
111        type_scaling=("std", "std", "std"),
112        seed=123,
113        s1=0.1,
114        s2=0.1,
115        sigma=0.05,
116        return_std=True,
117        backend="cpu",
118    ):
119        super().__init__(
120            n_hidden_features=n_hidden_features,
121            activation_name=activation_name,
122            a=a,
123            nodes_sim=nodes_sim,
124            bias=bias,
125            dropout=dropout,
126            direct_link=direct_link,
127            n_clusters=n_clusters,
128            cluster_encode=cluster_encode,
129            type_clust=type_clust,
130            type_scaling=type_scaling,
131            seed=seed,
132            backend=backend,
133        )
134
135        self.s1 = s1
136        self.s2 = s2
137        self.sigma = sigma
138        self.beta_ = None
139        self.Sigma_ = None
140        self.GCV_ = None
141        self.return_std = return_std
142
143    def fit(self, X, y, **kwargs):
144        """Fit BayesianRVFL2Regressor to training data (X, y)
145
146        Parameters:
147
148            X: {array-like}, shape = [n_samples, n_features]
149                Training vectors, where n_samples is the number
150                of samples and n_features is the number of features
151
152            y: array-like, shape = [n_samples]
153                Target values
154
155            **kwargs: additional parameters to be passed to
156                    self.cook_training_set
157
158        Returns:
159
160            self: object
161
162        """
163
164        centered_y, scaled_Z = self.cook_training_set(y=y, X=X, **kwargs)
165
166        n, p = X.shape
167        q = self.n_hidden_features
168
169        if self.direct_link == True:
170            r = p + self.n_clusters
171
172            block11 = (self.s1**2) * np.eye(r)
173            block12 = np.zeros((r, q))
174            block21 = np.zeros((q, r))
175            block22 = (self.s2**2) * np.eye(q)
176
177            Sigma_prior = mo.rbind(
178                x=mo.cbind(x=block11, y=block12, backend=self.backend),
179                y=mo.cbind(x=block21, y=block22, backend=self.backend),
180                backend=self.backend,
181            )
182
183        else:
184            Sigma_prior = (self.s2**2) * np.eye(q)
185
186        fit_obj = lmf.beta_Sigma_hat_rvfl2(
187            X=scaled_Z,
188            y=centered_y,
189            Sigma=Sigma_prior,
190            sigma=self.sigma,
191            fit_intercept=False,
192            return_cov=self.return_std,
193            backend=self.backend,
194        )
195
196        self.beta_ = fit_obj["beta_hat"]
197
198        if self.return_std == True:
199            self.Sigma_ = fit_obj["Sigma_hat"]
200
201        self.GCV_ = fit_obj["GCV"]
202
203        return self
204
205    def predict(self, X, return_std=False, **kwargs):
206        """Predict test data X.
207
208        Parameters:
209
210            X: {array-like}, shape = [n_samples, n_features]
211                Training vectors, where n_samples is the number
212                of samples and n_features is the number of features.
213
214            return_std: {boolean}, standard dev. is returned or not
215
216            **kwargs: additional parameters to be passed to
217                    self.cook_test_set
218
219        Returns:
220
221            model predictions: {array-like}
222
223        """
224
225        if len(X.shape) == 1:  # one observation in the test set only
226            n_features = X.shape[0]
227            new_X = mo.rbind(
228                x=X.reshape(1, n_features),
229                y=np.ones(n_features).reshape(1, n_features),
230                backend=self.backend,
231            )
232
233        self.return_std = return_std
234
235        if self.return_std == False:
236            if len(X.shape) == 1:
237                return (
238                    self.y_mean_
239                    + mo.safe_sparse_dot(
240                        self.cook_test_set(new_X, **kwargs),
241                        self.beta_,
242                        backend=self.backend,
243                    )
244                )[0]
245
246            return self.y_mean_ + mo.safe_sparse_dot(
247                self.cook_test_set(X, **kwargs),
248                self.beta_,
249                backend=self.backend,
250            )
251
252        else:  # confidence interval required for preds?
253            if len(X.shape) == 1:
254                Z = self.cook_test_set(new_X, **kwargs)
255
256                pred_obj = lmf.beta_Sigma_hat_rvfl2(
257                    X_star=Z,
258                    return_cov=self.return_std,
259                    beta_hat_=self.beta_,
260                    Sigma_hat_=self.Sigma_,
261                    backend=self.backend,
262                )
263
264                return (
265                    self.y_mean_ + pred_obj["preds"][0],
266                    pred_obj["preds_std"][0],
267                )
268
269            Z = self.cook_test_set(X, **kwargs)
270
271            pred_obj = lmf.beta_Sigma_hat_rvfl2(
272                X_star=Z,
273                return_cov=self.return_std,
274                beta_hat_=self.beta_,
275                Sigma_hat_=self.Sigma_,
276                backend=self.backend,
277            )
278
279            return (self.y_mean_ + pred_obj["preds"], pred_obj["preds_std"])

Bayesian Random Vector Functional Link Network regression with two priors

Parameters:

n_hidden_features: int
    number of nodes in the hidden layer

activation_name: str
    activation function: 'relu', 'tanh', 'sigmoid', 'prelu' or 'elu'

a: float
    hyperparameter for 'prelu' or 'elu' activation function

nodes_sim: str
    type of simulation for the nodes: 'sobol', 'hammersley', 'halton', 'uniform'

bias: boolean
    indicates if the hidden layer contains a bias term (True) or not (False)

dropout: float
    regularization parameter; (random) percentage of nodes dropped out
    of the training

direct_link: boolean
    indicates if the original features are included (True) in model''s fitting or not (False)

n_clusters: int
    number of clusters for 'kmeans' or 'gmm' clustering (could be 0: no clustering)

cluster_encode: bool
    defines how the variable containing clusters is treated (default is one-hot)
    if `False`, then labels are used, without one-hot encoding

type_clust: str
    type of clustering method: currently k-means ('kmeans') or Gaussian Mixture Model ('gmm')

type_scaling: a tuple of 3 strings
    scaling methods for inputs, hidden layer, and clustering respectively
    (and when relevant).
    Currently available: standardization ('std') or MinMax scaling ('minmax')

seed: int
    reproducibility seed for nodes_sim=='uniform'

s1: float
    std. dev. of init. regression parameters in Bayesian Ridge Regression

s2: float
    std. dev. of augmented regression parameters in Bayesian Ridge Regression

sigma: float
    std. dev. of residuals in Bayesian Ridge Regression

return_std: boolean
    if True, uncertainty around predictions is evaluated

backend: str
    "cpu" or "gpu" or "tpu"

Attributes:

beta_: array-like
    regression''s coefficients

Sigma_: array-like
    covariance of the distribution of fitted parameters

GCV_: float
    Generalized cross-validation error

y_mean_: float
    average response

Examples:

TBD
def fit(self, X, y, **kwargs):
143    def fit(self, X, y, **kwargs):
144        """Fit BayesianRVFL2Regressor to training data (X, y)
145
146        Parameters:
147
148            X: {array-like}, shape = [n_samples, n_features]
149                Training vectors, where n_samples is the number
150                of samples and n_features is the number of features
151
152            y: array-like, shape = [n_samples]
153                Target values
154
155            **kwargs: additional parameters to be passed to
156                    self.cook_training_set
157
158        Returns:
159
160            self: object
161
162        """
163
164        centered_y, scaled_Z = self.cook_training_set(y=y, X=X, **kwargs)
165
166        n, p = X.shape
167        q = self.n_hidden_features
168
169        if self.direct_link == True:
170            r = p + self.n_clusters
171
172            block11 = (self.s1**2) * np.eye(r)
173            block12 = np.zeros((r, q))
174            block21 = np.zeros((q, r))
175            block22 = (self.s2**2) * np.eye(q)
176
177            Sigma_prior = mo.rbind(
178                x=mo.cbind(x=block11, y=block12, backend=self.backend),
179                y=mo.cbind(x=block21, y=block22, backend=self.backend),
180                backend=self.backend,
181            )
182
183        else:
184            Sigma_prior = (self.s2**2) * np.eye(q)
185
186        fit_obj = lmf.beta_Sigma_hat_rvfl2(
187            X=scaled_Z,
188            y=centered_y,
189            Sigma=Sigma_prior,
190            sigma=self.sigma,
191            fit_intercept=False,
192            return_cov=self.return_std,
193            backend=self.backend,
194        )
195
196        self.beta_ = fit_obj["beta_hat"]
197
198        if self.return_std == True:
199            self.Sigma_ = fit_obj["Sigma_hat"]
200
201        self.GCV_ = fit_obj["GCV"]
202
203        return self

Fit BayesianRVFL2Regressor to training data (X, y)

Parameters:

X: {array-like}, shape = [n_samples, n_features]
    Training vectors, where n_samples is the number
    of samples and n_features is the number of features

y: array-like, shape = [n_samples]
    Target values

**kwargs: additional parameters to be passed to
        self.cook_training_set

Returns:

self: object
def predict(self, X, return_std=False, **kwargs):
205    def predict(self, X, return_std=False, **kwargs):
206        """Predict test data X.
207
208        Parameters:
209
210            X: {array-like}, shape = [n_samples, n_features]
211                Training vectors, where n_samples is the number
212                of samples and n_features is the number of features.
213
214            return_std: {boolean}, standard dev. is returned or not
215
216            **kwargs: additional parameters to be passed to
217                    self.cook_test_set
218
219        Returns:
220
221            model predictions: {array-like}
222
223        """
224
225        if len(X.shape) == 1:  # one observation in the test set only
226            n_features = X.shape[0]
227            new_X = mo.rbind(
228                x=X.reshape(1, n_features),
229                y=np.ones(n_features).reshape(1, n_features),
230                backend=self.backend,
231            )
232
233        self.return_std = return_std
234
235        if self.return_std == False:
236            if len(X.shape) == 1:
237                return (
238                    self.y_mean_
239                    + mo.safe_sparse_dot(
240                        self.cook_test_set(new_X, **kwargs),
241                        self.beta_,
242                        backend=self.backend,
243                    )
244                )[0]
245
246            return self.y_mean_ + mo.safe_sparse_dot(
247                self.cook_test_set(X, **kwargs),
248                self.beta_,
249                backend=self.backend,
250            )
251
252        else:  # confidence interval required for preds?
253            if len(X.shape) == 1:
254                Z = self.cook_test_set(new_X, **kwargs)
255
256                pred_obj = lmf.beta_Sigma_hat_rvfl2(
257                    X_star=Z,
258                    return_cov=self.return_std,
259                    beta_hat_=self.beta_,
260                    Sigma_hat_=self.Sigma_,
261                    backend=self.backend,
262                )
263
264                return (
265                    self.y_mean_ + pred_obj["preds"][0],
266                    pred_obj["preds_std"][0],
267                )
268
269            Z = self.cook_test_set(X, **kwargs)
270
271            pred_obj = lmf.beta_Sigma_hat_rvfl2(
272                X_star=Z,
273                return_cov=self.return_std,
274                beta_hat_=self.beta_,
275                Sigma_hat_=self.Sigma_,
276                backend=self.backend,
277            )
278
279            return (self.y_mean_ + pred_obj["preds"], pred_obj["preds_std"])

Predict test data X.

Parameters:

X: {array-like}, shape = [n_samples, n_features]
    Training vectors, where n_samples is the number
    of samples and n_features is the number of features.

return_std: {boolean}, standard dev. is returned or not

**kwargs: additional parameters to be passed to
        self.cook_test_set

Returns:

model predictions: {array-like}
class ClassicalMTS(nnetsauce.Base):
 42class ClassicalMTS(Base):
 43    """Multivariate time series (FactorMTS) forecasting with Factor models
 44
 45    Parameters:
 46
 47        model: type of model: str.
 48            currently, 'VAR', 'VECM', 'ARIMA', 'ETS', 'Theta'
 49
 50    Attributes:
 51
 52        df_: data frame
 53            the input data frame, in case a data.frame is provided to `fit`
 54
 55        level_: int
 56            level of confidence for prediction intervals (default is 95)
 57
 58    Examples:
 59    See examples/classical_mts_timeseries.py
 60    """
 61
 62    # construct the object -----
 63
 64    def __init__(self, model="VAR"):
 65
 66        self.model = model
 67        if self.model == "VAR":
 68            self.obj = VAR
 69        elif self.model == "VECM":
 70            self.obj = VECM
 71        elif self.model == "ARIMA":
 72            self.obj = ARIMA
 73        elif self.model == "ETS":
 74            self.obj = ExponentialSmoothing
 75        elif self.model == "Theta":
 76            self.obj = ThetaModel
 77        else:
 78            raise ValueError("model not recognized")
 79        self.n_series = None
 80        self.replications = None
 81        self.mean_ = None
 82        self.upper_ = None
 83        self.lower_ = None
 84        self.output_dates_ = None
 85        self.alpha_ = None
 86        self.df_ = None
 87        self.residuals_ = []
 88        self.sims_ = None
 89        self.level_ = None
 90
 91    def fit(self, X, **kwargs):
 92        """Fit FactorMTS model to training data X, with optional regressors xreg
 93
 94        Parameters:
 95
 96        X: {array-like}, shape = [n_samples, n_features]
 97            Training time series, where n_samples is the number
 98            of samples and n_features is the number of features;
 99            X must be in increasing order (most recent observations last)
100
101        **kwargs: for now, additional parameters to be passed to for kernel density estimation, when needed (see sklearn.neighbors.KernelDensity)
102
103        Returns:
104
105        self: object
106        """
107
108        try:
109            self.n_series = X.shape[1]
110        except Exception:
111            self.n_series = 1
112
113        if (isinstance(X, pd.DataFrame) is False) and isinstance(
114            X, pd.Series
115        ) is False:  # input data set is a numpy array
116
117            X = pd.DataFrame(X)
118            if self.n_series > 1:
119                self.series_names = [
120                    "series" + str(i) for i in range(X.shape[1])
121                ]
122            else:
123                self.series_names = "series0"
124
125        else:  # input data set is a DataFrame or Series with column names
126
127            X_index = None
128            if X.index is not None and len(X.shape) > 1:
129                X_index = X.index
130                X = copy.deepcopy(mo.convert_df_to_numeric(X))
131            if X_index is not None:
132                try:
133                    X.index = X_index
134                except Exception:
135                    pass
136            if isinstance(X, pd.DataFrame):
137                self.series_names = X.columns.tolist()
138            else:
139                self.series_names = X.name
140
141        if isinstance(X, pd.DataFrame) or isinstance(X, pd.Series):
142            self.df_ = X
143            X = X.values
144            self.df_.columns = self.series_names
145            self.input_dates = ts.compute_input_dates(self.df_)
146        else:
147            self.df_ = pd.DataFrame(X, columns=self.series_names)
148
149        if self.model == "Theta":
150            self.obj = self.obj(self.df_, **kwargs).fit()
151        else:
152            self.obj = self.obj(X, **kwargs).fit(**kwargs)
153
154        return self
155
156    def predict(self, h=5, level=95, **kwargs):
157        """Forecast all the time series, h steps ahead
158
159        Parameters:
160
161        h: {integer}
162            Forecasting horizon
163
164        **kwargs: additional parameters to be passed to
165                self.cook_test_set
166
167        Returns:
168
169        model predictions for horizon = h: {array-like}
170
171        """
172
173        self.output_dates_, frequency = ts.compute_output_dates(self.df_, h)
174
175        self.level_ = level
176
177        self.lower_ = None  # do not remove (/!\)
178
179        self.upper_ = None  # do not remove (/!\)
180
181        self.sims_ = None  # do not remove (/!\)
182
183        self.level_ = level
184
185        self.alpha_ = 100 - level
186
187        pi_multiplier = norm.ppf(1 - self.alpha_ / 200)
188
189        # Named tuple for forecast results
190        DescribeResult = namedtuple(
191            "DescribeResult", ("mean", "lower", "upper")
192        )
193
194        if self.model == "VAR":
195            mean_forecast, lower_bound, upper_bound = (
196                self.obj.forecast_interval(
197                    self.obj.endog, steps=h, alpha=self.alpha_ / 100, **kwargs
198                )
199            )
200
201        elif self.model == "VECM":
202            forecast_result = self.obj.predict(steps=h)
203            mean_forecast = forecast_result
204            lower_bound, upper_bound = self._compute_confidence_intervals(
205                forecast_result, alpha=self.alpha_ / 100, **kwargs
206            )
207
208        elif self.model == "ARIMA":
209            forecast_result = self.obj.get_forecast(steps=h)
210            mean_forecast = forecast_result.predicted_mean
211            lower_bound = forecast_result.conf_int()[:, 0]
212            upper_bound = forecast_result.conf_int()[:, 1]
213
214        elif self.model == "ETS":
215            forecast_result = self.obj.forecast(steps=h)
216            residuals = self.obj.resid
217            std_errors = np.std(residuals)
218            mean_forecast = forecast_result
219            lower_bound = forecast_result - pi_multiplier * std_errors
220            upper_bound = forecast_result + pi_multiplier * std_errors
221
222        elif self.model == "Theta":
223            try:
224                mean_forecast = self.obj.forecast(steps=h).values
225                forecast_result = self.obj.prediction_intervals(
226                    steps=h, alpha=self.alpha_ / 100, **kwargs
227                )
228                lower_bound = forecast_result["lower"].values
229                upper_bound = forecast_result["upper"].values
230            except Exception:
231                mean_forecast = self.obj.forecast(steps=h)
232                forecast_result = self.obj.prediction_intervals(
233                    steps=h, alpha=self.alpha_ / 100, **kwargs
234                )
235                lower_bound = forecast_result["lower"]
236                upper_bound = forecast_result["upper"]
237
238        else:
239
240            raise ValueError("model not recognized")
241
242        try:
243            self.mean_ = pd.DataFrame(
244                mean_forecast,
245                columns=self.series_names,
246                index=self.output_dates_,
247            )
248            self.lower_ = pd.DataFrame(
249                lower_bound, columns=self.series_names, index=self.output_dates_
250            )
251            self.upper_ = pd.DataFrame(
252                upper_bound, columns=self.series_names, index=self.output_dates_
253            )
254        except Exception:
255            self.mean_ = pd.Series(
256                mean_forecast, name=self.series_names, index=self.output_dates_
257            )
258            self.lower_ = pd.Series(
259                lower_bound, name=self.series_names, index=self.output_dates_
260            )
261            self.upper_ = pd.Series(
262                upper_bound, name=self.series_names, index=self.output_dates_
263            )
264
265        return DescribeResult(
266            mean=self.mean_, lower=self.lower_, upper=self.upper_
267        )
268
269    def _compute_confidence_intervals(self, forecast_result, alpha):
270        """
271        Compute confidence intervals for VECM forecasts.
272        Uses the covariance of residuals to approximate the confidence intervals.
273        """
274        residuals = self.obj.resid
275        cov_matrix = np.cov(residuals.T)  # Covariance matrix of residuals
276        std_errors = np.sqrt(np.diag(cov_matrix))  # Standard errors
277
278        z_value = norm.ppf(1 - alpha / 2)  # Z-score for the given alpha level
279        lower_bound = forecast_result - z_value * std_errors
280        upper_bound = forecast_result + z_value * std_errors
281
282        return lower_bound, upper_bound
283
284    def score(self, X, training_index, testing_index, scoring=None, **kwargs):
285        """Train on training_index, score on testing_index."""
286
287        assert (
288            bool(set(training_index).intersection(set(testing_index))) == False
289        ), "Non-overlapping 'training_index' and 'testing_index' required"
290
291        # Dimensions
292        try:
293            # multivariate time series
294            n, p = X.shape
295        except:
296            # univariate time series
297            n = X.shape[0]
298            p = 1
299
300        # Training and testing sets
301        if p > 1:
302            X_train = X[training_index, :]
303            X_test = X[testing_index, :]
304        else:
305            X_train = X[training_index]
306            X_test = X[testing_index]
307
308        # Horizon
309        h = len(testing_index)
310        assert (
311            len(training_index) + h
312        ) <= n, "Please check lengths of training and testing windows"
313
314        # Fit and predict
315        self.fit(X_train, **kwargs)
316        preds = self.predict(h=h, **kwargs)
317
318        if scoring is None:
319            scoring = "neg_root_mean_squared_error"
320
321        # check inputs
322        assert scoring in (
323            "explained_variance",
324            "neg_mean_absolute_error",
325            "neg_mean_squared_error",
326            "neg_root_mean_squared_error",
327            "neg_mean_squared_log_error",
328            "neg_median_absolute_error",
329            "r2",
330        ), "'scoring' should be in ('explained_variance', 'neg_mean_absolute_error', \
331                               'neg_mean_squared_error', 'neg_root_mean_squared_error', 'neg_mean_squared_log_error', \
332                               'neg_median_absolute_error', 'r2')"
333
334        scoring_options = {
335            "explained_variance": skm2.explained_variance_score,
336            "neg_mean_absolute_error": skm2.mean_absolute_error,
337            "neg_mean_squared_error": lambda x, y: np.mean((x - y) ** 2),
338            "neg_root_mean_squared_error": lambda x, y: np.sqrt(
339                np.mean((x - y) ** 2)
340            ),
341            "neg_mean_squared_log_error": skm2.mean_squared_log_error,
342            "neg_median_absolute_error": skm2.median_absolute_error,
343            "r2": skm2.r2_score,
344        }
345
346        # if p > 1:
347        #     return tuple(
348        #         [
349        #             scoring_options[scoring](
350        #                 X_test[:, i], preds[:, i]#, **kwargs
351        #             )
352        #             for i in range(p)
353        #         ]
354        #     )
355        # else:
356        return scoring_options[scoring](X_test, preds)
357
358    def plot(self, series=None, type_axis="dates", type_plot="pi"):
359        """Plot time series forecast
360
361        Parameters:
362
363        series: {integer} or {string}
364            series index or name
365
366        """
367
368        assert all(
369            [
370                self.mean_ is not None,
371                self.lower_ is not None,
372                self.upper_ is not None,
373                self.output_dates_ is not None,
374            ]
375        ), "model forecasting must be obtained first (with predict)"
376
377        if series is None:
378            assert (
379                self.n_series == 1
380            ), "please specify series index or name (n_series > 1)"
381            series = 0
382
383        if isinstance(series, str):
384            assert (
385                series in self.series_names
386            ), f"series {series} doesn't exist in the input dataset"
387            series_idx = self.df_.columns.get_loc(series)
388        else:
389            assert isinstance(series, int) and (
390                0 <= series < self.n_series
391            ), f"check series index (< {self.n_series})"
392            series_idx = series
393
394        if isinstance(self.df_, pd.DataFrame):
395            y_all = list(self.df_.iloc[:, series_idx]) + list(
396                self.mean_.iloc[:, series_idx]
397            )
398            y_test = list(self.mean_.iloc[:, series_idx])
399        else:
400            y_all = list(self.df_.values) + list(self.mean_.values)
401            y_test = list(self.mean_.values)
402        n_points_all = len(y_all)
403        n_points_train = self.df_.shape[0]
404
405        if type_axis == "numeric":
406            x_all = [i for i in range(n_points_all)]
407            x_test = [i for i in range(n_points_train, n_points_all)]
408
409        if type_axis == "dates":  # use dates
410            x_all = np.concatenate(
411                (self.input_dates.values, self.output_dates_.values), axis=None
412            )
413            x_test = self.output_dates_.values
414
415        if type_plot == "pi":
416            fig, ax = plt.subplots()
417            ax.plot(x_all, y_all, "-")
418            ax.plot(x_test, y_test, "-", color="orange")
419            try:
420                ax.fill_between(
421                    x_test,
422                    self.lower_.iloc[:, series_idx],
423                    self.upper_.iloc[:, series_idx],
424                    alpha=0.2,
425                    color="orange",
426                )
427            except Exception:
428                ax.fill_between(
429                    x_test,
430                    self.lower_.values,
431                    self.upper_.values,
432                    alpha=0.2,
433                    color="orange",
434                )
435            if self.replications is None:
436                if self.n_series > 1:
437                    plt.title(
438                        f"prediction intervals for {series}",
439                        loc="left",
440                        fontsize=12,
441                        fontweight=0,
442                        color="black",
443                    )
444                else:
445                    plt.title(
446                        f"prediction intervals for input time series",
447                        loc="left",
448                        fontsize=12,
449                        fontweight=0,
450                        color="black",
451                    )
452                plt.show()
453            else:  # self.replications is not None
454                if self.n_series > 1:
455                    plt.title(
456                        f"prediction intervals for {self.replications} simulations of {series}",
457                        loc="left",
458                        fontsize=12,
459                        fontweight=0,
460                        color="black",
461                    )
462                else:
463                    plt.title(
464                        f"prediction intervals for {self.replications} simulations of input time series",
465                        loc="left",
466                        fontsize=12,
467                        fontweight=0,
468                        color="black",
469                    )
470                plt.show()
471
472        if type_plot == "spaghetti":
473            palette = plt.get_cmap("Set1")
474            sims_ix = getsims(self.sims_, series_idx)
475            plt.plot(x_all, y_all, "-")
476            for col_ix in range(
477                sims_ix.shape[1]
478            ):  # avoid this when there are thousands of simulations
479                plt.plot(
480                    x_test,
481                    sims_ix[:, col_ix],
482                    "-",
483                    color=palette(col_ix),
484                    linewidth=1,
485                    alpha=0.9,
486                )
487            plt.plot(x_all, y_all, "-", color="black")
488            plt.plot(x_test, y_test, "-", color="blue")
489            # Add titles
490            if self.n_series > 1:
491                plt.title(
492                    f"{self.replications} simulations of {series}",
493                    loc="left",
494                    fontsize=12,
495                    fontweight=0,
496                    color="black",
497                )
498            else:
499                plt.title(
500                    f"{self.replications} simulations of input time series",
501                    loc="left",
502                    fontsize=12,
503                    fontweight=0,
504                    color="black",
505                )
506            plt.xlabel("Time")
507            plt.ylabel("Values")
508            # Show the graph
509            plt.show()
510
511    def cross_val_score(
512        self,
513        X,
514        scoring="root_mean_squared_error",
515        n_jobs=None,
516        verbose=0,
517        xreg=None,
518        initial_window=5,
519        horizon=3,
520        fixed_window=False,
521        show_progress=True,
522        level=95,
523        **kwargs,
524    ):
525        """Evaluate a score by time series cross-validation.
526
527        Parameters:
528
529            X: {array-like, sparse matrix} of shape (n_samples, n_features)
530                The data to fit.
531
532            scoring: str or a function
533                A str in ('root_mean_squared_error', 'mean_squared_error', 'mean_error',
534                'mean_absolute_error', 'mean_error', 'mean_percentage_error',
535                'mean_absolute_percentage_error',  'winkler_score', 'coverage')
536                Or a function defined as 'coverage' and 'winkler_score' in `utils.timeseries`
537
538            n_jobs: int, default=None
539                Number of jobs to run in parallel.
540
541            verbose: int, default=0
542                The verbosity level.
543
544            xreg: array-like, optional (default=None)
545                Additional (external) regressors to be passed to `fit`
546                xreg must be in 'increasing' order (most recent observations last)
547
548            initial_window: int
549                initial number of consecutive values in each training set sample
550
551            horizon: int
552                number of consecutive values in test set sample
553
554            fixed_window: boolean
555                if False, all training samples start at index 0, and the training
556                window's size is increasing.
557                if True, the training window's size is fixed, and the window is
558                rolling forward
559
560            show_progress: boolean
561                if True, a progress bar is printed
562
563            **kwargs: dict
564                additional parameters to be passed to `fit` and `predict`
565
566        Returns:
567
568            A tuple: descriptive statistics or errors and raw errors
569
570        """
571        tscv = TimeSeriesSplit()
572
573        tscv_obj = tscv.split(
574            X,
575            initial_window=initial_window,
576            horizon=horizon,
577            fixed_window=fixed_window,
578        )
579
580        if isinstance(scoring, str):
581
582            assert scoring in (
583                "root_mean_squared_error",
584                "mean_squared_error",
585                "mean_error",
586                "mean_absolute_error",
587                "mean_percentage_error",
588                "mean_absolute_percentage_error",
589                "winkler_score",
590                "coverage",
591            ), "must have scoring in ('root_mean_squared_error', 'mean_squared_error', 'mean_error', 'mean_absolute_error', 'mean_error', 'mean_percentage_error', 'mean_absolute_percentage_error',  'winkler_score', 'coverage')"
592
593            def err_func(X_test, X_pred, scoring):
594                if (self.replications is not None) or (
595                    self.type_pi == "gaussian"
596                ):  # probabilistic
597                    if scoring == "winkler_score":
598                        return winkler_score(X_pred, X_test, level=level)
599                    elif scoring == "coverage":
600                        return coverage(X_pred, X_test, level=level)
601                    else:
602                        return mean_errors(
603                            pred=X_pred.mean, actual=X_test, scoring=scoring
604                        )
605                else:  # not probabilistic
606                    return mean_errors(
607                        pred=X_pred, actual=X_test, scoring=scoring
608                    )
609
610        else:  # isinstance(scoring, str) = False
611
612            err_func = scoring
613
614        errors = []
615
616        train_indices = []
617
618        test_indices = []
619
620        for train_index, test_index in tscv_obj:
621            train_indices.append(train_index)
622            test_indices.append(test_index)
623
624        if show_progress is True:
625            iterator = tqdm(
626                zip(train_indices, test_indices), total=len(train_indices)
627            )
628        else:
629            iterator = zip(train_indices, test_indices)
630
631        for train_index, test_index in iterator:
632
633            if verbose == 1:
634                print(f"TRAIN: {train_index}")
635                print(f"TEST: {test_index}")
636
637            if isinstance(X, pd.DataFrame):
638                self.fit(X.iloc[train_index, :], xreg=xreg, **kwargs)
639                X_test = X.iloc[test_index, :]
640            else:
641                self.fit(X[train_index, :], xreg=xreg, **kwargs)
642                X_test = X[test_index, :]
643            X_pred = self.predict(h=int(len(test_index)), level=level, **kwargs)
644
645            errors.append(err_func(X_test, X_pred, scoring))
646
647        res = np.asarray(errors)
648
649        return res, describe(res)

Multivariate time series (FactorMTS) forecasting with Factor models

Parameters:

model: type of model: str.
    currently, 'VAR', 'VECM', 'ARIMA', 'ETS', 'Theta'

Attributes:

df_: data frame
    the input data frame, in case a data.frame is provided to `fit`

level_: int
    level of confidence for prediction intervals (default is 95)

Examples: See examples/classical_mts_timeseries.py

def fit(self, X, **kwargs):
 91    def fit(self, X, **kwargs):
 92        """Fit FactorMTS model to training data X, with optional regressors xreg
 93
 94        Parameters:
 95
 96        X: {array-like}, shape = [n_samples, n_features]
 97            Training time series, where n_samples is the number
 98            of samples and n_features is the number of features;
 99            X must be in increasing order (most recent observations last)
100
101        **kwargs: for now, additional parameters to be passed to for kernel density estimation, when needed (see sklearn.neighbors.KernelDensity)
102
103        Returns:
104
105        self: object
106        """
107
108        try:
109            self.n_series = X.shape[1]
110        except Exception:
111            self.n_series = 1
112
113        if (isinstance(X, pd.DataFrame) is False) and isinstance(
114            X, pd.Series
115        ) is False:  # input data set is a numpy array
116
117            X = pd.DataFrame(X)
118            if self.n_series > 1:
119                self.series_names = [
120                    "series" + str(i) for i in range(X.shape[1])
121                ]
122            else:
123                self.series_names = "series0"
124
125        else:  # input data set is a DataFrame or Series with column names
126
127            X_index = None
128            if X.index is not None and len(X.shape) > 1:
129                X_index = X.index
130                X = copy.deepcopy(mo.convert_df_to_numeric(X))
131            if X_index is not None:
132                try:
133                    X.index = X_index
134                except Exception:
135                    pass
136            if isinstance(X, pd.DataFrame):
137                self.series_names = X.columns.tolist()
138            else:
139                self.series_names = X.name
140
141        if isinstance(X, pd.DataFrame) or isinstance(X, pd.Series):
142            self.df_ = X
143            X = X.values
144            self.df_.columns = self.series_names
145            self.input_dates = ts.compute_input_dates(self.df_)
146        else:
147            self.df_ = pd.DataFrame(X, columns=self.series_names)
148
149        if self.model == "Theta":
150            self.obj = self.obj(self.df_, **kwargs).fit()
151        else:
152            self.obj = self.obj(X, **kwargs).fit(**kwargs)
153
154        return self

Fit FactorMTS model to training data X, with optional regressors xreg

Parameters:

X: {array-like}, shape = [n_samples, n_features] Training time series, where n_samples is the number of samples and n_features is the number of features; X must be in increasing order (most recent observations last)

**kwargs: for now, additional parameters to be passed to for kernel density estimation, when needed (see sklearn.neighbors.KernelDensity)

Returns:

self: object

def predict(self, h=5, level=95, **kwargs):
156    def predict(self, h=5, level=95, **kwargs):
157        """Forecast all the time series, h steps ahead
158
159        Parameters:
160
161        h: {integer}
162            Forecasting horizon
163
164        **kwargs: additional parameters to be passed to
165                self.cook_test_set
166
167        Returns:
168
169        model predictions for horizon = h: {array-like}
170
171        """
172
173        self.output_dates_, frequency = ts.compute_output_dates(self.df_, h)
174
175        self.level_ = level
176
177        self.lower_ = None  # do not remove (/!\)
178
179        self.upper_ = None  # do not remove (/!\)
180
181        self.sims_ = None  # do not remove (/!\)
182
183        self.level_ = level
184
185        self.alpha_ = 100 - level
186
187        pi_multiplier = norm.ppf(1 - self.alpha_ / 200)
188
189        # Named tuple for forecast results
190        DescribeResult = namedtuple(
191            "DescribeResult", ("mean", "lower", "upper")
192        )
193
194        if self.model == "VAR":
195            mean_forecast, lower_bound, upper_bound = (
196                self.obj.forecast_interval(
197                    self.obj.endog, steps=h, alpha=self.alpha_ / 100, **kwargs
198                )
199            )
200
201        elif self.model == "VECM":
202            forecast_result = self.obj.predict(steps=h)
203            mean_forecast = forecast_result
204            lower_bound, upper_bound = self._compute_confidence_intervals(
205                forecast_result, alpha=self.alpha_ / 100, **kwargs
206            )
207
208        elif self.model == "ARIMA":
209            forecast_result = self.obj.get_forecast(steps=h)
210            mean_forecast = forecast_result.predicted_mean
211            lower_bound = forecast_result.conf_int()[:, 0]
212            upper_bound = forecast_result.conf_int()[:, 1]
213
214        elif self.model == "ETS":
215            forecast_result = self.obj.forecast(steps=h)
216            residuals = self.obj.resid
217            std_errors = np.std(residuals)
218            mean_forecast = forecast_result
219            lower_bound = forecast_result - pi_multiplier * std_errors
220            upper_bound = forecast_result + pi_multiplier * std_errors
221
222        elif self.model == "Theta":
223            try:
224                mean_forecast = self.obj.forecast(steps=h).values
225                forecast_result = self.obj.prediction_intervals(
226                    steps=h, alpha=self.alpha_ / 100, **kwargs
227                )
228                lower_bound = forecast_result["lower"].values
229                upper_bound = forecast_result["upper"].values
230            except Exception:
231                mean_forecast = self.obj.forecast(steps=h)
232                forecast_result = self.obj.prediction_intervals(
233                    steps=h, alpha=self.alpha_ / 100, **kwargs
234                )
235                lower_bound = forecast_result["lower"]
236                upper_bound = forecast_result["upper"]
237
238        else:
239
240            raise ValueError("model not recognized")
241
242        try:
243            self.mean_ = pd.DataFrame(
244                mean_forecast,
245                columns=self.series_names,
246                index=self.output_dates_,
247            )
248            self.lower_ = pd.DataFrame(
249                lower_bound, columns=self.series_names, index=self.output_dates_
250            )
251            self.upper_ = pd.DataFrame(
252                upper_bound, columns=self.series_names, index=self.output_dates_
253            )
254        except Exception:
255            self.mean_ = pd.Series(
256                mean_forecast, name=self.series_names, index=self.output_dates_
257            )
258            self.lower_ = pd.Series(
259                lower_bound, name=self.series_names, index=self.output_dates_
260            )
261            self.upper_ = pd.Series(
262                upper_bound, name=self.series_names, index=self.output_dates_
263            )
264
265        return DescribeResult(
266            mean=self.mean_, lower=self.lower_, upper=self.upper_
267        )

Forecast all the time series, h steps ahead

Parameters:

h: {integer} Forecasting horizon

**kwargs: additional parameters to be passed to self.cook_test_set

Returns:

model predictions for horizon = h: {array-like}

def score(self, X, training_index, testing_index, scoring=None, **kwargs):
284    def score(self, X, training_index, testing_index, scoring=None, **kwargs):
285        """Train on training_index, score on testing_index."""
286
287        assert (
288            bool(set(training_index).intersection(set(testing_index))) == False
289        ), "Non-overlapping 'training_index' and 'testing_index' required"
290
291        # Dimensions
292        try:
293            # multivariate time series
294            n, p = X.shape
295        except:
296            # univariate time series
297            n = X.shape[0]
298            p = 1
299
300        # Training and testing sets
301        if p > 1:
302            X_train = X[training_index, :]
303            X_test = X[testing_index, :]
304        else:
305            X_train = X[training_index]
306            X_test = X[testing_index]
307
308        # Horizon
309        h = len(testing_index)
310        assert (
311            len(training_index) + h
312        ) <= n, "Please check lengths of training and testing windows"
313
314        # Fit and predict
315        self.fit(X_train, **kwargs)
316        preds = self.predict(h=h, **kwargs)
317
318        if scoring is None:
319            scoring = "neg_root_mean_squared_error"
320
321        # check inputs
322        assert scoring in (
323            "explained_variance",
324            "neg_mean_absolute_error",
325            "neg_mean_squared_error",
326            "neg_root_mean_squared_error",
327            "neg_mean_squared_log_error",
328            "neg_median_absolute_error",
329            "r2",
330        ), "'scoring' should be in ('explained_variance', 'neg_mean_absolute_error', \
331                               'neg_mean_squared_error', 'neg_root_mean_squared_error', 'neg_mean_squared_log_error', \
332                               'neg_median_absolute_error', 'r2')"
333
334        scoring_options = {
335            "explained_variance": skm2.explained_variance_score,
336            "neg_mean_absolute_error": skm2.mean_absolute_error,
337            "neg_mean_squared_error": lambda x, y: np.mean((x - y) ** 2),
338            "neg_root_mean_squared_error": lambda x, y: np.sqrt(
339                np.mean((x - y) ** 2)
340            ),
341            "neg_mean_squared_log_error": skm2.mean_squared_log_error,
342            "neg_median_absolute_error": skm2.median_absolute_error,
343            "r2": skm2.r2_score,
344        }
345
346        # if p > 1:
347        #     return tuple(
348        #         [
349        #             scoring_options[scoring](
350        #                 X_test[:, i], preds[:, i]#, **kwargs
351        #             )
352        #             for i in range(p)
353        #         ]
354        #     )
355        # else:
356        return scoring_options[scoring](X_test, preds)

Train on training_index, score on testing_index.

class CustomClassifier(nnetsauce.custom.custom.Custom, sklearn.base.ClassifierMixin):
 15class CustomClassifier(Custom, ClassifierMixin):
 16    """Custom Classification model
 17
 18    Attributes:
 19
 20        obj: object
 21            any object containing a method fit (obj.fit()) and a method predict
 22            (obj.predict())
 23
 24        n_hidden_features: int
 25            number of nodes in the hidden layer
 26
 27        activation_name: str
 28            activation function: 'relu', 'tanh', 'sigmoid', 'prelu' or 'elu'
 29
 30        a: float
 31            hyperparameter for 'prelu' or 'elu' activation function
 32
 33        nodes_sim: str
 34            type of simulation for the nodes: 'sobol', 'hammersley', 'halton',
 35            'uniform'
 36
 37        bias: boolean
 38            indicates if the hidden layer contains a bias term (True) or not
 39            (False)
 40
 41        dropout: float
 42            regularization parameter; (random) percentage of nodes dropped out
 43            of the training
 44
 45        direct_link: boolean
 46            indicates if the original predictors are included (True) in model''s
 47            fitting or not (False)
 48
 49        n_clusters: int
 50            number of clusters for 'kmeans' or 'gmm' clustering (could be 0:
 51                no clustering)
 52
 53        cluster_encode: bool
 54            defines how the variable containing clusters is treated (default is one-hot)
 55            if `False`, then labels are used, without one-hot encoding
 56
 57        type_clust: str
 58            type of clustering method: currently k-means ('kmeans') or Gaussian
 59            Mixture Model ('gmm')
 60
 61        type_scaling: a tuple of 3 strings
 62            scaling methods for inputs, hidden layer, and clustering respectively
 63            (and when relevant).
 64            Currently available: standardization ('std') or MinMax scaling ('minmax')
 65
 66        col_sample: float
 67            percentage of covariates randomly chosen for training
 68
 69        row_sample: float
 70            percentage of rows chosen for training, by stratified bootstrapping
 71
 72        level: float
 73            confidence level for prediction sets. Default is None.
 74
 75        pi_method: str
 76            method for constructing the prediction sets: 'icp', 'tcp' if level is not None. Default is 'icp'.
 77
 78        seed: int
 79            reproducibility seed for nodes_sim=='uniform'
 80
 81        backend: str
 82            "cpu" or "gpu" or "tpu"
 83
 84    Examples:
 85
 86    Note: it's better to use the `DeepClassifier` or `LazyDeepClassifier` classes directly
 87
 88    ```python
 89    import nnetsauce as ns
 90    from sklearn.ensemble import RandomForestClassifier
 91    from sklearn.model_selection import train_test_split
 92    from sklearn.datasets import load_digits
 93    from time import time
 94
 95    digits = load_digits()
 96    X = digits.data
 97    y = digits.target
 98    X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2,
 99                                                        random_state=123)
100
101    # layer 1 (base layer) ----
102    layer1_regr = RandomForestClassifier(n_estimators=10, random_state=123)
103
104    start = time()
105
106    layer1_regr.fit(X_train, y_train)
107
108    # Accuracy in layer 1
109    print(layer1_regr.score(X_test, y_test))
110
111    # layer 2 using layer 1 ----
112    layer2_regr = ns.CustomClassifier(obj = layer1_regr, n_hidden_features=5,
113                            direct_link=True, bias=True,
114                            nodes_sim='uniform', activation_name='relu',
115                            n_clusters=2, seed=123)
116    layer2_regr.fit(X_train, y_train)
117
118    # Accuracy in layer 2
119    print(layer2_regr.score(X_test, y_test))
120
121    # layer 3 using layer 2 ----
122    layer3_regr = ns.CustomClassifier(obj = layer2_regr, n_hidden_features=10,
123                            direct_link=True, bias=True, dropout=0.7,
124                            nodes_sim='uniform', activation_name='relu',
125                            n_clusters=2, seed=123)
126    layer3_regr.fit(X_train, y_train)
127
128    # Accuracy in layer 3
129    print(layer3_regr.score(X_test, y_test))
130
131    print(f"Elapsed {time() - start}")
132    ```
133
134    """
135
136    # construct the object -----
137
138    def __init__(
139        self,
140        obj,
141        n_hidden_features=5,
142        activation_name="relu",
143        a=0.01,
144        nodes_sim="sobol",
145        bias=True,
146        dropout=0,
147        direct_link=True,
148        n_clusters=2,
149        cluster_encode=True,
150        type_clust="kmeans",
151        type_scaling=("std", "std", "std"),
152        col_sample=1,
153        row_sample=1,
154        level=None,
155        pi_method="icp",
156        seed=123,
157        backend="cpu",
158    ):
159        super().__init__(
160            obj=obj,
161            n_hidden_features=n_hidden_features,
162            activation_name=activation_name,
163            a=a,
164            nodes_sim=nodes_sim,
165            bias=bias,
166            dropout=dropout,
167            direct_link=direct_link,
168            n_clusters=n_clusters,
169            cluster_encode=cluster_encode,
170            type_clust=type_clust,
171            type_scaling=type_scaling,
172            col_sample=col_sample,
173            row_sample=row_sample,
174            seed=seed,
175            backend=backend,
176        )
177        self.level = level
178        self.pi_method = pi_method
179        self.coef_ = None
180        self.type_fit = "classification"
181        if self.level is not None:
182            self.obj = PredictionSet(
183                self.obj, level=self.level, method=self.pi_method
184            )
185
186    def fit(self, X, y, sample_weight=None, **kwargs):
187        """Fit custom model to training data (X, y).
188
189        Parameters:
190
191            X: {array-like}, shape = [n_samples, n_features]
192                Training vectors, where n_samples is the number
193                of samples and n_features is the number of features.
194
195            y: array-like, shape = [n_samples]
196                Target values.
197
198            sample_weight: array-like, shape = [n_samples]
199                Sample weights.
200
201            **kwargs: additional parameters to be passed to
202                        self.cook_training_set or self.obj.fit
203
204        Returns:
205
206            self: object
207        """
208
209        if len(X.shape) == 1:
210            if isinstance(X, pd.DataFrame):
211                X = pd.DataFrame(X.values.reshape(1, -1), columns=X.columns)
212            else:
213                X = X.reshape(1, -1)
214
215        output_y, scaled_Z = self.cook_training_set(y=y, X=X, **kwargs)
216        self.classes_ = np.unique(y)
217        self.n_classes_ = len(self.classes_)  # for compatibility with
218
219        if self.level is not None:
220            self.obj = PredictionSet(
221                obj=self.obj, method=self.pi_method, level=self.level
222            )
223
224        # if sample_weights, else: (must use self.row_index)
225        if sample_weight is not None:
226            self.obj.fit(
227                scaled_Z,
228                output_y,
229                sample_weight=sample_weight[self.index_row_].ravel(),
230                # **kwargs
231            )
232
233            return self
234
235        # if sample_weight is None:
236        self.obj.fit(scaled_Z, output_y)
237        self.classes_ = np.unique(y)  # for compatibility with sklearn
238        self.n_classes_ = len(self.classes_)  # for compatibility with sklearn
239
240        if hasattr(self.obj, "coef_"):
241            self.coef_ = self.obj.coef_
242
243        return self
244
245    def partial_fit(self, X, y, sample_weight=None, **kwargs):
246        """Partial fit custom model to training data (X, y).
247
248        Parameters:
249
250            X: {array-like}, shape = [n_samples, n_features]
251                Subset of training vectors, where n_samples is the number
252                of samples and n_features is the number of features.
253
254            y: array-like, shape = [n_samples]
255                Subset of target values.
256
257            sample_weight: array-like, shape = [n_samples]
258                Sample weights.
259
260            **kwargs: additional parameters to be passed to
261                        self.cook_training_set or self.obj.fit
262
263        Returns:
264
265            self: object
266        """
267
268        if len(X.shape) == 1:
269            if isinstance(X, pd.DataFrame):
270                X = pd.DataFrame(X.values.reshape(1, -1), columns=X.columns)
271            else:
272                X = X.reshape(1, -1)
273            y = np.array([y], dtype=np.integer)
274
275        output_y, scaled_Z = self.cook_training_set(y=y, X=X, **kwargs)
276        self.n_classes_ = len(np.unique(y))  # for compatibility with sklearn
277
278        # if sample_weights, else: (must use self.row_index)
279        if sample_weight is not None:
280            try:
281                self.obj.partial_fit(
282                    scaled_Z,
283                    output_y,
284                    sample_weight=sample_weight[self.index_row_].ravel(),
285                    # **kwargs
286                )
287            except:
288                NotImplementedError
289
290            return self
291
292        # if sample_weight is None:
293        try:
294            self.obj.partial_fit(scaled_Z, output_y)
295        except:
296            raise NotImplementedError
297
298        self.classes_ = np.unique(y)  # for compatibility with sklearn
299        self.n_classes_ = len(self.classes_)  # for compatibility with sklearn
300
301        return self
302
303    def predict(self, X, **kwargs):
304        """Predict test data X.
305
306        Parameters:
307
308            X: {array-like}, shape = [n_samples, n_features]
309                Training vectors, where n_samples is the number
310                of samples and n_features is the number of features.
311
312            **kwargs: additional parameters to be passed to
313                    self.cook_test_set
314
315        Returns:
316
317            model predictions: {array-like}
318        """
319
320        if len(X.shape) == 1:
321            n_features = X.shape[0]
322            new_X = mo.rbind(
323                X.reshape(1, n_features),
324                np.ones(n_features).reshape(1, n_features),
325            )
326
327            return (
328                self.obj.predict(self.cook_test_set(new_X, **kwargs), **kwargs)
329            )[0]
330
331        return self.obj.predict(self.cook_test_set(X, **kwargs), **kwargs)
332
333    def predict_proba(self, X, **kwargs):
334        """Predict probabilities for test data X.
335
336        Args:
337
338            X: {array-like}, shape = [n_samples, n_features]
339                Training vectors, where n_samples is the number
340                of samples and n_features is the number of features.
341
342            **kwargs: additional parameters to be passed to
343                    self.cook_test_set
344
345        Returns:
346
347            probability estimates for test data: {array-like}
348        """
349
350        if len(X.shape) == 1:
351            n_features = X.shape[0]
352            new_X = mo.rbind(
353                X.reshape(1, n_features),
354                np.ones(n_features).reshape(1, n_features),
355            )
356
357            return (
358                self.obj.predict_proba(
359                    self.cook_test_set(new_X, **kwargs), **kwargs
360                )
361            )[0]
362
363        return self.obj.predict_proba(self.cook_test_set(X, **kwargs), **kwargs)
364
365    def score(self, X, y, scoring=None):
366        """Scoring function for classification.
367
368        Args:
369
370            X: {array-like}, shape = [n_samples, n_features]
371                Training vectors, where n_samples is the number
372                of samples and n_features is the number of features.
373
374            y: array-like, shape = [n_samples]
375                Target values.
376
377            scoring: str
378                scoring method (default is accuracy)
379
380        Returns:
381
382            score: float
383        """
384
385        if scoring is None:
386            scoring = "accuracy"
387
388        if scoring == "accuracy":
389            return skm2.accuracy_score(y, self.predict(X))
390
391        if scoring == "f1":
392            return skm2.f1_score(y, self.predict(X))
393
394        if scoring == "precision":
395            return skm2.precision_score(y, self.predict(X))
396
397        if scoring == "recall":
398            return skm2.recall_score(y, self.predict(X))
399
400        if scoring == "roc_auc":
401            return skm2.roc_auc_score(y, self.predict(X))
402
403        if scoring == "log_loss":
404            return skm2.log_loss(y, self.predict_proba(X))
405
406        if scoring == "balanced_accuracy":
407            return skm2.balanced_accuracy_score(y, self.predict(X))
408
409        if scoring == "average_precision":
410            return skm2.average_precision_score(y, self.predict(X))
411
412        if scoring == "neg_brier_score":
413            return -skm2.brier_score_loss(y, self.predict_proba(X))
414
415        if scoring == "neg_log_loss":
416            return -skm2.log_loss(y, self.predict_proba(X))

Custom Classification model

Attributes:

obj: object
    any object containing a method fit (obj.fit()) and a method predict
    (obj.predict())

n_hidden_features: int
    number of nodes in the hidden layer

activation_name: str
    activation function: 'relu', 'tanh', 'sigmoid', 'prelu' or 'elu'

a: float
    hyperparameter for 'prelu' or 'elu' activation function

nodes_sim: str
    type of simulation for the nodes: 'sobol', 'hammersley', 'halton',
    'uniform'

bias: boolean
    indicates if the hidden layer contains a bias term (True) or not
    (False)

dropout: float
    regularization parameter; (random) percentage of nodes dropped out
    of the training

direct_link: boolean
    indicates if the original predictors are included (True) in model''s
    fitting or not (False)

n_clusters: int
    number of clusters for 'kmeans' or 'gmm' clustering (could be 0:
        no clustering)

cluster_encode: bool
    defines how the variable containing clusters is treated (default is one-hot)
    if `False`, then labels are used, without one-hot encoding

type_clust: str
    type of clustering method: currently k-means ('kmeans') or Gaussian
    Mixture Model ('gmm')

type_scaling: a tuple of 3 strings
    scaling methods for inputs, hidden layer, and clustering respectively
    (and when relevant).
    Currently available: standardization ('std') or MinMax scaling ('minmax')

col_sample: float
    percentage of covariates randomly chosen for training

row_sample: float
    percentage of rows chosen for training, by stratified bootstrapping

level: float
    confidence level for prediction sets. Default is None.

pi_method: str
    method for constructing the prediction sets: 'icp', 'tcp' if level is not None. Default is 'icp'.

seed: int
    reproducibility seed for nodes_sim=='uniform'

backend: str
    "cpu" or "gpu" or "tpu"

Examples:

Note: it's better to use the DeepClassifier or LazyDeepClassifier classes directly

import nnetsauce as ns
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split
from sklearn.datasets import load_digits
from time import time

digits = load_digits()
X = digits.data
y = digits.target
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2,
                                                    random_state=123)

# layer 1 (base layer) ----
layer1_regr = RandomForestClassifier(n_estimators=10, random_state=123)

start = time()

layer1_regr.fit(X_train, y_train)

# Accuracy in layer 1
print(layer1_regr.score(X_test, y_test))

# layer 2 using layer 1 ----
layer2_regr = ns.CustomClassifier(obj = layer1_regr, n_hidden_features=5,
                        direct_link=True, bias=True,
                        nodes_sim='uniform', activation_name='relu',
                        n_clusters=2, seed=123)
layer2_regr.fit(X_train, y_train)

# Accuracy in layer 2
print(layer2_regr.score(X_test, y_test))

# layer 3 using layer 2 ----
layer3_regr = ns.CustomClassifier(obj = layer2_regr, n_hidden_features=10,
                        direct_link=True, bias=True, dropout=0.7,
                        nodes_sim='uniform', activation_name='relu',
                        n_clusters=2, seed=123)
layer3_regr.fit(X_train, y_train)

# Accuracy in layer 3
print(layer3_regr.score(X_test, y_test))

print(f"Elapsed {time() - start}")
def fit(self, X, y, sample_weight=None, **kwargs):
186    def fit(self, X, y, sample_weight=None, **kwargs):
187        """Fit custom model to training data (X, y).
188
189        Parameters:
190
191            X: {array-like}, shape = [n_samples, n_features]
192                Training vectors, where n_samples is the number
193                of samples and n_features is the number of features.
194
195            y: array-like, shape = [n_samples]
196                Target values.
197
198            sample_weight: array-like, shape = [n_samples]
199                Sample weights.
200
201            **kwargs: additional parameters to be passed to
202                        self.cook_training_set or self.obj.fit
203
204        Returns:
205
206            self: object
207        """
208
209        if len(X.shape) == 1:
210            if isinstance(X, pd.DataFrame):
211                X = pd.DataFrame(X.values.reshape(1, -1), columns=X.columns)
212            else:
213                X = X.reshape(1, -1)
214
215        output_y, scaled_Z = self.cook_training_set(y=y, X=X, **kwargs)
216        self.classes_ = np.unique(y)
217        self.n_classes_ = len(self.classes_)  # for compatibility with
218
219        if self.level is not None:
220            self.obj = PredictionSet(
221                obj=self.obj, method=self.pi_method, level=self.level
222            )
223
224        # if sample_weights, else: (must use self.row_index)
225        if sample_weight is not None:
226            self.obj.fit(
227                scaled_Z,
228                output_y,
229                sample_weight=sample_weight[self.index_row_].ravel(),
230                # **kwargs
231            )
232
233            return self
234
235        # if sample_weight is None:
236        self.obj.fit(scaled_Z, output_y)
237        self.classes_ = np.unique(y)  # for compatibility with sklearn
238        self.n_classes_ = len(self.classes_)  # for compatibility with sklearn
239
240        if hasattr(self.obj, "coef_"):
241            self.coef_ = self.obj.coef_
242
243        return self

Fit custom model to training data (X, y).

Parameters:

X: {array-like}, shape = [n_samples, n_features]
    Training vectors, where n_samples is the number
    of samples and n_features is the number of features.

y: array-like, shape = [n_samples]
    Target values.

sample_weight: array-like, shape = [n_samples]
    Sample weights.

**kwargs: additional parameters to be passed to
            self.cook_training_set or self.obj.fit

Returns:

self: object
def predict(self, X, **kwargs):
303    def predict(self, X, **kwargs):
304        """Predict test data X.
305
306        Parameters:
307
308            X: {array-like}, shape = [n_samples, n_features]
309                Training vectors, where n_samples is the number
310                of samples and n_features is the number of features.
311
312            **kwargs: additional parameters to be passed to
313                    self.cook_test_set
314
315        Returns:
316
317            model predictions: {array-like}
318        """
319
320        if len(X.shape) == 1:
321            n_features = X.shape[0]
322            new_X = mo.rbind(
323                X.reshape(1, n_features),
324                np.ones(n_features).reshape(1, n_features),
325            )
326
327            return (
328                self.obj.predict(self.cook_test_set(new_X, **kwargs), **kwargs)
329            )[0]
330
331        return self.obj.predict(self.cook_test_set(X, **kwargs), **kwargs)

Predict test data X.

Parameters:

X: {array-like}, shape = [n_samples, n_features]
    Training vectors, where n_samples is the number
    of samples and n_features is the number of features.

**kwargs: additional parameters to be passed to
        self.cook_test_set

Returns:

model predictions: {array-like}
def predict_proba(self, X, **kwargs):
333    def predict_proba(self, X, **kwargs):
334        """Predict probabilities for test data X.
335
336        Args:
337
338            X: {array-like}, shape = [n_samples, n_features]
339                Training vectors, where n_samples is the number
340                of samples and n_features is the number of features.
341
342            **kwargs: additional parameters to be passed to
343                    self.cook_test_set
344
345        Returns:
346
347            probability estimates for test data: {array-like}
348        """
349
350        if len(X.shape) == 1:
351            n_features = X.shape[0]
352            new_X = mo.rbind(
353                X.reshape(1, n_features),
354                np.ones(n_features).reshape(1, n_features),
355            )
356
357            return (
358                self.obj.predict_proba(
359                    self.cook_test_set(new_X, **kwargs), **kwargs
360                )
361            )[0]
362
363        return self.obj.predict_proba(self.cook_test_set(X, **kwargs), **kwargs)

Predict probabilities for test data X.

Args:

X: {array-like}, shape = [n_samples, n_features]
    Training vectors, where n_samples is the number
    of samples and n_features is the number of features.

**kwargs: additional parameters to be passed to
        self.cook_test_set

Returns:

probability estimates for test data: {array-like}
def score(self, X, y, scoring=None):
365    def score(self, X, y, scoring=None):
366        """Scoring function for classification.
367
368        Args:
369
370            X: {array-like}, shape = [n_samples, n_features]
371                Training vectors, where n_samples is the number
372                of samples and n_features is the number of features.
373
374            y: array-like, shape = [n_samples]
375                Target values.
376
377            scoring: str
378                scoring method (default is accuracy)
379
380        Returns:
381
382            score: float
383        """
384
385        if scoring is None:
386            scoring = "accuracy"
387
388        if scoring == "accuracy":
389            return skm2.accuracy_score(y, self.predict(X))
390
391        if scoring == "f1":
392            return skm2.f1_score(y, self.predict(X))
393
394        if scoring == "precision":
395            return skm2.precision_score(y, self.predict(X))
396
397        if scoring == "recall":
398            return skm2.recall_score(y, self.predict(X))
399
400        if scoring == "roc_auc":
401            return skm2.roc_auc_score(y, self.predict(X))
402
403        if scoring == "log_loss":
404            return skm2.log_loss(y, self.predict_proba(X))
405
406        if scoring == "balanced_accuracy":
407            return skm2.balanced_accuracy_score(y, self.predict(X))
408
409        if scoring == "average_precision":
410            return skm2.average_precision_score(y, self.predict(X))
411
412        if scoring == "neg_brier_score":
413            return -skm2.brier_score_loss(y, self.predict_proba(X))
414
415        if scoring == "neg_log_loss":
416            return -skm2.log_loss(y, self.predict_proba(X))

Scoring function for classification.

Args:

X: {array-like}, shape = [n_samples, n_features]
    Training vectors, where n_samples is the number
    of samples and n_features is the number of features.

y: array-like, shape = [n_samples]
    Target values.

scoring: str
    scoring method (default is accuracy)

Returns:

score: float
class CustomRegressor(nnetsauce.custom.custom.Custom, sklearn.base.RegressorMixin):
 18class CustomRegressor(Custom, RegressorMixin):
 19    """Custom Regression model
 20
 21    This class is used to 'augment' any regression model with transformed features.
 22
 23    Parameters:
 24
 25        obj: object
 26            any object containing a method fit (obj.fit()) and a method predict
 27            (obj.predict())
 28
 29        n_hidden_features: int
 30            number of nodes in the hidden layer
 31
 32        activation_name: str
 33            activation function: 'relu', 'tanh', 'sigmoid', 'prelu' or 'elu'
 34
 35        a: float
 36            hyperparameter for 'prelu' or 'elu' activation function
 37
 38        nodes_sim: str
 39            type of simulation for the nodes: 'sobol', 'hammersley', 'halton',
 40            'uniform'
 41
 42        bias: boolean
 43            indicates if the hidden layer contains a bias term (True) or not
 44            (False)
 45
 46        dropout: float
 47            regularization parameter; (random) percentage of nodes dropped out
 48            of the training
 49
 50        direct_link: boolean
 51            indicates if the original predictors are included (True) in model's
 52            fitting or not (False)
 53
 54        n_clusters: int
 55            number of clusters for 'kmeans' or 'gmm' clustering (could be 0:
 56                no clustering)
 57
 58        cluster_encode: bool
 59            defines how the variable containing clusters is treated (default is one-hot)
 60            if `False`, then labels are used, without one-hot encoding
 61
 62        type_clust: str
 63            type of clustering method: currently k-means ('kmeans') or Gaussian
 64            Mixture Model ('gmm')
 65
 66        type_scaling: a tuple of 3 strings
 67            scaling methods for inputs, hidden layer, and clustering respectively
 68            (and when relevant).
 69            Currently available: standardization ('std') or MinMax scaling ('minmax')
 70
 71        type_pi: str.
 72            type of prediction interval; currently `None` (split or local
 73            conformal without simulation), "kde" or "bootstrap" (simulated split
 74            conformal).
 75
 76        replications: int.
 77            number of replications (if needed) for predictive simulation.
 78            Used only in `self.predict`, for `self.kernel` in ('gaussian',
 79            'tophat') and `self.type_pi = 'kde'`. Default is `None`.
 80
 81        kernel: str.
 82            the kernel to use for kernel density estimation (used for predictive
 83            simulation in `self.predict`, with `method='splitconformal'` and
 84            `type_pi = 'kde'`). Currently, either 'gaussian' or 'tophat'.
 85
 86        type_split: str.
 87            Type of splitting for conformal prediction. None (default), or
 88            "random" (random split of data) or "sequential" (sequential split of data)
 89
 90        col_sample: float
 91            percentage of covariates randomly chosen for training
 92
 93        row_sample: float
 94            percentage of rows chosen for training, by stratified bootstrapping
 95
 96        level: float
 97            confidence level for prediction intervals
 98
 99        pi_method: str
100            method for prediction intervals: 'splitconformal' or 'localconformal'
101
102        seed: int
103            reproducibility seed for nodes_sim=='uniform'
104
105        type_fit: str
106            'regression'
107
108        backend: str
109            "cpu" or "gpu" or "tpu"
110
111    Examples:
112
113    See [https://thierrymoudiki.github.io/blog/2024/03/18/python/conformal-and-bayesian-regression](https://thierrymoudiki.github.io/blog/2024/03/18/python/conformal-and-bayesian-regression)
114
115    """
116
117    # construct the object -----
118
119    def __init__(
120        self,
121        obj,
122        n_hidden_features=5,
123        activation_name="relu",
124        a=0.01,
125        nodes_sim="sobol",
126        bias=True,
127        dropout=0,
128        direct_link=True,
129        n_clusters=2,
130        cluster_encode=True,
131        type_clust="kmeans",
132        type_scaling=("std", "std", "std"),
133        type_pi=None,
134        replications=None,
135        kernel=None,
136        type_split=None,
137        col_sample=1,
138        row_sample=1,
139        level=None,
140        pi_method=None,
141        seed=123,
142        backend="cpu",
143    ):
144        super().__init__(
145            obj=obj,
146            n_hidden_features=n_hidden_features,
147            activation_name=activation_name,
148            a=a,
149            nodes_sim=nodes_sim,
150            bias=bias,
151            dropout=dropout,
152            direct_link=direct_link,
153            n_clusters=n_clusters,
154            cluster_encode=cluster_encode,
155            type_clust=type_clust,
156            type_scaling=type_scaling,
157            col_sample=col_sample,
158            row_sample=row_sample,
159            seed=seed,
160            backend=backend,
161        )
162
163        self.type_fit = "regression"
164        self.type_pi = type_pi
165        self.replications = replications
166        self.kernel = kernel
167        self.type_split = type_split
168        self.level = level
169        self.pi_method = pi_method
170        self.coef_ = None
171        self.X_ = None
172        self.y_ = None
173
174    def fit(self, X, y, sample_weight=None, **kwargs):
175        """Fit custom model to training data (X, y).
176
177        Parameters:
178
179            X: {array-like}, shape = [n_samples, n_features]
180                Training vectors, where n_samples is the number
181                of samples and n_features is the number of features.
182
183            y: array-like, shape = [n_samples]
184                Target values.
185
186            sample_weight: array-like, shape = [n_samples]
187                Sample weights.
188
189            **kwargs: additional parameters to be passed to
190                self.cook_training_set or self.obj.fit
191
192        Returns:
193
194            self: object
195
196        """
197
198        centered_y, scaled_Z = self.cook_training_set(y=y, X=X, **kwargs)
199
200        if self.level is not None:
201            self.obj = PredictionInterval(
202                obj=self.obj, method=self.pi_method, level=self.level
203            )
204
205        # if sample_weights, else: (must use self.row_index)
206        if sample_weight is not None:
207            self.obj.fit(
208                scaled_Z,
209                centered_y,
210                sample_weight=sample_weight[self.index_row_].ravel(),
211                **kwargs
212            )
213
214            return self
215
216        self.obj.fit(scaled_Z, centered_y, **kwargs)
217
218        self.X_ = X
219
220        self.y_ = y
221
222        if hasattr(self.obj, "coef_"):
223            self.coef_ = self.obj.coef_
224
225        return self
226
227    def partial_fit(self, X, y, **kwargs):
228        """Partial fit custom model to training data (X, y).
229
230        Parameters:
231
232            X: {array-like}, shape = [n_samples, n_features]
233                Subset of training vectors, where n_samples is the number
234                of samples and n_features is the number of features.
235
236            y: array-like, shape = [n_samples]
237                Subset of target values.
238
239            **kwargs: additional parameters to be passed to
240                self.cook_training_set or self.obj.fit
241
242        Returns:
243
244            self: object
245
246        """
247
248        if len(X.shape) == 1:
249            if isinstance(X, pd.DataFrame):
250                X = pd.DataFrame(X.values.reshape(1, -1), columns=X.columns)
251            else:
252                X = X.reshape(1, -1)
253            y = np.array([y])
254
255        centered_y, scaled_Z = self.cook_training_set(y=y, X=X, **kwargs)
256
257        self.obj.partial_fit(scaled_Z, centered_y, **kwargs)
258
259        self.X_ = X
260
261        self.y_ = y
262
263        return self
264
265    def predict(self, X, level=95, method=None, **kwargs):
266        """Predict test data X.
267
268        Parameters:
269
270            X: {array-like}, shape = [n_samples, n_features]
271                Training vectors, where n_samples is the number
272                of samples and n_features is the number of features.
273
274            level: int
275                Level of confidence (default = 95)
276
277            method: str
278                `None`, or 'splitconformal', 'localconformal'
279                prediction (if you specify `return_pi = True`)
280
281            **kwargs: additional parameters
282                    `return_pi = True` for conformal prediction,
283                    with `method` in ('splitconformal', 'localconformal')
284                    or `return_std = True` for `self.obj` in
285                    (`sklearn.linear_model.BayesianRidge`,
286                    `sklearn.linear_model.ARDRegressor`,
287                    `sklearn.gaussian_process.GaussianProcessRegressor`)`
288
289        Returns:
290
291            model predictions:
292                an array if uncertainty quantification is not requested,
293                  or a tuple if with prediction intervals and simulations
294                  if `return_std = True` (mean, standard deviation,
295                  lower and upper prediction interval) or `return_pi = True`
296                  ()
297
298        """
299
300        if "return_std" in kwargs:
301
302            alpha = 100 - level
303            pi_multiplier = norm.ppf(1 - alpha / 200)
304
305            if len(X.shape) == 1:
306
307                n_features = X.shape[0]
308                new_X = mo.rbind(
309                    X.reshape(1, n_features),
310                    np.ones(n_features).reshape(1, n_features),
311                )
312
313                mean_, std_ = self.obj.predict(
314                    self.cook_test_set(new_X, **kwargs), return_std=True
315                )[0]
316
317                preds = self.y_mean_ + mean_
318                lower = self.y_mean_ + (mean_ - pi_multiplier * std_)
319                upper = self.y_mean_ + (mean_ + pi_multiplier * std_)
320
321                DescribeResults = namedtuple(
322                    "DescribeResults", ["mean", "std", "lower", "upper"]
323                )
324
325                return DescribeResults(preds, std_, lower, upper)
326
327            # len(X.shape) > 1
328            mean_, std_ = self.obj.predict(
329                self.cook_test_set(X, **kwargs), return_std=True
330            )
331
332            preds = self.y_mean_ + mean_
333            lower = self.y_mean_ + (mean_ - pi_multiplier * std_)
334            upper = self.y_mean_ + (mean_ + pi_multiplier * std_)
335
336            DescribeResults = namedtuple(
337                "DescribeResults", ["mean", "std", "lower", "upper"]
338            )
339
340            return DescribeResults(preds, std_, lower, upper)
341
342        if "return_pi" in kwargs:
343            assert method in (
344                "splitconformal",
345                "localconformal",
346            ), "method must be in ('splitconformal', 'localconformal')"
347            self.pi = PredictionInterval(
348                obj=self,
349                method=method,
350                level=level,
351                type_pi=self.type_pi,
352                replications=self.replications,
353                kernel=self.kernel,
354            )
355
356            if len(self.X_.shape) == 1:
357                if isinstance(X, pd.DataFrame):
358                    self.X_ = pd.DataFrame(
359                        self.X_.values.reshape(1, -1), columns=self.X_.columns
360                    )
361                else:
362                    self.X_ = self.X_.reshape(1, -1)
363                self.y_ = np.array([self.y_])
364
365            self.pi.fit(self.X_, self.y_)
366            # self.X_ = None # consumes memory to keep, dangerous to delete (side effect)
367            # self.y_ = None # consumes memory to keep, dangerous to delete (side effect)
368            preds = self.pi.predict(X, return_pi=True)
369            return preds
370
371        # "return_std" not in kwargs
372        if len(X.shape) == 1:
373
374            n_features = X.shape[0]
375            new_X = mo.rbind(
376                X.reshape(1, n_features),
377                np.ones(n_features).reshape(1, n_features),
378            )
379
380            return (
381                self.y_mean_
382                + self.obj.predict(
383                    self.cook_test_set(new_X, **kwargs), **kwargs
384                )
385            )[0]
386
387        # len(X.shape) > 1
388        return self.y_mean_ + self.obj.predict(
389            self.cook_test_set(X, **kwargs), **kwargs
390        )
391
392    def score(self, X, y, scoring=None):
393        """Compute the score of the model.
394
395        Parameters:
396
397            X: {array-like}, shape = [n_samples, n_features]
398                Training vectors, where n_samples is the number
399                of samples and n_features is the number of features.
400
401            y: array-like, shape = [n_samples]
402                Target values.
403
404            scoring: str
405                scoring method
406
407        Returns:
408
409            score: float
410
411        """
412
413        if scoring is None:
414            return np.sqrt(np.mean((self.predict(X) - y) ** 2))
415
416        return skm2.get_scorer(scoring)(self, X, y)

Custom Regression model

This class is used to 'augment' any regression model with transformed features.

Parameters:

obj: object
    any object containing a method fit (obj.fit()) and a method predict
    (obj.predict())

n_hidden_features: int
    number of nodes in the hidden layer

activation_name: str
    activation function: 'relu', 'tanh', 'sigmoid', 'prelu' or 'elu'

a: float
    hyperparameter for 'prelu' or 'elu' activation function

nodes_sim: str
    type of simulation for the nodes: 'sobol', 'hammersley', 'halton',
    'uniform'

bias: boolean
    indicates if the hidden layer contains a bias term (True) or not
    (False)

dropout: float
    regularization parameter; (random) percentage of nodes dropped out
    of the training

direct_link: boolean
    indicates if the original predictors are included (True) in model's
    fitting or not (False)

n_clusters: int
    number of clusters for 'kmeans' or 'gmm' clustering (could be 0:
        no clustering)

cluster_encode: bool
    defines how the variable containing clusters is treated (default is one-hot)
    if `False`, then labels are used, without one-hot encoding

type_clust: str
    type of clustering method: currently k-means ('kmeans') or Gaussian
    Mixture Model ('gmm')

type_scaling: a tuple of 3 strings
    scaling methods for inputs, hidden layer, and clustering respectively
    (and when relevant).
    Currently available: standardization ('std') or MinMax scaling ('minmax')

type_pi: str.
    type of prediction interval; currently `None` (split or local
    conformal without simulation), "kde" or "bootstrap" (simulated split
    conformal).

replications: int.
    number of replications (if needed) for predictive simulation.
    Used only in `self.predict`, for `self.kernel` in ('gaussian',
    'tophat') and `self.type_pi = 'kde'`. Default is `None`.

kernel: str.
    the kernel to use for kernel density estimation (used for predictive
    simulation in `self.predict`, with `method='splitconformal'` and
    `type_pi = 'kde'`). Currently, either 'gaussian' or 'tophat'.

type_split: str.
    Type of splitting for conformal prediction. None (default), or
    "random" (random split of data) or "sequential" (sequential split of data)

col_sample: float
    percentage of covariates randomly chosen for training

row_sample: float
    percentage of rows chosen for training, by stratified bootstrapping

level: float
    confidence level for prediction intervals

pi_method: str
    method for prediction intervals: 'splitconformal' or 'localconformal'

seed: int
    reproducibility seed for nodes_sim=='uniform'

type_fit: str
    'regression'

backend: str
    "cpu" or "gpu" or "tpu"

Examples:

See https://thierrymoudiki.github.io/blog/2024/03/18/python/conformal-and-bayesian-regression

def fit(self, X, y, sample_weight=None, **kwargs):
174    def fit(self, X, y, sample_weight=None, **kwargs):
175        """Fit custom model to training data (X, y).
176
177        Parameters:
178
179            X: {array-like}, shape = [n_samples, n_features]
180                Training vectors, where n_samples is the number
181                of samples and n_features is the number of features.
182
183            y: array-like, shape = [n_samples]
184                Target values.
185
186            sample_weight: array-like, shape = [n_samples]
187                Sample weights.
188
189            **kwargs: additional parameters to be passed to
190                self.cook_training_set or self.obj.fit
191
192        Returns:
193
194            self: object
195
196        """
197
198        centered_y, scaled_Z = self.cook_training_set(y=y, X=X, **kwargs)
199
200        if self.level is not None:
201            self.obj = PredictionInterval(
202                obj=self.obj, method=self.pi_method, level=self.level
203            )
204
205        # if sample_weights, else: (must use self.row_index)
206        if sample_weight is not None:
207            self.obj.fit(
208                scaled_Z,
209                centered_y,
210                sample_weight=sample_weight[self.index_row_].ravel(),
211                **kwargs
212            )
213
214            return self
215
216        self.obj.fit(scaled_Z, centered_y, **kwargs)
217
218        self.X_ = X
219
220        self.y_ = y
221
222        if hasattr(self.obj, "coef_"):
223            self.coef_ = self.obj.coef_
224
225        return self

Fit custom model to training data (X, y).

Parameters:

X: {array-like}, shape = [n_samples, n_features]
    Training vectors, where n_samples is the number
    of samples and n_features is the number of features.

y: array-like, shape = [n_samples]
    Target values.

sample_weight: array-like, shape = [n_samples]
    Sample weights.

**kwargs: additional parameters to be passed to
    self.cook_training_set or self.obj.fit

Returns:

self: object
def predict(self, X, level=95, method=None, **kwargs):
265    def predict(self, X, level=95, method=None, **kwargs):
266        """Predict test data X.
267
268        Parameters:
269
270            X: {array-like}, shape = [n_samples, n_features]
271                Training vectors, where n_samples is the number
272                of samples and n_features is the number of features.
273
274            level: int
275                Level of confidence (default = 95)
276
277            method: str
278                `None`, or 'splitconformal', 'localconformal'
279                prediction (if you specify `return_pi = True`)
280
281            **kwargs: additional parameters
282                    `return_pi = True` for conformal prediction,
283                    with `method` in ('splitconformal', 'localconformal')
284                    or `return_std = True` for `self.obj` in
285                    (`sklearn.linear_model.BayesianRidge`,
286                    `sklearn.linear_model.ARDRegressor`,
287                    `sklearn.gaussian_process.GaussianProcessRegressor`)`
288
289        Returns:
290
291            model predictions:
292                an array if uncertainty quantification is not requested,
293                  or a tuple if with prediction intervals and simulations
294                  if `return_std = True` (mean, standard deviation,
295                  lower and upper prediction interval) or `return_pi = True`
296                  ()
297
298        """
299
300        if "return_std" in kwargs:
301
302            alpha = 100 - level
303            pi_multiplier = norm.ppf(1 - alpha / 200)
304
305            if len(X.shape) == 1:
306
307                n_features = X.shape[0]
308                new_X = mo.rbind(
309                    X.reshape(1, n_features),
310                    np.ones(n_features).reshape(1, n_features),
311                )
312
313                mean_, std_ = self.obj.predict(
314                    self.cook_test_set(new_X, **kwargs), return_std=True
315                )[0]
316
317                preds = self.y_mean_ + mean_
318                lower = self.y_mean_ + (mean_ - pi_multiplier * std_)
319                upper = self.y_mean_ + (mean_ + pi_multiplier * std_)
320
321                DescribeResults = namedtuple(
322                    "DescribeResults", ["mean", "std", "lower", "upper"]
323                )
324
325                return DescribeResults(preds, std_, lower, upper)
326
327            # len(X.shape) > 1
328            mean_, std_ = self.obj.predict(
329                self.cook_test_set(X, **kwargs), return_std=True
330            )
331
332            preds = self.y_mean_ + mean_
333            lower = self.y_mean_ + (mean_ - pi_multiplier * std_)
334            upper = self.y_mean_ + (mean_ + pi_multiplier * std_)
335
336            DescribeResults = namedtuple(
337                "DescribeResults", ["mean", "std", "lower", "upper"]
338            )
339
340            return DescribeResults(preds, std_, lower, upper)
341
342        if "return_pi" in kwargs:
343            assert method in (
344                "splitconformal",
345                "localconformal",
346            ), "method must be in ('splitconformal', 'localconformal')"
347            self.pi = PredictionInterval(
348                obj=self,
349                method=method,
350                level=level,
351                type_pi=self.type_pi,
352                replications=self.replications,
353                kernel=self.kernel,
354            )
355
356            if len(self.X_.shape) == 1:
357                if isinstance(X, pd.DataFrame):
358                    self.X_ = pd.DataFrame(
359                        self.X_.values.reshape(1, -1), columns=self.X_.columns
360                    )
361                else:
362                    self.X_ = self.X_.reshape(1, -1)
363                self.y_ = np.array([self.y_])
364
365            self.pi.fit(self.X_, self.y_)
366            # self.X_ = None # consumes memory to keep, dangerous to delete (side effect)
367            # self.y_ = None # consumes memory to keep, dangerous to delete (side effect)
368            preds = self.pi.predict(X, return_pi=True)
369            return preds
370
371        # "return_std" not in kwargs
372        if len(X.shape) == 1:
373
374            n_features = X.shape[0]
375            new_X = mo.rbind(
376                X.reshape(1, n_features),
377                np.ones(n_features).reshape(1, n_features),
378            )
379
380            return (
381                self.y_mean_
382                + self.obj.predict(
383                    self.cook_test_set(new_X, **kwargs), **kwargs
384                )
385            )[0]
386
387        # len(X.shape) > 1
388        return self.y_mean_ + self.obj.predict(
389            self.cook_test_set(X, **kwargs), **kwargs
390        )

Predict test data X.

Parameters:

X: {array-like}, shape = [n_samples, n_features]
    Training vectors, where n_samples is the number
    of samples and n_features is the number of features.

level: int
    Level of confidence (default = 95)

method: str
    `None`, or 'splitconformal', 'localconformal'
    prediction (if you specify `return_pi = True`)

**kwargs: additional parameters
        `return_pi = True` for conformal prediction,
        with `method` in ('splitconformal', 'localconformal')
        or `return_std = True` for `self.obj` in
        (`sklearn.linear_model.BayesianRidge`,
        `sklearn.linear_model.ARDRegressor`,
        `sklearn.gaussian_process.GaussianProcessRegressor`)`

Returns:

model predictions:
    an array if uncertainty quantification is not requested,
      or a tuple if with prediction intervals and simulations
      if `return_std = True` (mean, standard deviation,
      lower and upper prediction interval) or `return_pi = True`
      ()
def score(self, X, y, scoring=None):
392    def score(self, X, y, scoring=None):
393        """Compute the score of the model.
394
395        Parameters:
396
397            X: {array-like}, shape = [n_samples, n_features]
398                Training vectors, where n_samples is the number
399                of samples and n_features is the number of features.
400
401            y: array-like, shape = [n_samples]
402                Target values.
403
404            scoring: str
405                scoring method
406
407        Returns:
408
409            score: float
410
411        """
412
413        if scoring is None:
414            return np.sqrt(np.mean((self.predict(X) - y) ** 2))
415
416        return skm2.get_scorer(scoring)(self, X, y)

Compute the score of the model.

Parameters:

X: {array-like}, shape = [n_samples, n_features]
    Training vectors, where n_samples is the number
    of samples and n_features is the number of features.

y: array-like, shape = [n_samples]
    Target values.

scoring: str
    scoring method

Returns:

score: float
class DeepClassifier(nnetsauce.CustomClassifier, sklearn.base.ClassifierMixin):
 30class DeepClassifier(CustomClassifier, ClassifierMixin):
 31    """
 32    Deep Classifier
 33
 34    Parameters:
 35
 36        obj: an object
 37            A base learner, see also https://www.researchgate.net/publication/380701207_Deep_Quasi-Randomized_neural_Networks_for_classification
 38
 39        n_layers: int (default=3)
 40            Number of layers. `n_layers = 1` is a simple `CustomClassifier`
 41
 42        verbose : int, optional (default=0)
 43            Monitor progress when fitting.
 44
 45        All the other parameters are nnetsauce `CustomClassifier`'s
 46
 47    Examples:
 48
 49        ```python
 50        import nnetsauce as ns
 51        from sklearn.datasets import load_breast_cancer
 52        from sklearn.model_selection import train_test_split
 53        from sklearn.linear_model import LogisticRegressionCV
 54        data = load_breast_cancer()
 55        X = data.data
 56        y= data.target
 57        X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=.2, random_state=123)
 58        obj = LogisticRegressionCV()
 59        clf = ns.DeepClassifier(obj)
 60        clf.fit(X_train, y_train)
 61        print(clf.score(clf.predict(X_test), y_test))
 62        ```
 63    """
 64
 65    def __init__(
 66        self,
 67        obj,
 68        # Defining depth
 69        n_layers=3,
 70        verbose=0,
 71        # CustomClassifier attributes
 72        n_hidden_features=5,
 73        activation_name="relu",
 74        a=0.01,
 75        nodes_sim="sobol",
 76        bias=True,
 77        dropout=0,
 78        direct_link=True,
 79        n_clusters=2,
 80        cluster_encode=True,
 81        type_clust="kmeans",
 82        type_scaling=("std", "std", "std"),
 83        col_sample=1,
 84        row_sample=1,
 85        level=None,
 86        pi_method="icp",
 87        seed=123,
 88        backend="cpu",
 89    ):
 90        super().__init__(
 91            obj=obj,
 92            n_hidden_features=n_hidden_features,
 93            activation_name=activation_name,
 94            a=a,
 95            nodes_sim=nodes_sim,
 96            bias=bias,
 97            dropout=dropout,
 98            direct_link=direct_link,
 99            n_clusters=n_clusters,
100            cluster_encode=cluster_encode,
101            type_clust=type_clust,
102            type_scaling=type_scaling,
103            col_sample=col_sample,
104            row_sample=row_sample,
105            level=level,
106            pi_method=pi_method,
107            seed=seed,
108            backend=backend,
109        )
110
111        assert n_layers >= 1, "must have n_layers >= 1"
112
113        self.stacked_obj = deepcopy(obj)
114        self.verbose = verbose
115        self.n_layers = n_layers
116        self.classes_ = None
117        self.n_classes_ = None
118
119    def fit(self, X, y, **kwargs):
120        """Fit Classification algorithms to X and y.
121        Parameters
122        ----------
123        X : array-like,
124            Training vectors, where rows is the number of samples
125            and columns is the number of features.
126        y : array-like,
127            Training vectors, where rows is the number of samples
128            and columns is the number of features.
129        **kwargs: dict
130            Additional parameters to be passed to the fit method
131            of the base learner. For example, `sample_weight`.
132
133        Returns
134        -------
135        A fitted object
136        """
137
138        self.classes_ = np.unique(y)
139        self.n_classes_ = len(
140            self.classes_
141        )  # for compatibility with         scikit-learn
142
143        if isinstance(X, np.ndarray):
144            X = pd.DataFrame(X)
145
146        # init layer
147        self.stacked_obj = CustomClassifier(
148            obj=self.stacked_obj,
149            n_hidden_features=self.n_hidden_features,
150            activation_name=self.activation_name,
151            a=self.a,
152            nodes_sim=self.nodes_sim,
153            bias=self.bias,
154            dropout=self.dropout,
155            direct_link=self.direct_link,
156            n_clusters=self.n_clusters,
157            cluster_encode=self.cluster_encode,
158            type_clust=self.type_clust,
159            type_scaling=self.type_scaling,
160            col_sample=self.col_sample,
161            row_sample=self.row_sample,
162            seed=self.seed,
163            backend=self.backend,
164        )
165
166        if self.verbose > 0:
167            iterator = tqdm(range(self.n_layers - 1))
168        else:
169            iterator = range(self.n_layers - 1)
170
171        for _ in iterator:
172            self.stacked_obj = deepcopy(
173                CustomClassifier(
174                    obj=self.stacked_obj,
175                    n_hidden_features=self.n_hidden_features,
176                    activation_name=self.activation_name,
177                    a=self.a,
178                    nodes_sim=self.nodes_sim,
179                    bias=self.bias,
180                    dropout=self.dropout,
181                    direct_link=self.direct_link,
182                    n_clusters=self.n_clusters,
183                    cluster_encode=self.cluster_encode,
184                    type_clust=self.type_clust,
185                    type_scaling=self.type_scaling,
186                    col_sample=self.col_sample,
187                    row_sample=self.row_sample,
188                    seed=self.seed,
189                    backend=self.backend,
190                )
191            )
192
193        self.stacked_obj.fit(X, y, **kwargs)
194
195        if self.level is not None:
196            self.stacked_obj = PredictionSet(
197                obj=self.stacked_obj, method=self.pi_method, level=self.level
198            )
199
200        return self
201
202    def partial_fit(self, X, y, **kwargs):
203        """Fit Regression algorithms to X and y.
204        Parameters
205        ----------
206        X : array-like,
207            Training vectors, where rows is the number of samples
208            and columns is the number of features.
209        y : array-like,
210            Training vectors, where rows is the number of samples
211            and columns is the number of features.
212        **kwargs: dict
213            Additional parameters to be passed to the fit method
214            of the base learner. For example, `sample_weight`.
215        Returns
216        -------
217        A fitted object
218        """
219        assert hasattr(self, "stacked_obj"), "model must be fitted first"
220        current_obj = self.stacked_obj
221        for _ in range(self.n_layers):
222            try:
223                input_X = current_obj.obj.cook_test_set(X)
224                current_obj.obj.partial_fit(input_X, y, **kwargs)
225                try:
226                    current_obj = current_obj.obj
227                except AttributeError:
228                    pass
229            except ValueError:
230                pass
231        return self
232
233    def predict(self, X):
234        return self.stacked_obj.predict(X)
235
236    def predict_proba(self, X):
237        return self.stacked_obj.predict_proba(X)
238
239    def score(self, X, y, scoring=None):
240        return self.stacked_obj.score(X, y, scoring)
241
242    def cross_val_optim(
243        self,
244        X_train,
245        y_train,
246        X_test=None,
247        y_test=None,
248        scoring="accuracy",
249        surrogate_obj=None,
250        cv=5,
251        n_jobs=None,
252        n_init=10,
253        n_iter=190,
254        abs_tol=1e-3,
255        verbose=2,
256        seed=123,
257        **kwargs,
258    ):
259        """Cross-validation function and hyperparameters' search
260
261        Parameters:
262
263            X_train: array-like,
264                Training vectors, where rows is the number of samples
265                and columns is the number of features.
266
267            y_train: array-like,
268                Training vectors, where rows is the number of samples
269                and columns is the number of features.
270
271            X_test: array-like,
272                Testing vectors, where rows is the number of samples
273                and columns is the number of features.
274
275            y_test: array-like,
276                Testing vectors, where rows is the number of samples
277                and columns is the number of features.
278
279            scoring: str
280                scoring metric; see https://scikit-learn.org/stable/modules/model_evaluation.html#the-scoring-parameter-defining-model-evaluation-rules
281
282            surrogate_obj: an object;
283                An ML model for estimating the uncertainty around the objective function
284
285            cv: int;
286                number of cross-validation folds
287
288            n_jobs: int;
289                number of jobs for parallel execution
290
291            n_init: an integer;
292                number of points in the initial setting, when `x_init` and `y_init` are not provided
293
294            n_iter: an integer;
295                number of iterations of the minimization algorithm
296
297            abs_tol: a float;
298                tolerance for convergence of the optimizer (early stopping based on acquisition function)
299
300            verbose: int
301                controls verbosity
302
303            seed: int
304                reproducibility seed
305
306            **kwargs: dict
307                additional parameters to be passed to the estimator
308
309        Examples:
310
311            ```python
312            ```
313        """
314
315        num_to_activation_name = {1: "relu", 2: "sigmoid", 3: "tanh"}
316        num_to_nodes_sim = {1: "sobol", 2: "uniform", 3: "hammersley"}
317        num_to_type_clust = {1: "kmeans", 2: "gmm"}
318
319        def deepclassifier_cv(
320            X_train,
321            y_train,
322            # Defining depth
323            n_layers=3,
324            # CustomClassifier attributes
325            n_hidden_features=5,
326            activation_name="relu",
327            nodes_sim="sobol",
328            dropout=0,
329            n_clusters=2,
330            type_clust="kmeans",
331            cv=5,
332            n_jobs=None,
333            scoring="accuracy",
334            seed=123,
335        ):
336            self.set_params(
337                **{
338                    "n_layers": n_layers,
339                    # CustomClassifier attributes
340                    "n_hidden_features": n_hidden_features,
341                    "activation_name": activation_name,
342                    "nodes_sim": nodes_sim,
343                    "dropout": dropout,
344                    "n_clusters": n_clusters,
345                    "type_clust": type_clust,
346                    **kwargs,
347                }
348            )
349            return -cross_val_score(
350                estimator=self,
351                X=X_train,
352                y=y_train,
353                scoring=scoring,
354                cv=cv,
355                n_jobs=n_jobs,
356                verbose=0,
357            ).mean()
358
359        # objective function for hyperparams tuning
360        def crossval_objective(xx):
361            return deepclassifier_cv(
362                X_train=X_train,
363                y_train=y_train,
364                # Defining depth
365                n_layers=int(np.ceil(xx[0])),
366                # CustomClassifier attributes
367                n_hidden_features=int(np.ceil(xx[1])),
368                activation_name=num_to_activation_name[np.ceil(xx[2])],
369                nodes_sim=num_to_nodes_sim[int(np.ceil(xx[3]))],
370                dropout=xx[4],
371                n_clusters=int(np.ceil(xx[5])),
372                type_clust=num_to_type_clust[int(np.ceil(xx[6]))],
373                cv=cv,
374                n_jobs=n_jobs,
375                scoring=scoring,
376                seed=seed,
377            )
378
379        if surrogate_obj is None:
380            gp_opt = gp.GPOpt(
381                objective_func=crossval_objective,
382                lower_bound=np.array([0, 3, 0, 0, 0.0, 0, 0]),
383                upper_bound=np.array([5, 100, 3, 3, 0.4, 5, 2]),
384                params_names=[
385                    "n_layers",
386                    # CustomClassifier attributes
387                    "n_hidden_features",
388                    "activation_name",
389                    "nodes_sim",
390                    "dropout",
391                    "n_clusters",
392                    "type_clust",
393                ],
394                method="bayesian",
395                n_init=n_init,
396                n_iter=n_iter,
397                seed=seed,
398            )
399        else:
400            gp_opt = gp.GPOpt(
401                objective_func=crossval_objective,
402                lower_bound=np.array([0, 3, 0, 0, 0.0, 0, 0]),
403                upper_bound=np.array([5, 100, 3, 3, 0.4, 5, 2]),
404                params_names=[
405                    "n_layers",
406                    # CustomClassifier attributes
407                    "n_hidden_features",
408                    "activation_name",
409                    "nodes_sim",
410                    "dropout",
411                    "n_clusters",
412                    "type_clust",
413                ],
414                acquisition="ucb",
415                method="splitconformal",
416                surrogate_obj=ns.PredictionInterval(
417                    obj=surrogate_obj, method="splitconformal"
418                ),
419                n_init=n_init,
420                n_iter=n_iter,
421                seed=seed,
422            )
423
424        res = gp_opt.optimize(verbose=verbose, abs_tol=abs_tol)
425        res.best_params["n_layers"] = int(np.ceil(res.best_params["n_layers"]))
426        res.best_params["n_hidden_features"] = int(
427            np.ceil(res.best_params["n_hidden_features"])
428        )
429        res.best_params["activation_name"] = num_to_activation_name[
430            np.ceil(res.best_params["activation_name"])
431        ]
432        res.best_params["nodes_sim"] = num_to_nodes_sim[
433            int(np.ceil(res.best_params["nodes_sim"]))
434        ]
435        res.best_params["dropout"] = res.best_params["dropout"]
436        res.best_params["n_clusters"] = int(
437            np.ceil(res.best_params["n_clusters"])
438        )
439        res.best_params["type_clust"] = num_to_type_clust[
440            int(np.ceil(res.best_params["type_clust"]))
441        ]
442
443        # out-of-sample error
444        if X_test is not None and y_test is not None:
445            self.set_params(**res.best_params, verbose=0, seed=seed)
446            preds = self.fit(X_train, y_train).predict(X_test)
447            # check error on y_test
448            oos_err = getattr(metrics, scoring + "_score")(
449                y_true=y_test, y_pred=preds
450            )
451            result = namedtuple("result", res._fields + ("test_" + scoring,))
452            return result(*res, oos_err)
453        else:
454            return res
455
456    def lazy_cross_val_optim(
457        self,
458        X_train,
459        y_train,
460        X_test=None,
461        y_test=None,
462        scoring="accuracy",
463        surrogate_objs=None,
464        customize=False,
465        cv=5,
466        n_jobs=None,
467        n_init=10,
468        n_iter=190,
469        abs_tol=1e-3,
470        verbose=1,
471        seed=123,
472    ):
473        """Automated Cross-validation function and hyperparameters' search using multiple surrogates
474
475        Parameters:
476
477            X_train: array-like,
478                Training vectors, where rows is the number of samples
479                and columns is the number of features.
480
481            y_train: array-like,
482                Training vectors, where rows is the number of samples
483                and columns is the number of features.
484
485            X_test: array-like,
486                Testing vectors, where rows is the number of samples
487                and columns is the number of features.
488
489            y_test: array-like,
490                Testing vectors, where rows is the number of samples
491                and columns is the number of features.
492
493            scoring: str
494                scoring metric; see https://scikit-learn.org/stable/modules/model_evaluation.html#the-scoring-parameter-defining-model-evaluation-rules
495
496            surrogate_objs: object names as a list of strings;
497                ML models for estimating the uncertainty around the objective function
498
499            customize: boolean
500                if True, the surrogate is transformed into a quasi-randomized network (default is False)
501
502            cv: int;
503                number of cross-validation folds
504
505            n_jobs: int;
506                number of jobs for parallel execution
507
508            n_init: an integer;
509                number of points in the initial setting, when `x_init` and `y_init` are not provided
510
511            n_iter: an integer;
512                number of iterations of the minimization algorithm
513
514            abs_tol: a float;
515                tolerance for convergence of the optimizer (early stopping based on acquisition function)
516
517            verbose: int
518                controls verbosity
519
520            seed: int
521                reproducibility seed
522
523        Examples:
524
525            ```python
526            ```
527        """
528
529        removed_regressors = [
530            "TheilSenRegressor",
531            "ARDRegression",
532            "CCA",
533            "GaussianProcessRegressor",
534            "GradientBoostingRegressor",
535            "HistGradientBoostingRegressor",
536            "IsotonicRegression",
537            "MultiOutputRegressor",
538            "MultiTaskElasticNet",
539            "MultiTaskElasticNetCV",
540            "MultiTaskLasso",
541            "MultiTaskLassoCV",
542            "OrthogonalMatchingPursuit",
543            "OrthogonalMatchingPursuitCV",
544            "PLSCanonical",
545            "PLSRegression",
546            "RadiusNeighborsRegressor",
547            "RegressorChain",
548            "StackingRegressor",
549            "VotingRegressor",
550        ]
551
552        results = []
553
554        for est in all_estimators():
555
556            if surrogate_objs is None:
557
558                if issubclass(est[1], RegressorMixin) and (
559                    est[0] not in removed_regressors
560                ):
561                    try:
562                        if customize == True:
563                            print(f"\n surrogate: CustomClassifier({est[0]})")
564                            surr_obj = ns.CustomClassifier(obj=est[1]())
565                        else:
566                            print(f"\n surrogate: {est[0]}")
567                            surr_obj = est[1]()
568                        res = self.cross_val_optim(
569                            X_train=X_train,
570                            y_train=y_train,
571                            X_test=X_test,
572                            y_test=y_test,
573                            surrogate_obj=surr_obj,
574                            cv=cv,
575                            n_jobs=n_jobs,
576                            scoring=scoring,
577                            n_init=n_init,
578                            n_iter=n_iter,
579                            abs_tol=abs_tol,
580                            verbose=verbose,
581                            seed=seed,
582                        )
583                        print(f"\n result: {res}")
584                        if customize == True:
585                            results.append((f"CustomClassifier({est[0]})", res))
586                        else:
587                            results.append((est[0], res))
588                    except:
589                        pass
590
591            else:
592
593                if (
594                    issubclass(est[1], RegressorMixin)
595                    and (est[0] not in removed_regressors)
596                    and est[0] in surrogate_objs
597                ):
598                    try:
599                        if customize == True:
600                            print(f"\n surrogate: CustomClassifier({est[0]})")
601                            surr_obj = ns.CustomClassifier(obj=est[1]())
602                        else:
603                            print(f"\n surrogate: {est[0]}")
604                            surr_obj = est[1]()
605                        res = self.cross_val_optim(
606                            X_train=X_train,
607                            y_train=y_train,
608                            X_test=X_test,
609                            y_test=y_test,
610                            surrogate_obj=surr_obj,
611                            cv=cv,
612                            n_jobs=n_jobs,
613                            scoring=scoring,
614                            n_init=n_init,
615                            n_iter=n_iter,
616                            abs_tol=abs_tol,
617                            verbose=verbose,
618                            seed=seed,
619                        )
620                        print(f"\n result: {res}")
621                        if customize == True:
622                            results.append((f"CustomClassifier({est[0]})", res))
623                        else:
624                            results.append((est[0], res))
625                    except:
626                        pass
627
628        return results

Deep Classifier

Parameters:

obj: an object
    A base learner, see also https://www.researchgate.net/publication/380701207_Deep_Quasi-Randomized_neural_Networks_for_classification

n_layers: int (default=3)
    Number of layers. `n_layers = 1` is a simple `CustomClassifier`

verbose : int, optional (default=0)
    Monitor progress when fitting.

All the other parameters are nnetsauce `CustomClassifier`'s

Examples:

import nnetsauce as ns
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegressionCV
data = load_breast_cancer()
X = data.data
y= data.target
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=.2, random_state=123)
obj = LogisticRegressionCV()
clf = ns.DeepClassifier(obj)
clf.fit(X_train, y_train)
print(clf.score(clf.predict(X_test), y_test))
def fit(self, X, y, **kwargs):
119    def fit(self, X, y, **kwargs):
120        """Fit Classification algorithms to X and y.
121        Parameters
122        ----------
123        X : array-like,
124            Training vectors, where rows is the number of samples
125            and columns is the number of features.
126        y : array-like,
127            Training vectors, where rows is the number of samples
128            and columns is the number of features.
129        **kwargs: dict
130            Additional parameters to be passed to the fit method
131            of the base learner. For example, `sample_weight`.
132
133        Returns
134        -------
135        A fitted object
136        """
137
138        self.classes_ = np.unique(y)
139        self.n_classes_ = len(
140            self.classes_
141        )  # for compatibility with         scikit-learn
142
143        if isinstance(X, np.ndarray):
144            X = pd.DataFrame(X)
145
146        # init layer
147        self.stacked_obj = CustomClassifier(
148            obj=self.stacked_obj,
149            n_hidden_features=self.n_hidden_features,
150            activation_name=self.activation_name,
151            a=self.a,
152            nodes_sim=self.nodes_sim,
153            bias=self.bias,
154            dropout=self.dropout,
155            direct_link=self.direct_link,
156            n_clusters=self.n_clusters,
157            cluster_encode=self.cluster_encode,
158            type_clust=self.type_clust,
159            type_scaling=self.type_scaling,
160            col_sample=self.col_sample,
161            row_sample=self.row_sample,
162            seed=self.seed,
163            backend=self.backend,
164        )
165
166        if self.verbose > 0:
167            iterator = tqdm(range(self.n_layers - 1))
168        else:
169            iterator = range(self.n_layers - 1)
170
171        for _ in iterator:
172            self.stacked_obj = deepcopy(
173                CustomClassifier(
174                    obj=self.stacked_obj,
175                    n_hidden_features=self.n_hidden_features,
176                    activation_name=self.activation_name,
177                    a=self.a,
178                    nodes_sim=self.nodes_sim,
179                    bias=self.bias,
180                    dropout=self.dropout,
181                    direct_link=self.direct_link,
182                    n_clusters=self.n_clusters,
183                    cluster_encode=self.cluster_encode,
184                    type_clust=self.type_clust,
185                    type_scaling=self.type_scaling,
186                    col_sample=self.col_sample,
187                    row_sample=self.row_sample,
188                    seed=self.seed,
189                    backend=self.backend,
190                )
191            )
192
193        self.stacked_obj.fit(X, y, **kwargs)
194
195        if self.level is not None:
196            self.stacked_obj = PredictionSet(
197                obj=self.stacked_obj, method=self.pi_method, level=self.level
198            )
199
200        return self

Fit Classification algorithms to X and y.

Parameters

X : array-like, Training vectors, where rows is the number of samples and columns is the number of features. y : array-like, Training vectors, where rows is the number of samples and columns is the number of features. **kwargs: dict Additional parameters to be passed to the fit method of the base learner. For example, sample_weight.

Returns

A fitted object

def predict(self, X):
233    def predict(self, X):
234        return self.stacked_obj.predict(X)

Predict test data X.

Parameters:

X: {array-like}, shape = [n_samples, n_features]
    Training vectors, where n_samples is the number
    of samples and n_features is the number of features.

**kwargs: additional parameters to be passed to
        self.cook_test_set

Returns:

model predictions: {array-like}
def predict_proba(self, X):
236    def predict_proba(self, X):
237        return self.stacked_obj.predict_proba(X)

Predict probabilities for test data X.

Args:

X: {array-like}, shape = [n_samples, n_features]
    Training vectors, where n_samples is the number
    of samples and n_features is the number of features.

**kwargs: additional parameters to be passed to
        self.cook_test_set

Returns:

probability estimates for test data: {array-like}
def score(self, X, y, scoring=None):
239    def score(self, X, y, scoring=None):
240        return self.stacked_obj.score(X, y, scoring)

Scoring function for classification.

Args:

X: {array-like}, shape = [n_samples, n_features]
    Training vectors, where n_samples is the number
    of samples and n_features is the number of features.

y: array-like, shape = [n_samples]
    Target values.

scoring: str
    scoring method (default is accuracy)

Returns:

score: float
class DeepRegressor(nnetsauce.CustomRegressor, sklearn.base.RegressorMixin):
 13class DeepRegressor(CustomRegressor, RegressorMixin):
 14    """
 15    Deep Regressor
 16
 17    Parameters:
 18
 19        obj: an object
 20            A base learner, see also https://www.researchgate.net/publication/380701207_Deep_Quasi-Randomized_neural_Networks_for_classification
 21
 22        verbose : int, optional (default=0)
 23            Monitor progress when fitting.
 24
 25        n_layers: int (default=3)
 26            Number of layers. `n_layers = 1` is a simple `CustomRegressor`
 27
 28        All the other parameters are nnetsauce `CustomRegressor`'s
 29
 30    Examples:
 31
 32        ```python
 33        import nnetsauce as ns
 34        from sklearn.datasets import load_diabetes
 35        from sklearn.model_selection import train_test_split
 36        from sklearn.linear_model import RidgeCV
 37        data = load_diabetes()
 38        X = data.data
 39        y= data.target
 40        X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=.2, random_state=123)
 41        obj = RidgeCV()
 42        clf = ns.DeepRegressor(obj)
 43        clf.fit(X_train, y_train)
 44        print(clf.score(clf.predict(X_test), y_test))
 45        ```
 46
 47    """
 48
 49    def __init__(
 50        self,
 51        obj,
 52        # Defining depth
 53        n_layers=3,
 54        verbose=0,
 55        # CustomRegressor attributes
 56        n_hidden_features=5,
 57        activation_name="relu",
 58        a=0.01,
 59        nodes_sim="sobol",
 60        bias=True,
 61        dropout=0,
 62        direct_link=True,
 63        n_clusters=2,
 64        cluster_encode=True,
 65        type_clust="kmeans",
 66        type_scaling=("std", "std", "std"),
 67        col_sample=1,
 68        row_sample=1,
 69        level=None,
 70        pi_method="splitconformal",
 71        seed=123,
 72        backend="cpu",
 73    ):
 74        super().__init__(
 75            obj=obj,
 76            n_hidden_features=n_hidden_features,
 77            activation_name=activation_name,
 78            a=a,
 79            nodes_sim=nodes_sim,
 80            bias=bias,
 81            dropout=dropout,
 82            direct_link=direct_link,
 83            n_clusters=n_clusters,
 84            cluster_encode=cluster_encode,
 85            type_clust=type_clust,
 86            type_scaling=type_scaling,
 87            col_sample=col_sample,
 88            row_sample=row_sample,
 89            level=level,
 90            pi_method=pi_method,
 91            seed=seed,
 92            backend=backend,
 93        )
 94
 95        assert n_layers >= 1, "must have n_layers >= 1"
 96
 97        self.stacked_obj = deepcopy(obj)
 98        self.verbose = verbose
 99        self.n_layers = n_layers
100        self.level = level
101        self.pi_method = pi_method
102        self.coef_ = None
103
104    def fit(self, X, y, **kwargs):
105        """Fit Regression algorithms to X and y.
106        Parameters
107        ----------
108        X : array-like,
109            Training vectors, where rows is the number of samples
110            and columns is the number of features.
111        y : array-like,
112            Training vectors, where rows is the number of samples
113            and columns is the number of features.
114        **kwargs: dict
115            Additional parameters to be passed to the fit method
116            of the base learner. For example, `sample_weight`.
117        Returns
118        -------
119        A fitted object
120        """
121
122        if isinstance(X, np.ndarray):
123            X = pd.DataFrame(X)
124
125        # init layer
126        self.stacked_obj = CustomRegressor(
127            obj=self.stacked_obj,
128            n_hidden_features=self.n_hidden_features,
129            activation_name=self.activation_name,
130            a=self.a,
131            nodes_sim=self.nodes_sim,
132            bias=self.bias,
133            dropout=self.dropout,
134            direct_link=self.direct_link,
135            n_clusters=self.n_clusters,
136            cluster_encode=self.cluster_encode,
137            type_clust=self.type_clust,
138            type_scaling=self.type_scaling,
139            col_sample=self.col_sample,
140            row_sample=self.row_sample,
141            seed=self.seed,
142            backend=self.backend,
143        )
144
145        if self.verbose > 0:
146            iterator = tqdm(range(self.n_layers - 1))
147        else:
148            iterator = range(self.n_layers - 1)
149
150        for _ in iterator:
151            self.stacked_obj = deepcopy(
152                CustomRegressor(
153                    obj=self.stacked_obj,
154                    n_hidden_features=self.n_hidden_features,
155                    activation_name=self.activation_name,
156                    a=self.a,
157                    nodes_sim=self.nodes_sim,
158                    bias=self.bias,
159                    dropout=self.dropout,
160                    direct_link=self.direct_link,
161                    n_clusters=self.n_clusters,
162                    cluster_encode=self.cluster_encode,
163                    type_clust=self.type_clust,
164                    type_scaling=self.type_scaling,
165                    col_sample=self.col_sample,
166                    row_sample=self.row_sample,
167                    seed=self.seed,
168                    backend=self.backend,
169                )
170            )
171
172        self.stacked_obj.fit(X, y, **kwargs)
173
174        if self.level is not None:
175            self.stacked_obj = PredictionInterval(
176                obj=self.stacked_obj, method=self.pi_method, level=self.level
177            )
178
179        if hasattr(self.stacked_obj, "clustering_obj_"):
180            self.clustering_obj_ = self.stacked_obj.clustering_obj_
181
182        if hasattr(self.stacked_obj, "coef_"):
183            self.coef_ = self.stacked_obj.coef_
184
185        if hasattr(self.stacked_obj, "scaler_"):
186            self.scaler_ = self.stacked_obj.scaler_
187
188        if hasattr(self.stacked_obj, "nn_scaler_"):
189            self.nn_scaler_ = self.stacked_obj.nn_scaler_
190
191        if hasattr(self.stacked_obj, "clustering_scaler_"):
192            self.clustering_scaler_ = self.stacked_obj.clustering_scaler_
193
194        return self
195
196    def partial_fit(self, X, y, **kwargs):
197        """Fit Regression algorithms to X and y.
198        Parameters
199        ----------
200        X : array-like,
201            Training vectors, where rows is the number of samples
202            and columns is the number of features.
203        y : array-like,
204            Training vectors, where rows is the number of samples
205            and columns is the number of features.
206        **kwargs: dict
207            Additional parameters to be passed to the fit method
208            of the base learner. For example, `sample_weight`.
209        Returns
210        -------
211        A fitted object
212        """
213        assert hasattr(self, "stacked_obj"), "model must be fitted first"
214        current_obj = self.stacked_obj
215        for _ in range(self.n_layers):
216            try:
217                input_X = current_obj.obj.cook_test_set(X)
218                current_obj.obj.partial_fit(input_X, y, **kwargs)
219                try:
220                    current_obj = current_obj.obj
221                except AttributeError:
222                    pass
223            except ValueError as e:
224                print(e)
225                pass
226        return self
227
228    def predict(self, X, **kwargs):
229        if self.level is not None:
230            return self.stacked_obj.predict(X, return_pi=True)
231        return self.stacked_obj.predict(X, **kwargs)
232
233    def score(self, X, y, scoring=None):
234        return self.stacked_obj.score(X, y, scoring)

Deep Regressor

Parameters:

obj: an object
    A base learner, see also https://www.researchgate.net/publication/380701207_Deep_Quasi-Randomized_neural_Networks_for_classification

verbose : int, optional (default=0)
    Monitor progress when fitting.

n_layers: int (default=3)
    Number of layers. `n_layers = 1` is a simple `CustomRegressor`

All the other parameters are nnetsauce `CustomRegressor`'s

Examples:

import nnetsauce as ns
from sklearn.datasets import load_diabetes
from sklearn.model_selection import train_test_split
from sklearn.linear_model import RidgeCV
data = load_diabetes()
X = data.data
y= data.target
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=.2, random_state=123)
obj = RidgeCV()
clf = ns.DeepRegressor(obj)
clf.fit(X_train, y_train)
print(clf.score(clf.predict(X_test), y_test))
def fit(self, X, y, **kwargs):
104    def fit(self, X, y, **kwargs):
105        """Fit Regression algorithms to X and y.
106        Parameters
107        ----------
108        X : array-like,
109            Training vectors, where rows is the number of samples
110            and columns is the number of features.
111        y : array-like,
112            Training vectors, where rows is the number of samples
113            and columns is the number of features.
114        **kwargs: dict
115            Additional parameters to be passed to the fit method
116            of the base learner. For example, `sample_weight`.
117        Returns
118        -------
119        A fitted object
120        """
121
122        if isinstance(X, np.ndarray):
123            X = pd.DataFrame(X)
124
125        # init layer
126        self.stacked_obj = CustomRegressor(
127            obj=self.stacked_obj,
128            n_hidden_features=self.n_hidden_features,
129            activation_name=self.activation_name,
130            a=self.a,
131            nodes_sim=self.nodes_sim,
132            bias=self.bias,
133            dropout=self.dropout,
134            direct_link=self.direct_link,
135            n_clusters=self.n_clusters,
136            cluster_encode=self.cluster_encode,
137            type_clust=self.type_clust,
138            type_scaling=self.type_scaling,
139            col_sample=self.col_sample,
140            row_sample=self.row_sample,
141            seed=self.seed,
142            backend=self.backend,
143        )
144
145        if self.verbose > 0:
146            iterator = tqdm(range(self.n_layers - 1))
147        else:
148            iterator = range(self.n_layers - 1)
149
150        for _ in iterator:
151            self.stacked_obj = deepcopy(
152                CustomRegressor(
153                    obj=self.stacked_obj,
154                    n_hidden_features=self.n_hidden_features,
155                    activation_name=self.activation_name,
156                    a=self.a,
157                    nodes_sim=self.nodes_sim,
158                    bias=self.bias,
159                    dropout=self.dropout,
160                    direct_link=self.direct_link,
161                    n_clusters=self.n_clusters,
162                    cluster_encode=self.cluster_encode,
163                    type_clust=self.type_clust,
164                    type_scaling=self.type_scaling,
165                    col_sample=self.col_sample,
166                    row_sample=self.row_sample,
167                    seed=self.seed,
168                    backend=self.backend,
169                )
170            )
171
172        self.stacked_obj.fit(X, y, **kwargs)
173
174        if self.level is not None:
175            self.stacked_obj = PredictionInterval(
176                obj=self.stacked_obj, method=self.pi_method, level=self.level
177            )
178
179        if hasattr(self.stacked_obj, "clustering_obj_"):
180            self.clustering_obj_ = self.stacked_obj.clustering_obj_
181
182        if hasattr(self.stacked_obj, "coef_"):
183            self.coef_ = self.stacked_obj.coef_
184
185        if hasattr(self.stacked_obj, "scaler_"):
186            self.scaler_ = self.stacked_obj.scaler_
187
188        if hasattr(self.stacked_obj, "nn_scaler_"):
189            self.nn_scaler_ = self.stacked_obj.nn_scaler_
190
191        if hasattr(self.stacked_obj, "clustering_scaler_"):
192            self.clustering_scaler_ = self.stacked_obj.clustering_scaler_
193
194        return self

Fit Regression algorithms to X and y.

Parameters

X : array-like, Training vectors, where rows is the number of samples and columns is the number of features. y : array-like, Training vectors, where rows is the number of samples and columns is the number of features. **kwargs: dict Additional parameters to be passed to the fit method of the base learner. For example, sample_weight.

Returns

A fitted object

def predict(self, X, **kwargs):
228    def predict(self, X, **kwargs):
229        if self.level is not None:
230            return self.stacked_obj.predict(X, return_pi=True)
231        return self.stacked_obj.predict(X, **kwargs)

Predict test data X.

Parameters:

X: {array-like}, shape = [n_samples, n_features]
    Training vectors, where n_samples is the number
    of samples and n_features is the number of features.

level: int
    Level of confidence (default = 95)

method: str
    `None`, or 'splitconformal', 'localconformal'
    prediction (if you specify `return_pi = True`)

**kwargs: additional parameters
        `return_pi = True` for conformal prediction,
        with `method` in ('splitconformal', 'localconformal')
        or `return_std = True` for `self.obj` in
        (`sklearn.linear_model.BayesianRidge`,
        `sklearn.linear_model.ARDRegressor`,
        `sklearn.gaussian_process.GaussianProcessRegressor`)`

Returns:

model predictions:
    an array if uncertainty quantification is not requested,
      or a tuple if with prediction intervals and simulations
      if `return_std = True` (mean, standard deviation,
      lower and upper prediction interval) or `return_pi = True`
      ()
def score(self, X, y, scoring=None):
233    def score(self, X, y, scoring=None):
234        return self.stacked_obj.score(X, y, scoring)

Compute the score of the model.

Parameters:

X: {array-like}, shape = [n_samples, n_features]
    Training vectors, where n_samples is the number
    of samples and n_features is the number of features.

y: array-like, shape = [n_samples]
    Target values.

scoring: str
    scoring method

Returns:

score: float
class DeepMTS(nnetsauce.MTS):
 11class DeepMTS(MTS):
 12    """Univariate and multivariate time series (DeepMTS) forecasting with Quasi-Randomized networks (Work in progress /!\)
 13
 14    Parameters:
 15
 16        obj: object.
 17            any object containing a method fit (obj.fit()) and a method predict
 18            (obj.predict()).
 19
 20        n_layers: int.
 21            number of layers in the neural network.
 22
 23        n_hidden_features: int.
 24            number of nodes in the hidden layer.
 25
 26        activation_name: str.
 27            activation function: 'relu', 'tanh', 'sigmoid', 'prelu' or 'elu'.
 28
 29        a: float.
 30            hyperparameter for 'prelu' or 'elu' activation function.
 31
 32        nodes_sim: str.
 33            type of simulation for the nodes: 'sobol', 'hammersley', 'halton',
 34            'uniform'.
 35
 36        bias: boolean.
 37            indicates if the hidden layer contains a bias term (True) or not
 38            (False).
 39
 40        dropout: float.
 41            regularization parameter; (random) percentage of nodes dropped out
 42            of the training.
 43
 44        direct_link: boolean.
 45            indicates if the original predictors are included (True) in model's fitting or not (False).
 46
 47        n_clusters: int.
 48            number of clusters for 'kmeans' or 'gmm' clustering (could be 0: no clustering).
 49
 50        cluster_encode: bool.
 51            defines how the variable containing clusters is treated (default is one-hot)
 52            if `False`, then labels are used, without one-hot encoding.
 53
 54        type_clust: str.
 55            type of clustering method: currently k-means ('kmeans') or Gaussian
 56            Mixture Model ('gmm').
 57
 58        type_scaling: a tuple of 3 strings.
 59            scaling methods for inputs, hidden layer, and clustering respectively
 60            (and when relevant).
 61            Currently available: standardization ('std') or MinMax scaling ('minmax').
 62
 63        lags: int.
 64            number of lags used for each time series.
 65
 66        type_pi: str.
 67            type of prediction interval; currently:
 68            - "gaussian": simple, fast, but: assumes stationarity of Gaussian in-sample residuals and independence in the multivariate case
 69            - "kde": based on Kernel Density Estimation of in-sample residuals
 70            - "bootstrap": based on independent bootstrap of in-sample residuals
 71            - "block-bootstrap": based on basic block bootstrap of in-sample residuals
 72            - "scp-kde": Sequential split conformal prediction with Kernel Density Estimation of calibrated residuals
 73            - "scp-bootstrap": Sequential split conformal prediction with independent bootstrap of calibrated residuals
 74            - "scp-block-bootstrap": Sequential split conformal prediction with basic block bootstrap of calibrated residuals
 75            - "scp2-kde": Sequential split conformal prediction with Kernel Density Estimation of standardized calibrated residuals
 76            - "scp2-bootstrap": Sequential split conformal prediction with independent bootstrap of standardized calibrated residuals
 77            - "scp2-block-bootstrap": Sequential split conformal prediction with basic block bootstrap of standardized calibrated residuals
 78
 79        block_size: int.
 80            size of block for 'type_pi' in ("block-bootstrap", "scp-block-bootstrap", "scp2-block-bootstrap").
 81            Default is round(3.15*(n_residuals^1/3))
 82
 83        replications: int.
 84            number of replications (if needed, for predictive simulation). Default is 'None'.
 85
 86        kernel: str.
 87            the kernel to use for residuals density estimation (used for predictive simulation). Currently, either 'gaussian' or 'tophat'.
 88
 89        agg: str.
 90            either "mean" or "median" for simulation of bootstrap aggregating
 91
 92        seed: int.
 93            reproducibility seed for nodes_sim=='uniform' or predictive simulation.
 94
 95        backend: str.
 96            "cpu" or "gpu" or "tpu".
 97
 98        verbose: int.
 99            0: not printing; 1: printing
100
101        show_progress: bool.
102            True: progress bar when fitting each series; False: no progress bar when fitting each series
103
104    Attributes:
105
106        fit_objs_: dict
107            objects adjusted to each individual time series
108
109        y_: {array-like}
110            DeepMTS responses (most recent observations first)
111
112        X_: {array-like}
113            DeepMTS lags
114
115        xreg_: {array-like}
116            external regressors
117
118        y_means_: dict
119            a dictionary of each series mean values
120
121        preds_: {array-like}
122            successive model predictions
123
124        preds_std_: {array-like}
125            standard deviation around the predictions
126
127        return_std_: boolean
128            return uncertainty or not (set in predict)
129
130        df_: data frame
131            the input data frame, in case a data.frame is provided to `fit`
132
133    Examples:
134
135    Example 1:
136
137        ```python
138        import nnetsauce as ns
139        import numpy as np
140        from sklearn import linear_model
141        np.random.seed(123)
142
143        M = np.random.rand(10, 3)
144        M[:,0] = 10*M[:,0]
145        M[:,2] = 25*M[:,2]
146        print(M)
147
148        # Adjust Bayesian Ridge
149        regr4 = linear_model.BayesianRidge()
150        obj_DeepMTS = ns.DeepMTS(regr4, lags = 1, n_hidden_features=5)
151        obj_DeepMTS.fit(M)
152        print(obj_DeepMTS.predict())
153
154        # with credible intervals
155        print(obj_DeepMTS.predict(return_std=True, level=80))
156
157        print(obj_DeepMTS.predict(return_std=True, level=95))
158        ```
159
160    Example 2:
161
162        ```python
163        import nnetsauce as ns
164        import numpy as np
165        from sklearn import linear_model
166
167        dataset = {
168        'date' : ['2001-01-01', '2002-01-01', '2003-01-01', '2004-01-01', '2005-01-01'],
169        'series1' : [34, 30, 35.6, 33.3, 38.1],
170        'series2' : [4, 5.5, 5.6, 6.3, 5.1],
171        'series3' : [100, 100.5, 100.6, 100.2, 100.1]}
172        df = pd.DataFrame(dataset).set_index('date')
173        print(df)
174
175        # Adjust Bayesian Ridge
176        regr5 = linear_model.BayesianRidge()
177        obj_DeepMTS = ns.DeepMTS(regr5, lags = 1, n_hidden_features=5)
178        obj_DeepMTS.fit(df)
179        print(obj_DeepMTS.predict())
180
181        # with credible intervals
182        print(obj_DeepMTS.predict(return_std=True, level=80))
183
184        print(obj_DeepMTS.predict(return_std=True, level=95))
185        ```
186
187    """
188
189    # construct the object -----
190
191    def __init__(
192        self,
193        obj,
194        n_layers=3,
195        n_hidden_features=5,
196        activation_name="relu",
197        a=0.01,
198        nodes_sim="sobol",
199        bias=True,
200        dropout=0,
201        direct_link=True,
202        n_clusters=2,
203        cluster_encode=True,
204        type_clust="kmeans",
205        type_scaling=("std", "std", "std"),
206        lags=1,
207        type_pi="kde",
208        block_size=None,
209        replications=None,
210        kernel=None,
211        agg="mean",
212        seed=123,
213        backend="cpu",
214        verbose=0,
215        show_progress=True,
216    ):
217        assert int(lags) == lags, "parameter 'lags' should be an integer"
218        assert n_layers >= 1, "must have n_layers >= 1"
219        self.n_layers = int(n_layers)
220
221        if self.n_layers > 1:
222
223            for _ in range(self.n_layers - 1):
224                obj = CustomRegressor(
225                    obj=deepcopy(obj),
226                    n_hidden_features=n_hidden_features,
227                    activation_name=activation_name,
228                    a=a,
229                    nodes_sim=nodes_sim,
230                    bias=bias,
231                    dropout=dropout,
232                    direct_link=direct_link,
233                    n_clusters=n_clusters,
234                    cluster_encode=cluster_encode,
235                    type_clust=type_clust,
236                    type_scaling=type_scaling,
237                    seed=seed,
238                    backend=backend,
239                )
240
241        self.obj = deepcopy(obj)
242        super().__init__(
243            obj=self.obj,
244            n_hidden_features=n_hidden_features,
245            activation_name=activation_name,
246            a=a,
247            nodes_sim=nodes_sim,
248            bias=bias,
249            dropout=dropout,
250            direct_link=direct_link,
251            n_clusters=n_clusters,
252            cluster_encode=cluster_encode,
253            type_clust=type_clust,
254            type_scaling=type_scaling,
255            lags=lags,
256            type_pi=type_pi,
257            block_size=block_size,
258            replications=replications,
259            kernel=kernel,
260            agg=agg,
261            seed=seed,
262            backend=backend,
263            verbose=verbose,
264            show_progress=show_progress,
265        )

Univariate and multivariate time series (DeepMTS) forecasting with Quasi-Randomized networks (Work in progress /!)

Parameters:

obj: object.
    any object containing a method fit (obj.fit()) and a method predict
    (obj.predict()).

n_layers: int.
    number of layers in the neural network.

n_hidden_features: int.
    number of nodes in the hidden layer.

activation_name: str.
    activation function: 'relu', 'tanh', 'sigmoid', 'prelu' or 'elu'.

a: float.
    hyperparameter for 'prelu' or 'elu' activation function.

nodes_sim: str.
    type of simulation for the nodes: 'sobol', 'hammersley', 'halton',
    'uniform'.

bias: boolean.
    indicates if the hidden layer contains a bias term (True) or not
    (False).

dropout: float.
    regularization parameter; (random) percentage of nodes dropped out
    of the training.

direct_link: boolean.
    indicates if the original predictors are included (True) in model's fitting or not (False).

n_clusters: int.
    number of clusters for 'kmeans' or 'gmm' clustering (could be 0: no clustering).

cluster_encode: bool.
    defines how the variable containing clusters is treated (default is one-hot)
    if `False`, then labels are used, without one-hot encoding.

type_clust: str.
    type of clustering method: currently k-means ('kmeans') or Gaussian
    Mixture Model ('gmm').

type_scaling: a tuple of 3 strings.
    scaling methods for inputs, hidden layer, and clustering respectively
    (and when relevant).
    Currently available: standardization ('std') or MinMax scaling ('minmax').

lags: int.
    number of lags used for each time series.

type_pi: str.
    type of prediction interval; currently:
    - "gaussian": simple, fast, but: assumes stationarity of Gaussian in-sample residuals and independence in the multivariate case
    - "kde": based on Kernel Density Estimation of in-sample residuals
    - "bootstrap": based on independent bootstrap of in-sample residuals
    - "block-bootstrap": based on basic block bootstrap of in-sample residuals
    - "scp-kde": Sequential split conformal prediction with Kernel Density Estimation of calibrated residuals
    - "scp-bootstrap": Sequential split conformal prediction with independent bootstrap of calibrated residuals
    - "scp-block-bootstrap": Sequential split conformal prediction with basic block bootstrap of calibrated residuals
    - "scp2-kde": Sequential split conformal prediction with Kernel Density Estimation of standardized calibrated residuals
    - "scp2-bootstrap": Sequential split conformal prediction with independent bootstrap of standardized calibrated residuals
    - "scp2-block-bootstrap": Sequential split conformal prediction with basic block bootstrap of standardized calibrated residuals

block_size: int.
    size of block for 'type_pi' in ("block-bootstrap", "scp-block-bootstrap", "scp2-block-bootstrap").
    Default is round(3.15*(n_residuals^1/3))

replications: int.
    number of replications (if needed, for predictive simulation). Default is 'None'.

kernel: str.
    the kernel to use for residuals density estimation (used for predictive simulation). Currently, either 'gaussian' or 'tophat'.

agg: str.
    either "mean" or "median" for simulation of bootstrap aggregating

seed: int.
    reproducibility seed for nodes_sim=='uniform' or predictive simulation.

backend: str.
    "cpu" or "gpu" or "tpu".

verbose: int.
    0: not printing; 1: printing

show_progress: bool.
    True: progress bar when fitting each series; False: no progress bar when fitting each series

Attributes:

fit_objs_: dict
    objects adjusted to each individual time series

y_: {array-like}
    DeepMTS responses (most recent observations first)

X_: {array-like}
    DeepMTS lags

xreg_: {array-like}
    external regressors

y_means_: dict
    a dictionary of each series mean values

preds_: {array-like}
    successive model predictions

preds_std_: {array-like}
    standard deviation around the predictions

return_std_: boolean
    return uncertainty or not (set in predict)

df_: data frame
    the input data frame, in case a data.frame is provided to `fit`

Examples:

Example 1:

import nnetsauce as ns
import numpy as np
from sklearn import linear_model
np.random.seed(123)

M = np.random.rand(10, 3)
M[:,0] = 10*M[:,0]
M[:,2] = 25*M[:,2]
print(M)

# Adjust Bayesian Ridge
regr4 = linear_model.BayesianRidge()
obj_DeepMTS = ns.DeepMTS(regr4, lags = 1, n_hidden_features=5)
obj_DeepMTS.fit(M)
print(obj_DeepMTS.predict())

# with credible intervals
print(obj_DeepMTS.predict(return_std=True, level=80))

print(obj_DeepMTS.predict(return_std=True, level=95))

Example 2:

import nnetsauce as ns
import numpy as np
from sklearn import linear_model

dataset = {
'date' : ['2001-01-01', '2002-01-01', '2003-01-01', '2004-01-01', '2005-01-01'],
'series1' : [34, 30, 35.6, 33.3, 38.1],
'series2' : [4, 5.5, 5.6, 6.3, 5.1],
'series3' : [100, 100.5, 100.6, 100.2, 100.1]}
df = pd.DataFrame(dataset).set_index('date')
print(df)

# Adjust Bayesian Ridge
regr5 = linear_model.BayesianRidge()
obj_DeepMTS = ns.DeepMTS(regr5, lags = 1, n_hidden_features=5)
obj_DeepMTS.fit(df)
print(obj_DeepMTS.predict())

# with credible intervals
print(obj_DeepMTS.predict(return_std=True, level=80))

print(obj_DeepMTS.predict(return_std=True, level=95))
class Downloader:
 6class Downloader:
 7    """Download datasets from data sources (R-universe for now)"""
 8
 9    def __init__(self):
10        self.pkgname = None
11        self.dataset = None
12        self.source = None
13        self.url = None
14        self.request = None
15
16    def download(
17        self,
18        pkgname="MASS",
19        dataset="Boston",
20        source="https://cran.r-universe.dev/",
21        **kwargs
22    ):
23        """Download datasets from data sources (R-universe for now)
24
25        Examples:
26
27        ```python
28        import nnetsauce as ns
29
30        downloader = ns.Downloader()
31        df = downloader.download(pkgname="MASS", dataset="Boston")
32        ```
33
34        """
35        self.pkgname = pkgname
36        self.dataset = dataset
37        self.source = source
38        self.url = source + pkgname + "/data/" + dataset + "/json"
39        self.request = requests.get(self.url)
40        return pd.DataFrame(self.request.json(), **kwargs)

Download datasets from data sources (R-universe for now)

def download( self, pkgname='MASS', dataset='Boston', source='https://cran.r-universe.dev/', **kwargs):
16    def download(
17        self,
18        pkgname="MASS",
19        dataset="Boston",
20        source="https://cran.r-universe.dev/",
21        **kwargs
22    ):
23        """Download datasets from data sources (R-universe for now)
24
25        Examples:
26
27        ```python
28        import nnetsauce as ns
29
30        downloader = ns.Downloader()
31        df = downloader.download(pkgname="MASS", dataset="Boston")
32        ```
33
34        """
35        self.pkgname = pkgname
36        self.dataset = dataset
37        self.source = source
38        self.url = source + pkgname + "/data/" + dataset + "/json"
39        self.request = requests.get(self.url)
40        return pd.DataFrame(self.request.json(), **kwargs)

Download datasets from data sources (R-universe for now)

Examples:

import nnetsauce as ns

downloader = ns.Downloader()
df = downloader.download(pkgname="MASS", dataset="Boston")
class GLMClassifier(nnetsauce.glm.glm.GLM, sklearn.base.ClassifierMixin):
 16class GLMClassifier(GLM, ClassifierMixin):
 17    """Generalized 'linear' models using quasi-randomized networks (classification)
 18
 19    Parameters:
 20
 21        n_hidden_features: int
 22            number of nodes in the hidden layer
 23
 24        lambda1: float
 25            regularization parameter for GLM coefficients on original features
 26
 27        alpha1: float
 28            controls compromize between l1 and l2 norm of GLM coefficients on original features
 29
 30        lambda2: float
 31            regularization parameter for GLM coefficients on nonlinear features
 32
 33        alpha2: float
 34            controls compromize between l1 and l2 norm of GLM coefficients on nonlinear features
 35
 36        activation_name: str
 37            activation function: 'relu', 'tanh', 'sigmoid', 'prelu' or 'elu'
 38
 39        a: float
 40            hyperparameter for 'prelu' or 'elu' activation function
 41
 42        nodes_sim: str
 43            type of simulation for the nodes: 'sobol', 'hammersley', 'halton',
 44            'uniform'
 45
 46        bias: boolean
 47            indicates if the hidden layer contains a bias term (True) or not
 48            (False)
 49
 50        dropout: float
 51            regularization parameter; (random) percentage of nodes dropped out
 52            of the training
 53
 54        direct_link: boolean
 55            indicates if the original predictors are included (True) in model's
 56            fitting or not (False)
 57
 58        n_clusters: int
 59            number of clusters for 'kmeans' or 'gmm' clustering (could be 0:
 60                no clustering)
 61
 62        cluster_encode: bool
 63            defines how the variable containing clusters is treated (default is one-hot)
 64            if `False`, then labels are used, without one-hot encoding
 65
 66        type_clust: str
 67            type of clustering method: currently k-means ('kmeans') or Gaussian
 68            Mixture Model ('gmm')
 69
 70        type_scaling: a tuple of 3 strings
 71            scaling methods for inputs, hidden layer, and clustering respectively
 72            (and when relevant).
 73            Currently available: standardization ('std') or MinMax scaling ('minmax')
 74
 75        optimizer: object
 76            optimizer, from class nnetsauce.Optimizer
 77
 78        seed: int
 79            reproducibility seed for nodes_sim=='uniform'
 80
 81    Attributes:
 82
 83        beta_: vector
 84            regression coefficients
 85
 86    Examples:
 87
 88    See [https://github.com/Techtonique/nnetsauce/blob/master/examples/glm_classification.py](https://github.com/Techtonique/nnetsauce/blob/master/examples/glm_classification.py)
 89
 90    """
 91
 92    # construct the object -----
 93
 94    def __init__(
 95        self,
 96        n_hidden_features=5,
 97        lambda1=0.01,
 98        alpha1=0.5,
 99        lambda2=0.01,
100        alpha2=0.5,
101        family="expit",
102        activation_name="relu",
103        a=0.01,
104        nodes_sim="sobol",
105        bias=True,
106        dropout=0,
107        direct_link=True,
108        n_clusters=2,
109        cluster_encode=True,
110        type_clust="kmeans",
111        type_scaling=("std", "std", "std"),
112        optimizer=Optimizer(),
113        seed=123,
114    ):
115        super().__init__(
116            n_hidden_features=n_hidden_features,
117            lambda1=lambda1,
118            alpha1=alpha1,
119            lambda2=lambda2,
120            alpha2=alpha2,
121            activation_name=activation_name,
122            a=a,
123            nodes_sim=nodes_sim,
124            bias=bias,
125            dropout=dropout,
126            direct_link=direct_link,
127            n_clusters=n_clusters,
128            cluster_encode=cluster_encode,
129            type_clust=type_clust,
130            type_scaling=type_scaling,
131            optimizer=optimizer,
132            seed=seed,
133        )
134
135        self.family = family
136
137    def logit_loss(self, Y, row_index, XB):
138        self.n_classes = Y.shape[1]  # len(np.unique(y))
139        # Y = mo.one_hot_encode2(y, self.n_classes)
140        # Y = self.optimizer.one_hot_encode(y, self.n_classes)
141
142        # max_double = 709.0 # only if softmax
143        # XB[XB > max_double] = max_double
144        XB[XB > 709.0] = 709.0
145
146        if row_index is None:
147            return -np.mean(np.sum(Y * XB, axis=1) - logsumexp(XB))
148
149        return -np.mean(np.sum(Y[row_index, :] * XB, axis=1) - logsumexp(XB))
150
151    def expit_erf_loss(self, Y, row_index, XB):
152        # self.n_classes = len(np.unique(y))
153        # Y = mo.one_hot_encode2(y, self.n_classes)
154        # Y = self.optimizer.one_hot_encode(y, self.n_classes)
155        self.n_classes = Y.shape[1]
156
157        if row_index is None:
158            return -np.mean(np.sum(Y * XB, axis=1) - logsumexp(XB))
159
160        return -np.mean(np.sum(Y[row_index, :] * XB, axis=1) - logsumexp(XB))
161
162    def loss_func(
163        self,
164        beta,
165        group_index,
166        X,
167        Y,
168        y,
169        row_index=None,
170        type_loss="logit",
171        **kwargs
172    ):
173        res = {
174            "logit": self.logit_loss,
175            "expit": self.expit_erf_loss,
176            "erf": self.expit_erf_loss,
177        }
178
179        if row_index is None:
180            row_index = range(len(y))
181            XB = self.compute_XB(
182                X,
183                beta=np.reshape(beta, (X.shape[1], self.n_classes), order="F"),
184            )
185
186            return res[type_loss](Y, row_index, XB) + self.compute_penalty(
187                group_index=group_index, beta=beta
188            )
189
190        XB = self.compute_XB(
191            X,
192            beta=np.reshape(beta, (X.shape[1], self.n_classes), order="F"),
193            row_index=row_index,
194        )
195
196        return res[type_loss](Y, row_index, XB) + self.compute_penalty(
197            group_index=group_index, beta=beta
198        )
199
200    def fit(self, X, y, **kwargs):
201        """Fit GLM model to training data (X, y).
202
203        Args:
204
205            X: {array-like}, shape = [n_samples, n_features]
206                Training vectors, where n_samples is the number
207                of samples and n_features is the number of features.
208
209            y: array-like, shape = [n_samples]
210                Target values.
211
212            **kwargs: additional parameters to be passed to
213                    self.cook_training_set or self.obj.fit
214
215        Returns:
216
217            self: object
218
219        """
220
221        assert mx.is_factor(
222            y
223        ), "y must contain only integers"  # change is_factor and subsampling everywhere
224
225        self.classes_ = np.unique(y)  # for compatibility with sklearn
226        self.n_classes_ = len(self.classes_)  # for compatibility with sklearn
227
228        self.beta_ = None
229
230        n, p = X.shape
231
232        self.group_index = n * X.shape[1]
233
234        self.n_classes = len(np.unique(y))
235
236        output_y, scaled_Z = self.cook_training_set(y=y, X=X, **kwargs)
237
238        # Y = mo.one_hot_encode2(output_y, self.n_classes)
239        Y = self.optimizer.one_hot_encode(output_y, self.n_classes)
240
241        # initialization
242        beta_ = np.linalg.lstsq(scaled_Z, Y, rcond=None)[0]
243
244        # optimization
245        # fit(self, loss_func, response, x0, **kwargs):
246        # loss_func(self, beta, group_index, X, y,
247        #          row_index=None, type_loss="gaussian",
248        #          **kwargs)
249        self.optimizer.fit(
250            self.loss_func,
251            response=y,
252            x0=beta_.flatten(order="F"),
253            group_index=self.group_index,
254            X=scaled_Z,
255            Y=Y,
256            y=y,
257            type_loss=self.family,
258        )
259
260        self.beta_ = self.optimizer.results[0]
261        self.classes_ = np.unique(y)
262
263        return self
264
265    def predict(self, X, **kwargs):
266        """Predict test data X.
267
268        Args:
269
270            X: {array-like}, shape = [n_samples, n_features]
271                Training vectors, where n_samples is the number
272                of samples and n_features is the number of features.
273
274            **kwargs: additional parameters to be passed to
275                    self.cook_test_set
276
277        Returns:
278
279            model predictions: {array-like}
280
281        """
282
283        return np.argmax(self.predict_proba(X, **kwargs), axis=1)
284
285    def predict_proba(self, X, **kwargs):
286        """Predict probabilities for test data X.
287
288        Args:
289
290            X: {array-like}, shape = [n_samples, n_features]
291                Training vectors, where n_samples is the number
292                of samples and n_features is the number of features.
293
294            **kwargs: additional parameters to be passed to
295                    self.cook_test_set
296
297        Returns:
298
299            probability estimates for test data: {array-like}
300
301        """
302        if len(X.shape) == 1:
303            n_features = X.shape[0]
304            new_X = mo.rbind(
305                X.reshape(1, n_features),
306                np.ones(n_features).reshape(1, n_features),
307            )
308
309            Z = self.cook_test_set(new_X, **kwargs)
310
311        else:
312            Z = self.cook_test_set(X, **kwargs)
313
314        ZB = mo.safe_sparse_dot(
315            Z,
316            self.beta_.reshape(
317                self.n_classes,
318                X.shape[1] + self.n_hidden_features + self.n_clusters,
319            ).T,
320        )
321
322        if self.family == "logit":
323            exp_ZB = np.exp(ZB)
324
325            return exp_ZB / exp_ZB.sum(axis=1)[:, None]
326
327        if self.family == "expit":
328            exp_ZB = expit(ZB)
329
330            return exp_ZB / exp_ZB.sum(axis=1)[:, None]
331
332        if self.family == "erf":
333            exp_ZB = 0.5 * (1 + erf(ZB))
334
335            return exp_ZB / exp_ZB.sum(axis=1)[:, None]
336
337    def score(self, X, y, scoring=None):
338        """Scoring function for classification.
339
340        Args:
341
342            X: {array-like}, shape = [n_samples, n_features]
343                Training vectors, where n_samples is the number
344                of samples and n_features is the number of features.
345
346            y: array-like, shape = [n_samples]
347                Target values.
348
349            scoring: str
350                scoring method (default is accuracy)
351
352        Returns:
353
354            score: float
355        """
356
357        if scoring is None:
358            scoring = "accuracy"
359
360        if scoring == "accuracy":
361            return skm2.accuracy_score(y, self.predict(X))
362
363        if scoring == "f1":
364            return skm2.f1_score(y, self.predict(X))
365
366        if scoring == "precision":
367            return skm2.precision_score(y, self.predict(X))
368
369        if scoring == "recall":
370            return skm2.recall_score(y, self.predict(X))
371
372        if scoring == "roc_auc":
373            return skm2.roc_auc_score(y, self.predict(X))
374
375        if scoring == "log_loss":
376            return skm2.log_loss(y, self.predict_proba(X))
377
378        if scoring == "balanced_accuracy":
379            return skm2.balanced_accuracy_score(y, self.predict(X))
380
381        if scoring == "average_precision":
382            return skm2.average_precision_score(y, self.predict(X))
383
384        if scoring == "neg_brier_score":
385            return -skm2.brier_score_loss(y, self.predict_proba(X))
386
387        if scoring == "neg_log_loss":
388            return -skm2.log_loss(y, self.predict_proba(X))

Generalized 'linear' models using quasi-randomized networks (classification)

Parameters:

n_hidden_features: int
    number of nodes in the hidden layer

lambda1: float
    regularization parameter for GLM coefficients on original features

alpha1: float
    controls compromize between l1 and l2 norm of GLM coefficients on original features

lambda2: float
    regularization parameter for GLM coefficients on nonlinear features

alpha2: float
    controls compromize between l1 and l2 norm of GLM coefficients on nonlinear features

activation_name: str
    activation function: 'relu', 'tanh', 'sigmoid', 'prelu' or 'elu'

a: float
    hyperparameter for 'prelu' or 'elu' activation function

nodes_sim: str
    type of simulation for the nodes: 'sobol', 'hammersley', 'halton',
    'uniform'

bias: boolean
    indicates if the hidden layer contains a bias term (True) or not
    (False)

dropout: float
    regularization parameter; (random) percentage of nodes dropped out
    of the training

direct_link: boolean
    indicates if the original predictors are included (True) in model's
    fitting or not (False)

n_clusters: int
    number of clusters for 'kmeans' or 'gmm' clustering (could be 0:
        no clustering)

cluster_encode: bool
    defines how the variable containing clusters is treated (default is one-hot)
    if `False`, then labels are used, without one-hot encoding

type_clust: str
    type of clustering method: currently k-means ('kmeans') or Gaussian
    Mixture Model ('gmm')

type_scaling: a tuple of 3 strings
    scaling methods for inputs, hidden layer, and clustering respectively
    (and when relevant).
    Currently available: standardization ('std') or MinMax scaling ('minmax')

optimizer: object
    optimizer, from class Optimizer

seed: int
    reproducibility seed for nodes_sim=='uniform'

Attributes:

beta_: vector
    regression coefficients

Examples:

See https://github.com/Techtonique/nnetsauce/blob/master/examples/glm_classification.py

def fit(self, X, y, **kwargs):
200    def fit(self, X, y, **kwargs):
201        """Fit GLM model to training data (X, y).
202
203        Args:
204
205            X: {array-like}, shape = [n_samples, n_features]
206                Training vectors, where n_samples is the number
207                of samples and n_features is the number of features.
208
209            y: array-like, shape = [n_samples]
210                Target values.
211
212            **kwargs: additional parameters to be passed to
213                    self.cook_training_set or self.obj.fit
214
215        Returns:
216
217            self: object
218
219        """
220
221        assert mx.is_factor(
222            y
223        ), "y must contain only integers"  # change is_factor and subsampling everywhere
224
225        self.classes_ = np.unique(y)  # for compatibility with sklearn
226        self.n_classes_ = len(self.classes_)  # for compatibility with sklearn
227
228        self.beta_ = None
229
230        n, p = X.shape
231
232        self.group_index = n * X.shape[1]
233
234        self.n_classes = len(np.unique(y))
235
236        output_y, scaled_Z = self.cook_training_set(y=y, X=X, **kwargs)
237
238        # Y = mo.one_hot_encode2(output_y, self.n_classes)
239        Y = self.optimizer.one_hot_encode(output_y, self.n_classes)
240
241        # initialization
242        beta_ = np.linalg.lstsq(scaled_Z, Y, rcond=None)[0]
243
244        # optimization
245        # fit(self, loss_func, response, x0, **kwargs):
246        # loss_func(self, beta, group_index, X, y,
247        #          row_index=None, type_loss="gaussian",
248        #          **kwargs)
249        self.optimizer.fit(
250            self.loss_func,
251            response=y,
252            x0=beta_.flatten(order="F"),
253            group_index=self.group_index,
254            X=scaled_Z,
255            Y=Y,
256            y=y,
257            type_loss=self.family,
258        )
259
260        self.beta_ = self.optimizer.results[0]
261        self.classes_ = np.unique(y)
262
263        return self

Fit GLM model to training data (X, y).

Args:

X: {array-like}, shape = [n_samples, n_features]
    Training vectors, where n_samples is the number
    of samples and n_features is the number of features.

y: array-like, shape = [n_samples]
    Target values.

**kwargs: additional parameters to be passed to
        self.cook_training_set or self.obj.fit

Returns:

self: object
def predict(self, X, **kwargs):
265    def predict(self, X, **kwargs):
266        """Predict test data X.
267
268        Args:
269
270            X: {array-like}, shape = [n_samples, n_features]
271                Training vectors, where n_samples is the number
272                of samples and n_features is the number of features.
273
274            **kwargs: additional parameters to be passed to
275                    self.cook_test_set
276
277        Returns:
278
279            model predictions: {array-like}
280
281        """
282
283        return np.argmax(self.predict_proba(X, **kwargs), axis=1)

Predict test data X.

Args:

X: {array-like}, shape = [n_samples, n_features]
    Training vectors, where n_samples is the number
    of samples and n_features is the number of features.

**kwargs: additional parameters to be passed to
        self.cook_test_set

Returns:

model predictions: {array-like}
def predict_proba(self, X, **kwargs):
285    def predict_proba(self, X, **kwargs):
286        """Predict probabilities for test data X.
287
288        Args:
289
290            X: {array-like}, shape = [n_samples, n_features]
291                Training vectors, where n_samples is the number
292                of samples and n_features is the number of features.
293
294            **kwargs: additional parameters to be passed to
295                    self.cook_test_set
296
297        Returns:
298
299            probability estimates for test data: {array-like}
300
301        """
302        if len(X.shape) == 1:
303            n_features = X.shape[0]
304            new_X = mo.rbind(
305                X.reshape(1, n_features),
306                np.ones(n_features).reshape(1, n_features),
307            )
308
309            Z = self.cook_test_set(new_X, **kwargs)
310
311        else:
312            Z = self.cook_test_set(X, **kwargs)
313
314        ZB = mo.safe_sparse_dot(
315            Z,
316            self.beta_.reshape(
317                self.n_classes,
318                X.shape[1] + self.n_hidden_features + self.n_clusters,
319            ).T,
320        )
321
322        if self.family == "logit":
323            exp_ZB = np.exp(ZB)
324
325            return exp_ZB / exp_ZB.sum(axis=1)[:, None]
326
327        if self.family == "expit":
328            exp_ZB = expit(ZB)
329
330            return exp_ZB / exp_ZB.sum(axis=1)[:, None]
331
332        if self.family == "erf":
333            exp_ZB = 0.5 * (1 + erf(ZB))
334
335            return exp_ZB / exp_ZB.sum(axis=1)[:, None]

Predict probabilities for test data X.

Args:

X: {array-like}, shape = [n_samples, n_features]
    Training vectors, where n_samples is the number
    of samples and n_features is the number of features.

**kwargs: additional parameters to be passed to
        self.cook_test_set

Returns:

probability estimates for test data: {array-like}
def score(self, X, y, scoring=None):
337    def score(self, X, y, scoring=None):
338        """Scoring function for classification.
339
340        Args:
341
342            X: {array-like}, shape = [n_samples, n_features]
343                Training vectors, where n_samples is the number
344                of samples and n_features is the number of features.
345
346            y: array-like, shape = [n_samples]
347                Target values.
348
349            scoring: str
350                scoring method (default is accuracy)
351
352        Returns:
353
354            score: float
355        """
356
357        if scoring is None:
358            scoring = "accuracy"
359
360        if scoring == "accuracy":
361            return skm2.accuracy_score(y, self.predict(X))
362
363        if scoring == "f1":
364            return skm2.f1_score(y, self.predict(X))
365
366        if scoring == "precision":
367            return skm2.precision_score(y, self.predict(X))
368
369        if scoring == "recall":
370            return skm2.recall_score(y, self.predict(X))
371
372        if scoring == "roc_auc":
373            return skm2.roc_auc_score(y, self.predict(X))
374
375        if scoring == "log_loss":
376            return skm2.log_loss(y, self.predict_proba(X))
377
378        if scoring == "balanced_accuracy":
379            return skm2.balanced_accuracy_score(y, self.predict(X))
380
381        if scoring == "average_precision":
382            return skm2.average_precision_score(y, self.predict(X))
383
384        if scoring == "neg_brier_score":
385            return -skm2.brier_score_loss(y, self.predict_proba(X))
386
387        if scoring == "neg_log_loss":
388            return -skm2.log_loss(y, self.predict_proba(X))

Scoring function for classification.

Args:

X: {array-like}, shape = [n_samples, n_features]
    Training vectors, where n_samples is the number
    of samples and n_features is the number of features.

y: array-like, shape = [n_samples]
    Target values.

scoring: str
    scoring method (default is accuracy)

Returns:

score: float
class GLMRegressor(nnetsauce.glm.glm.GLM, sklearn.base.RegressorMixin):
 14class GLMRegressor(GLM, RegressorMixin):
 15    """Generalized 'linear' models using quasi-randomized networks (regression)
 16
 17    Attributes:
 18
 19        n_hidden_features: int
 20            number of nodes in the hidden layer
 21
 22        lambda1: float
 23            regularization parameter for GLM coefficients on original features
 24
 25        alpha1: float
 26            controls compromize between l1 and l2 norm of GLM coefficients on original features
 27
 28        lambda2: float
 29            regularization parameter for GLM coefficients on nonlinear features
 30
 31        alpha2: float
 32            controls compromize between l1 and l2 norm of GLM coefficients on nonlinear features
 33
 34        family: str
 35            "gaussian", "laplace" or "poisson" (for now)
 36
 37        activation_name: str
 38            activation function: 'relu', 'tanh', 'sigmoid', 'prelu' or 'elu'
 39
 40        a: float
 41            hyperparameter for 'prelu' or 'elu' activation function
 42
 43        nodes_sim: str
 44            type of simulation for the nodes: 'sobol', 'hammersley', 'halton',
 45            'uniform'
 46
 47        bias: boolean
 48            indicates if the hidden layer contains a bias term (True) or not
 49            (False)
 50
 51        dropout: float
 52            regularization parameter; (random) percentage of nodes dropped out
 53            of the training
 54
 55        direct_link: boolean
 56            indicates if the original predictors are included (True) in model's
 57            fitting or not (False)
 58
 59        n_clusters: int
 60            number of clusters for 'kmeans' or 'gmm' clustering (could be 0:
 61                no clustering)
 62
 63        cluster_encode: bool
 64            defines how the variable containing clusters is treated (default is one-hot)
 65            if `False`, then labels are used, without one-hot encoding
 66
 67        type_clust: str
 68            type of clustering method: currently k-means ('kmeans') or Gaussian
 69            Mixture Model ('gmm')
 70
 71        type_scaling: a tuple of 3 strings
 72            scaling methods for inputs, hidden layer, and clustering respectively
 73            (and when relevant).
 74            Currently available: standardization ('std') or MinMax scaling ('minmax')
 75
 76        optimizer: object
 77            optimizer, from class nnetsauce.utils.Optimizer
 78
 79        seed: int
 80            reproducibility seed for nodes_sim=='uniform'
 81
 82    Attributes:
 83
 84        beta_: vector
 85            regression coefficients
 86
 87    Examples:
 88
 89    See [https://github.com/Techtonique/nnetsauce/blob/master/examples/glm_regression.py](https://github.com/Techtonique/nnetsauce/blob/master/examples/glm_regression.py)
 90
 91    """
 92
 93    # construct the object -----
 94
 95    def __init__(
 96        self,
 97        n_hidden_features=5,
 98        lambda1=0.01,
 99        alpha1=0.5,
100        lambda2=0.01,
101        alpha2=0.5,
102        family="gaussian",
103        activation_name="relu",
104        a=0.01,
105        nodes_sim="sobol",
106        bias=True,
107        dropout=0,
108        direct_link=True,
109        n_clusters=2,
110        cluster_encode=True,
111        type_clust="kmeans",
112        type_scaling=("std", "std", "std"),
113        optimizer=Optimizer(),
114        seed=123,
115    ):
116        super().__init__(
117            n_hidden_features=n_hidden_features,
118            lambda1=lambda1,
119            alpha1=alpha1,
120            lambda2=lambda2,
121            alpha2=alpha2,
122            activation_name=activation_name,
123            a=a,
124            nodes_sim=nodes_sim,
125            bias=bias,
126            dropout=dropout,
127            direct_link=direct_link,
128            n_clusters=n_clusters,
129            cluster_encode=cluster_encode,
130            type_clust=type_clust,
131            type_scaling=type_scaling,
132            optimizer=optimizer,
133            seed=seed,
134        )
135
136        self.family = family
137
138    def gaussian_loss(self, y, row_index, XB):
139        return 0.5 * np.mean(np.square(y[row_index] - XB))
140
141    def laplace_loss(self, y, row_index, XB):
142        return 0.5 * np.mean(np.abs(y[row_index] - XB))
143
144    def poisson_loss(self, y, row_index, XB):
145        return -np.mean(y[row_index] * XB - np.exp(XB))
146
147    def loss_func(
148        self,
149        beta,
150        group_index,
151        X,
152        y,
153        row_index=None,
154        type_loss="gaussian",
155        **kwargs
156    ):
157        res = {
158            "gaussian": self.gaussian_loss,
159            "laplace": self.laplace_loss,
160            "poisson": self.poisson_loss,
161        }
162
163        if row_index is None:
164            row_index = range(len(y))
165            XB = self.compute_XB(X, beta=beta)
166
167            return res[type_loss](y, row_index, XB) + self.compute_penalty(
168                group_index=group_index, beta=beta
169            )
170
171        XB = self.compute_XB(X, beta=beta, row_index=row_index)
172
173        return res[type_loss](y, row_index, XB) + self.compute_penalty(
174            group_index=group_index, beta=beta
175        )
176
177    def fit(self, X, y, **kwargs):
178        """Fit GLM model to training data (X, y).
179
180        Args:
181
182            X: {array-like}, shape = [n_samples, n_features]
183                Training vectors, where n_samples is the number
184                of samples and n_features is the number of features.
185
186            y: array-like, shape = [n_samples]
187                Target values.
188
189            **kwargs: additional parameters to be passed to
190                    self.cook_training_set or self.obj.fit
191
192        Returns:
193
194            self: object
195
196        """
197
198        self.beta_ = None
199
200        self.n_iter = 0
201
202        n, self.group_index = X.shape
203
204        centered_y, scaled_Z = self.cook_training_set(y=y, X=X, **kwargs)
205
206        n_Z = scaled_Z.shape[0]
207
208        # initialization
209        beta_ = np.linalg.lstsq(scaled_Z, centered_y, rcond=None)[0]
210
211        # optimization
212        # fit(self, loss_func, response, x0, **kwargs):
213        # loss_func(self, beta, group_index, X, y,
214        #          row_index=None, type_loss="gaussian",
215        #          **kwargs)
216        self.optimizer.fit(
217            self.loss_func,
218            response=centered_y,
219            x0=beta_,
220            group_index=self.group_index,
221            X=scaled_Z,
222            y=centered_y,
223            type_loss=self.family,
224            **kwargs
225        )
226
227        self.beta_ = self.optimizer.results[0]
228
229        return self
230
231    def predict(self, X, **kwargs):
232        """Predict test data X.
233
234        Args:
235
236            X: {array-like}, shape = [n_samples, n_features]
237                Training vectors, where n_samples is the number
238                of samples and n_features is the number of features.
239
240            **kwargs: additional parameters to be passed to
241                    self.cook_test_set
242
243        Returns:
244
245            model predictions: {array-like}
246
247        """
248
249        if len(X.shape) == 1:
250            n_features = X.shape[0]
251            new_X = mo.rbind(
252                X.reshape(1, n_features),
253                np.ones(n_features).reshape(1, n_features),
254            )
255
256            return (
257                self.y_mean_
258                + np.dot(self.cook_test_set(new_X, **kwargs), self.beta_)
259            )[0]
260
261        return self.y_mean_ + np.dot(
262            self.cook_test_set(X, **kwargs), self.beta_
263        )
264
265    def score(self, X, y, scoring=None):
266        """Compute the score of the model.
267
268        Parameters:
269
270            X: {array-like}, shape = [n_samples, n_features]
271                Training vectors, where n_samples is the number
272                of samples and n_features is the number of features.
273
274            y: array-like, shape = [n_samples]
275                Target values.
276
277            scoring: str
278                scoring method
279
280        Returns:
281
282            score: float
283
284        """
285
286        if scoring is None:
287            return np.sqrt(np.mean((self.predict(X) - y) ** 2))
288
289        return skm2.get_scorer(scoring)(self, X, y)

Generalized 'linear' models using quasi-randomized networks (regression)

Attributes:

n_hidden_features: int
    number of nodes in the hidden layer

lambda1: float
    regularization parameter for GLM coefficients on original features

alpha1: float
    controls compromize between l1 and l2 norm of GLM coefficients on original features

lambda2: float
    regularization parameter for GLM coefficients on nonlinear features

alpha2: float
    controls compromize between l1 and l2 norm of GLM coefficients on nonlinear features

family: str
    "gaussian", "laplace" or "poisson" (for now)

activation_name: str
    activation function: 'relu', 'tanh', 'sigmoid', 'prelu' or 'elu'

a: float
    hyperparameter for 'prelu' or 'elu' activation function

nodes_sim: str
    type of simulation for the nodes: 'sobol', 'hammersley', 'halton',
    'uniform'

bias: boolean
    indicates if the hidden layer contains a bias term (True) or not
    (False)

dropout: float
    regularization parameter; (random) percentage of nodes dropped out
    of the training

direct_link: boolean
    indicates if the original predictors are included (True) in model's
    fitting or not (False)

n_clusters: int
    number of clusters for 'kmeans' or 'gmm' clustering (could be 0:
        no clustering)

cluster_encode: bool
    defines how the variable containing clusters is treated (default is one-hot)
    if `False`, then labels are used, without one-hot encoding

type_clust: str
    type of clustering method: currently k-means ('kmeans') or Gaussian
    Mixture Model ('gmm')

type_scaling: a tuple of 3 strings
    scaling methods for inputs, hidden layer, and clustering respectively
    (and when relevant).
    Currently available: standardization ('std') or MinMax scaling ('minmax')

optimizer: object
    optimizer, from class Optimizer

seed: int
    reproducibility seed for nodes_sim=='uniform'

Attributes:

beta_: vector
    regression coefficients

Examples:

See https://github.com/Techtonique/nnetsauce/blob/master/examples/glm_regression.py

def fit(self, X, y, **kwargs):
177    def fit(self, X, y, **kwargs):
178        """Fit GLM model to training data (X, y).
179
180        Args:
181
182            X: {array-like}, shape = [n_samples, n_features]
183                Training vectors, where n_samples is the number
184                of samples and n_features is the number of features.
185
186            y: array-like, shape = [n_samples]
187                Target values.
188
189            **kwargs: additional parameters to be passed to
190                    self.cook_training_set or self.obj.fit
191
192        Returns:
193
194            self: object
195
196        """
197
198        self.beta_ = None
199
200        self.n_iter = 0
201
202        n, self.group_index = X.shape
203
204        centered_y, scaled_Z = self.cook_training_set(y=y, X=X, **kwargs)
205
206        n_Z = scaled_Z.shape[0]
207
208        # initialization
209        beta_ = np.linalg.lstsq(scaled_Z, centered_y, rcond=None)[0]
210
211        # optimization
212        # fit(self, loss_func, response, x0, **kwargs):
213        # loss_func(self, beta, group_index, X, y,
214        #          row_index=None, type_loss="gaussian",
215        #          **kwargs)
216        self.optimizer.fit(
217            self.loss_func,
218            response=centered_y,
219            x0=beta_,
220            group_index=self.group_index,
221            X=scaled_Z,
222            y=centered_y,
223            type_loss=self.family,
224            **kwargs
225        )
226
227        self.beta_ = self.optimizer.results[0]
228
229        return self

Fit GLM model to training data (X, y).

Args:

X: {array-like}, shape = [n_samples, n_features]
    Training vectors, where n_samples is the number
    of samples and n_features is the number of features.

y: array-like, shape = [n_samples]
    Target values.

**kwargs: additional parameters to be passed to
        self.cook_training_set or self.obj.fit

Returns:

self: object
def predict(self, X, **kwargs):
231    def predict(self, X, **kwargs):
232        """Predict test data X.
233
234        Args:
235
236            X: {array-like}, shape = [n_samples, n_features]
237                Training vectors, where n_samples is the number
238                of samples and n_features is the number of features.
239
240            **kwargs: additional parameters to be passed to
241                    self.cook_test_set
242
243        Returns:
244
245            model predictions: {array-like}
246
247        """
248
249        if len(X.shape) == 1:
250            n_features = X.shape[0]
251            new_X = mo.rbind(
252                X.reshape(1, n_features),
253                np.ones(n_features).reshape(1, n_features),
254            )
255
256            return (
257                self.y_mean_
258                + np.dot(self.cook_test_set(new_X, **kwargs), self.beta_)
259            )[0]
260
261        return self.y_mean_ + np.dot(
262            self.cook_test_set(X, **kwargs), self.beta_
263        )

Predict test data X.

Args:

X: {array-like}, shape = [n_samples, n_features]
    Training vectors, where n_samples is the number
    of samples and n_features is the number of features.

**kwargs: additional parameters to be passed to
        self.cook_test_set

Returns:

model predictions: {array-like}
def score(self, X, y, scoring=None):
265    def score(self, X, y, scoring=None):
266        """Compute the score of the model.
267
268        Parameters:
269
270            X: {array-like}, shape = [n_samples, n_features]
271                Training vectors, where n_samples is the number
272                of samples and n_features is the number of features.
273
274            y: array-like, shape = [n_samples]
275                Target values.
276
277            scoring: str
278                scoring method
279
280        Returns:
281
282            score: float
283
284        """
285
286        if scoring is None:
287            return np.sqrt(np.mean((self.predict(X) - y) ** 2))
288
289        return skm2.get_scorer(scoring)(self, X, y)

Compute the score of the model.

Parameters:

X: {array-like}, shape = [n_samples, n_features]
    Training vectors, where n_samples is the number
    of samples and n_features is the number of features.

y: array-like, shape = [n_samples]
    Target values.

scoring: str
    scoring method

Returns:

score: float
class LazyClassifier(nnetsauce.LazyDeepClassifier):
755class LazyClassifier(LazyDeepClassifier):
756    """
757        Fitting -- almost -- all the classification algorithms with
758        nnetsauce's CustomClassifier and returning their scores (no layers).
759
760    Parameters:
761
762        verbose: int, optional (default=0)
763            Any positive number for verbosity.
764
765        ignore_warnings: bool, optional (default=True)
766            When set to True, the warning related to algorigms that are not able to run are ignored.
767
768        custom_metric: function, optional (default=None)
769            When function is provided, models are evaluated based on the custom evaluation metric provided.
770
771        predictions: bool, optional (default=False)
772            When set to True, the predictions of all the models models are returned as dataframe.
773
774        sort_by: string, optional (default='Accuracy')
775            Sort models by a metric. Available options are 'Accuracy', 'Balanced Accuracy', 'ROC AUC', 'F1 Score'
776            or a custom metric identified by its name and provided by custom_metric.
777
778        random_state: int, optional (default=42)
779            Reproducibiility seed.
780
781        estimators: list, optional (default='all')
782            list of Estimators names or just 'all' (default='all')
783
784        preprocess: bool
785            preprocessing is done when set to True
786
787        n_jobs : int, when possible, run in parallel
788            For now, only used by individual models that support it.
789
790        All the other parameters are the same as CustomClassifier's.
791
792    Attributes:
793
794        models_: dict-object
795            Returns a dictionary with each model pipeline as value
796            with key as name of models.
797
798        best_model_: object
799            Returns the best model pipeline based on the sort_by metric.
800
801    Examples:
802
803        import nnetsauce as ns
804        import numpy as np
805        from sklearn import datasets
806        from sklearn.utils import shuffle
807
808        dataset = datasets.load_iris()
809        X = dataset.data
810        y = dataset.target
811        X, y = shuffle(X, y, random_state=123)
812        X = X.astype(np.float32)
813        y = y.astype(np.float32)
814        X_train, X_test = X[:100], X[100:]
815        y_train, y_test = y[:100], y[100:]
816
817        clf = ns.LazyClassifier(verbose=0, ignore_warnings=True, custom_metric=None)
818        models, predictions = clf.fit(X_train, X_test, y_train, y_test)
819        model_dictionary = clf.provide_models(X_train,X_test,y_train,y_test)
820        print(models)
821
822    """
823
824    def __init__(
825        self,
826        verbose=0,
827        ignore_warnings=True,
828        custom_metric=None,
829        predictions=False,
830        sort_by="Accuracy",
831        random_state=42,
832        estimators="all",
833        preprocess=False,
834        n_jobs=None,
835        # CustomClassifier attributes
836        obj=None,
837        n_hidden_features=5,
838        activation_name="relu",
839        a=0.01,
840        nodes_sim="sobol",
841        bias=True,
842        dropout=0,
843        direct_link=True,
844        n_clusters=2,
845        cluster_encode=True,
846        type_clust="kmeans",
847        type_scaling=("std", "std", "std"),
848        col_sample=1,
849        row_sample=1,
850        seed=123,
851        backend="cpu",
852    ):
853        super().__init__(
854            verbose=verbose,
855            ignore_warnings=ignore_warnings,
856            custom_metric=custom_metric,
857            predictions=predictions,
858            sort_by=sort_by,
859            random_state=random_state,
860            estimators=estimators,
861            preprocess=preprocess,
862            n_jobs=n_jobs,
863            n_layers=1,
864            obj=obj,
865            n_hidden_features=n_hidden_features,
866            activation_name=activation_name,
867            a=a,
868            nodes_sim=nodes_sim,
869            bias=bias,
870            dropout=dropout,
871            direct_link=direct_link,
872            n_clusters=n_clusters,
873            cluster_encode=cluster_encode,
874            type_clust=type_clust,
875            type_scaling=type_scaling,
876            col_sample=col_sample,
877            row_sample=row_sample,
878            seed=seed,
879            backend=backend,
880        )

Fitting -- almost -- all the classification algorithms with nnetsauce's CustomClassifier and returning their scores (no layers).

Parameters:

verbose: int, optional (default=0)
    Any positive number for verbosity.

ignore_warnings: bool, optional (default=True)
    When set to True, the warning related to algorigms that are not able to run are ignored.

custom_metric: function, optional (default=None)
    When function is provided, models are evaluated based on the custom evaluation metric provided.

predictions: bool, optional (default=False)
    When set to True, the predictions of all the models models are returned as dataframe.

sort_by: string, optional (default='Accuracy')
    Sort models by a metric. Available options are 'Accuracy', 'Balanced Accuracy', 'ROC AUC', 'F1 Score'
    or a custom metric identified by its name and provided by custom_metric.

random_state: int, optional (default=42)
    Reproducibiility seed.

estimators: list, optional (default='all')
    list of Estimators names or just 'all' (default='all')

preprocess: bool
    preprocessing is done when set to True

n_jobs : int, when possible, run in parallel
    For now, only used by individual models that support it.

All the other parameters are the same as CustomClassifier's.

Attributes:

models_: dict-object
    Returns a dictionary with each model pipeline as value
    with key as name of models.

best_model_: object
    Returns the best model pipeline based on the sort_by metric.

Examples:

import nnetsauce as ns
import numpy as np
from sklearn import datasets
from sklearn.utils import shuffle

dataset = datasets.load_iris()
X = dataset.data
y = dataset.target
X, y = shuffle(X, y, random_state=123)
X = X.astype(np.float32)
y = y.astype(np.float32)
X_train, X_test = X[:100], X[100:]
y_train, y_test = y[:100], y[100:]

clf = ns.LazyClassifier(verbose=0, ignore_warnings=True, custom_metric=None)
models, predictions = clf.fit(X_train, X_test, y_train, y_test)
model_dictionary = clf.provide_models(X_train,X_test,y_train,y_test)
print(models)
class LazyRegressor(nnetsauce.LazyDeepRegressor):
657class LazyRegressor(LazyDeepRegressor):
658    """
659        Fitting -- almost -- all the regression algorithms with
660        nnetsauce's CustomRegressor and returning their scores.
661
662    Parameters:
663
664        verbose: int, optional (default=0)
665            Any positive number for verbosity.
666
667        ignore_warnings: bool, optional (default=True)
668            When set to True, the warning related to algorigms that are not able to run are ignored.
669
670        custom_metric: function, optional (default=None)
671            When function is provided, models are evaluated based on the custom evaluation metric provided.
672
673        predictions: bool, optional (default=False)
674            When set to True, the predictions of all the models models are returned as dataframe.
675
676        sort_by: string, optional (default='RMSE')
677            Sort models by a metric. Available options are 'R-Squared', 'Adjusted R-Squared', 'RMSE', 'Time Taken' and 'Custom Metric'.
678            or a custom metric identified by its name and provided by custom_metric.
679
680        random_state: int, optional (default=42)
681            Reproducibiility seed.
682
683        estimators: list, optional (default='all')
684            list of Estimators names or just 'all' (default='all')
685
686        preprocess: bool
687            preprocessing is done when set to True
688
689        n_jobs : int, when possible, run in parallel
690            For now, only used by individual models that support it.
691
692        All the other parameters are the same as CustomRegressor's.
693
694    Attributes:
695
696        models_: dict-object
697            Returns a dictionary with each model pipeline as value
698            with key as name of models.
699
700        best_model_: object
701            Returns the best model pipeline based on the sort_by metric.
702
703    Examples:
704
705        import nnetsauce as ns
706        import numpy as np
707        from sklearn import datasets
708        from sklearn.utils import shuffle
709
710        diabetes = datasets.load_diabetes()
711        X, y = shuffle(diabetes.data, diabetes.target, random_state=13)
712        X = X.astype(np.float32)
713
714        offset = int(X.shape[0] * 0.9)
715        X_train, y_train = X[:offset], y[:offset]
716        X_test, y_test = X[offset:], y[offset:]
717
718        reg = ns.LazyRegressor(verbose=0, ignore_warnings=False,
719                            custom_metric=None)
720        models, predictions = reg.fit(X_train, X_test, y_train, y_test)
721        print(models)
722
723    """
724
725    def __init__(
726        self,
727        verbose=0,
728        ignore_warnings=True,
729        custom_metric=None,
730        predictions=False,
731        sort_by="RMSE",
732        random_state=42,
733        estimators="all",
734        preprocess=False,
735        n_jobs=None,
736        # CustomRegressor attributes
737        obj=None,
738        n_hidden_features=5,
739        activation_name="relu",
740        a=0.01,
741        nodes_sim="sobol",
742        bias=True,
743        dropout=0,
744        direct_link=True,
745        n_clusters=2,
746        cluster_encode=True,
747        type_clust="kmeans",
748        type_scaling=("std", "std", "std"),
749        col_sample=1,
750        row_sample=1,
751        seed=123,
752        backend="cpu",
753    ):
754        super().__init__(
755            verbose=verbose,
756            ignore_warnings=ignore_warnings,
757            custom_metric=custom_metric,
758            predictions=predictions,
759            sort_by=sort_by,
760            random_state=random_state,
761            estimators=estimators,
762            preprocess=preprocess,
763            n_jobs=n_jobs,
764            n_layers=1,
765            obj=obj,
766            n_hidden_features=n_hidden_features,
767            activation_name=activation_name,
768            a=a,
769            nodes_sim=nodes_sim,
770            bias=bias,
771            dropout=dropout,
772            direct_link=direct_link,
773            n_clusters=n_clusters,
774            cluster_encode=cluster_encode,
775            type_clust=type_clust,
776            type_scaling=type_scaling,
777            col_sample=col_sample,
778            row_sample=row_sample,
779            seed=seed,
780            backend=backend,
781        )

Fitting -- almost -- all the regression algorithms with nnetsauce's CustomRegressor and returning their scores.

Parameters:

verbose: int, optional (default=0)
    Any positive number for verbosity.

ignore_warnings: bool, optional (default=True)
    When set to True, the warning related to algorigms that are not able to run are ignored.

custom_metric: function, optional (default=None)
    When function is provided, models are evaluated based on the custom evaluation metric provided.

predictions: bool, optional (default=False)
    When set to True, the predictions of all the models models are returned as dataframe.

sort_by: string, optional (default='RMSE')
    Sort models by a metric. Available options are 'R-Squared', 'Adjusted R-Squared', 'RMSE', 'Time Taken' and 'Custom Metric'.
    or a custom metric identified by its name and provided by custom_metric.

random_state: int, optional (default=42)
    Reproducibiility seed.

estimators: list, optional (default='all')
    list of Estimators names or just 'all' (default='all')

preprocess: bool
    preprocessing is done when set to True

n_jobs : int, when possible, run in parallel
    For now, only used by individual models that support it.

All the other parameters are the same as CustomRegressor's.

Attributes:

models_: dict-object
    Returns a dictionary with each model pipeline as value
    with key as name of models.

best_model_: object
    Returns the best model pipeline based on the sort_by metric.

Examples:

import nnetsauce as ns
import numpy as np
from sklearn import datasets
from sklearn.utils import shuffle

diabetes = datasets.load_diabetes()
X, y = shuffle(diabetes.data, diabetes.target, random_state=13)
X = X.astype(np.float32)

offset = int(X.shape[0] * 0.9)
X_train, y_train = X[:offset], y[:offset]
X_test, y_test = X[offset:], y[offset:]

reg = ns.LazyRegressor(verbose=0, ignore_warnings=False,
                    custom_metric=None)
models, predictions = reg.fit(X_train, X_test, y_train, y_test)
print(models)
class LazyDeepClassifier(nnetsauce.custom.custom.Custom, sklearn.base.ClassifierMixin):
 94class LazyDeepClassifier(Custom, ClassifierMixin):
 95    """
 96
 97    Fitting -- almost -- all the classification algorithms with layers of
 98    nnetsauce's CustomClassifier and returning their scores.
 99
100    Parameters:
101
102        verbose: int, optional (default=0)
103            Any positive number for verbosity.
104
105        ignore_warnings: bool, optional (default=True)
106            When set to True, the warning related to algorigms that are not
107            able to run are ignored.
108
109        custom_metric: function, optional (default=None)
110            When function is provided, models are evaluated based on the custom
111              evaluation metric provided.
112
113        predictions: bool, optional (default=False)
114            When set to True, the predictions of all the models models are
115            returned as data frame.
116
117        sort_by: string, optional (default='Accuracy')
118            Sort models by a metric. Available options are 'Accuracy',
119            'Balanced Accuracy', 'ROC AUC', 'F1 Score' or a custom metric
120            identified by its name and provided by custom_metric.
121
122        random_state: int, optional (default=42)
123            Reproducibiility seed.
124
125        estimators: list, optional (default='all')
126            list of Estimators names or just 'all' for > 90 classifiers
127            (default='all')
128
129        preprocess: bool, preprocessing is done when set to True
130
131        n_jobs: int, when possible, run in parallel
132            For now, only used by individual models that support it.
133
134        n_layers: int, optional (default=3)
135            Number of layers of CustomClassifiers to be used.
136
137        All the other parameters are the same as CustomClassifier's.
138
139    Attributes:
140
141        models_: dict-object
142            Returns a dictionary with each model pipeline as value
143            with key as name of models.
144
145        best_model_: object
146            Returns the best model pipeline.
147
148    Examples
149
150        ```python
151        import nnetsauce as ns
152        from sklearn.datasets import load_breast_cancer
153        from sklearn.model_selection import train_test_split
154        data = load_breast_cancer()
155        X = data.data
156        y= data.target
157        X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=.2,
158            random_state=123)
159        clf = ns.LazyDeepClassifier(verbose=0, ignore_warnings=True, custom_metric=None)
160        models, predictions = clf.fit(X_train, X_test, y_train, y_test)
161        model_dictionary = clf.provide_models(X_train,X_test,y_train,y_test)
162        print(models)
163        ```
164
165    """
166
167    def __init__(
168        self,
169        verbose=0,
170        ignore_warnings=True,
171        custom_metric=None,
172        predictions=False,
173        sort_by="Accuracy",
174        random_state=42,
175        estimators="all",
176        preprocess=False,
177        n_jobs=None,
178        # Defining depth
179        n_layers=3,
180        # CustomClassifier attributes
181        obj=None,
182        n_hidden_features=5,
183        activation_name="relu",
184        a=0.01,
185        nodes_sim="sobol",
186        bias=True,
187        dropout=0,
188        direct_link=True,
189        n_clusters=2,
190        cluster_encode=True,
191        type_clust="kmeans",
192        type_scaling=("std", "std", "std"),
193        col_sample=1,
194        row_sample=1,
195        seed=123,
196        backend="cpu",
197    ):
198        self.verbose = verbose
199        self.ignore_warnings = ignore_warnings
200        self.custom_metric = custom_metric
201        self.predictions = predictions
202        self.sort_by = sort_by
203        self.models_ = {}
204        self.best_model_ = None
205        self.random_state = random_state
206        self.estimators = estimators
207        self.preprocess = preprocess
208        self.n_layers = n_layers - 1
209        self.n_jobs = n_jobs
210        super().__init__(
211            obj=obj,
212            n_hidden_features=n_hidden_features,
213            activation_name=activation_name,
214            a=a,
215            nodes_sim=nodes_sim,
216            bias=bias,
217            dropout=dropout,
218            direct_link=direct_link,
219            n_clusters=n_clusters,
220            cluster_encode=cluster_encode,
221            type_clust=type_clust,
222            type_scaling=type_scaling,
223            col_sample=col_sample,
224            row_sample=row_sample,
225            seed=seed,
226            backend=backend,
227        )
228
229    def fit(self, X_train, X_test, y_train, y_test):
230        """Fit classifiers to X_train and y_train, predict and score on X_test,
231        y_test.
232
233        Parameters:
234
235            X_train: array-like,
236                Training vectors, where rows is the number of samples
237                and columns is the number of features.
238
239            X_test: array-like,
240                Testing vectors, where rows is the number of samples
241                and columns is the number of features.
242
243            y_train: array-like,
244                Training vectors, where rows is the number of samples
245                and columns is the number of features.
246
247            y_test: array-like,
248                Testing vectors, where rows is the number of samples
249                and columns is the number of features.
250
251        Returns:
252
253            scores: Pandas DataFrame
254                Returns metrics of all the models in a Pandas DataFrame.
255
256            predictions: Pandas DataFrame
257                Returns predictions of all the models in a Pandas DataFrame.
258        """
259        Accuracy = []
260        B_Accuracy = []
261        ROC_AUC = []
262        F1 = []
263        names = []
264        TIME = []
265        predictions = {}
266
267        if self.custom_metric is not None:
268            CUSTOM_METRIC = []
269
270        if isinstance(X_train, np.ndarray):
271            X_train = pd.DataFrame(X_train)
272            X_test = pd.DataFrame(X_test)
273
274        numeric_features = X_train.select_dtypes(include=[np.number]).columns
275        categorical_features = X_train.select_dtypes(include=["object"]).columns
276
277        categorical_low, categorical_high = get_card_split(
278            X_train, categorical_features
279        )
280
281        if self.preprocess is True:
282            preprocessor = ColumnTransformer(
283                transformers=[
284                    ("numeric", numeric_transformer, numeric_features),
285                    (
286                        "categorical_low",
287                        categorical_transformer_low,
288                        categorical_low,
289                    ),
290                    (
291                        "categorical_high",
292                        categorical_transformer_high,
293                        categorical_high,
294                    ),
295                ]
296            )
297
298        # baseline models
299        try:
300            baseline_names = ["RandomForestClassifier", "XGBClassifier"]
301            baseline_models = [RandomForestClassifier(), xgb.XGBClassifier()]
302        except Exception as exception:
303            baseline_names = ["RandomForestClassifier"]
304            baseline_models = [RandomForestClassifier()]
305
306        for name, model in zip(baseline_names, baseline_models):
307            start = time.time()
308            try:
309                model.fit(X_train, y_train)
310                self.models_[name] = model
311                y_pred = model.predict(X_test)
312                accuracy = accuracy_score(y_test, y_pred, normalize=True)
313                b_accuracy = balanced_accuracy_score(y_test, y_pred)
314                f1 = f1_score(y_test, y_pred, average="weighted")
315                try:
316                    roc_auc = roc_auc_score(y_test, y_pred)
317                except Exception as exception:
318                    roc_auc = None
319                    if self.ignore_warnings is False:
320                        print("ROC AUC couldn't be calculated for " + name)
321                        print(exception)
322                names.append(name)
323                Accuracy.append(accuracy)
324                B_Accuracy.append(b_accuracy)
325                ROC_AUC.append(roc_auc)
326                F1.append(f1)
327                TIME.append(time.time() - start)
328                if self.custom_metric is not None:
329                    custom_metric = self.custom_metric(y_test, y_pred)
330                    CUSTOM_METRIC.append(custom_metric)
331                if self.verbose > 0:
332                    if self.custom_metric is not None:
333                        print(
334                            {
335                                "Model": name,
336                                "Accuracy": accuracy,
337                                "Balanced Accuracy": b_accuracy,
338                                "ROC AUC": roc_auc,
339                                "F1 Score": f1,
340                                self.custom_metric.__name__: custom_metric,
341                                "Time taken": time.time() - start,
342                            }
343                        )
344                    else:
345                        print(
346                            {
347                                "Model": name,
348                                "Accuracy": accuracy,
349                                "Balanced Accuracy": b_accuracy,
350                                "ROC AUC": roc_auc,
351                                "F1 Score": f1,
352                                "Time taken": time.time() - start,
353                            }
354                        )
355                if self.predictions:
356                    predictions[name] = y_pred
357            except Exception as exception:
358                if self.ignore_warnings is False:
359                    print(name + " model failed to execute")
360                    print(exception)
361
362        if self.estimators == "all":
363            self.classifiers = [
364                item
365                for sublist in [
366                    DEEPCLASSIFIERS,
367                    DEEPMULTITASKCLASSIFIERS,
368                    DEEPSIMPLEMULTITASKCLASSIFIERS,
369                ]
370                for item in sublist
371            ]
372        else:
373            self.classifiers = (
374                [
375                    ("DeepCustomClassifier(" + est[0] + ")", est[1])
376                    for est in all_estimators()
377                    if (
378                        issubclass(est[1], ClassifierMixin)
379                        and (est[0] in self.estimators)
380                    )
381                ]
382                + [
383                    (
384                        "DeepMultitaskClassifier(" + est[0] + ")",
385                        partial(MultitaskClassifier, obj=est[1]()),
386                    )
387                    for est in all_estimators()
388                    if (
389                        issubclass(est[1], RegressorMixin)
390                        and (est[0] in self.estimators)
391                    )
392                ]
393                + [
394                    (
395                        "DeepSimpleMultitaskClassifier(" + est[0] + ")",
396                        partial(SimpleMultitaskClassifier, obj=est[1]()),
397                    )
398                    for est in all_estimators()
399                    if (
400                        issubclass(est[1], RegressorMixin)
401                        and (est[0] in self.estimators)
402                    )
403                ]
404            )
405
406        if self.preprocess is True:
407
408            for name, model in tqdm(self.classifiers):  # do parallel exec
409
410                other_args = (
411                    {}
412                )  # use this trick for `random_state` too --> refactor
413                try:
414                    if (
415                        "n_jobs" in model().get_params().keys()
416                        and name.find("LogisticRegression") == -1
417                    ):
418                        other_args["n_jobs"] = self.n_jobs
419                except Exception:
420                    pass
421
422                start = time.time()
423
424                try:
425                    if "random_state" in model().get_params().keys():
426                        layer_clf = CustomClassifier(
427                            obj=model(random_state=self.random_state),
428                            n_hidden_features=self.n_hidden_features,
429                            activation_name=self.activation_name,
430                            a=self.a,
431                            nodes_sim=self.nodes_sim,
432                            bias=self.bias,
433                            dropout=self.dropout,
434                            direct_link=self.direct_link,
435                            n_clusters=self.n_clusters,
436                            cluster_encode=self.cluster_encode,
437                            type_clust=self.type_clust,
438                            type_scaling=self.type_scaling,
439                            col_sample=self.col_sample,
440                            row_sample=self.row_sample,
441                            seed=self.seed,
442                            backend=self.backend,
443                        )
444
445                    else:
446                        layer_clf = CustomClassifier(
447                            obj=model(),
448                            n_hidden_features=self.n_hidden_features,
449                            activation_name=self.activation_name,
450                            a=self.a,
451                            nodes_sim=self.nodes_sim,
452                            bias=self.bias,
453                            dropout=self.dropout,
454                            direct_link=self.direct_link,
455                            n_clusters=self.n_clusters,
456                            cluster_encode=self.cluster_encode,
457                            type_clust=self.type_clust,
458                            type_scaling=self.type_scaling,
459                            col_sample=self.col_sample,
460                            row_sample=self.row_sample,
461                            seed=self.seed,
462                            backend=self.backend,
463                        )
464
465                    layer_clf.fit(X_train, y_train)
466
467                    for _ in range(self.n_layers):
468                        layer_clf = deepcopy(
469                            CustomClassifier(
470                                obj=layer_clf,
471                                n_hidden_features=self.n_hidden_features,
472                                activation_name=self.activation_name,
473                                a=self.a,
474                                nodes_sim=self.nodes_sim,
475                                bias=self.bias,
476                                dropout=self.dropout,
477                                direct_link=self.direct_link,
478                                n_clusters=self.n_clusters,
479                                cluster_encode=self.cluster_encode,
480                                type_clust=self.type_clust,
481                                type_scaling=self.type_scaling,
482                                col_sample=self.col_sample,
483                                row_sample=self.row_sample,
484                                seed=self.seed,
485                                backend=self.backend,
486                            )
487                        )
488
489                    pipe = Pipeline(
490                        [
491                            ("preprocessor", preprocessor),
492                            ("classifier", layer_clf),
493                        ]
494                    )
495
496                    pipe.fit(X_train, y_train)
497                    self.models_[name] = pipe
498                    y_pred = pipe.predict(X_test)
499                    accuracy = accuracy_score(y_test, y_pred, normalize=True)
500                    b_accuracy = balanced_accuracy_score(y_test, y_pred)
501                    f1 = f1_score(y_test, y_pred, average="weighted")
502                    try:
503                        roc_auc = roc_auc_score(y_test, y_pred)
504                    except Exception as exception:
505                        roc_auc = None
506                        if self.ignore_warnings is False:
507                            print("ROC AUC couldn't be calculated for " + name)
508                            print(exception)
509                    names.append(name)
510                    Accuracy.append(accuracy)
511                    B_Accuracy.append(b_accuracy)
512                    ROC_AUC.append(roc_auc)
513                    F1.append(f1)
514                    TIME.append(time.time() - start)
515                    if self.custom_metric is not None:
516                        custom_metric = self.custom_metric(y_test, y_pred)
517                        CUSTOM_METRIC.append(custom_metric)
518                    if self.verbose > 0:
519                        if self.custom_metric is not None:
520                            print(
521                                {
522                                    "Model": name,
523                                    "Accuracy": accuracy,
524                                    "Balanced Accuracy": b_accuracy,
525                                    "ROC AUC": roc_auc,
526                                    "F1 Score": f1,
527                                    self.custom_metric.__name__: custom_metric,
528                                    "Time taken": time.time() - start,
529                                }
530                            )
531                        else:
532                            print(
533                                {
534                                    "Model": name,
535                                    "Accuracy": accuracy,
536                                    "Balanced Accuracy": b_accuracy,
537                                    "ROC AUC": roc_auc,
538                                    "F1 Score": f1,
539                                    "Time taken": time.time() - start,
540                                }
541                            )
542                    if self.predictions:
543                        predictions[name] = y_pred
544                except Exception as exception:
545                    if self.ignore_warnings is False:
546                        print(name + " model failed to execute")
547                        print(exception)
548
549        else:  # no preprocessing
550
551            for name, model in tqdm(self.classifiers):  # do parallel exec
552                start = time.time()
553                try:
554                    if "random_state" in model().get_params().keys():
555                        layer_clf = CustomClassifier(
556                            obj=model(random_state=self.random_state),
557                            n_hidden_features=self.n_hidden_features,
558                            activation_name=self.activation_name,
559                            a=self.a,
560                            nodes_sim=self.nodes_sim,
561                            bias=self.bias,
562                            dropout=self.dropout,
563                            direct_link=self.direct_link,
564                            n_clusters=self.n_clusters,
565                            cluster_encode=self.cluster_encode,
566                            type_clust=self.type_clust,
567                            type_scaling=self.type_scaling,
568                            col_sample=self.col_sample,
569                            row_sample=self.row_sample,
570                            seed=self.seed,
571                            backend=self.backend,
572                        )
573
574                    else:
575                        layer_clf = CustomClassifier(
576                            obj=model(),
577                            n_hidden_features=self.n_hidden_features,
578                            activation_name=self.activation_name,
579                            a=self.a,
580                            nodes_sim=self.nodes_sim,
581                            bias=self.bias,
582                            dropout=self.dropout,
583                            direct_link=self.direct_link,
584                            n_clusters=self.n_clusters,
585                            cluster_encode=self.cluster_encode,
586                            type_clust=self.type_clust,
587                            type_scaling=self.type_scaling,
588                            col_sample=self.col_sample,
589                            row_sample=self.row_sample,
590                            seed=self.seed,
591                            backend=self.backend,
592                        )
593
594                    layer_clf.fit(X_train, y_train)
595
596                    for _ in range(self.n_layers):
597                        layer_clf = deepcopy(
598                            CustomClassifier(
599                                obj=layer_clf,
600                                n_hidden_features=self.n_hidden_features,
601                                activation_name=self.activation_name,
602                                a=self.a,
603                                nodes_sim=self.nodes_sim,
604                                bias=self.bias,
605                                dropout=self.dropout,
606                                direct_link=self.direct_link,
607                                n_clusters=self.n_clusters,
608                                cluster_encode=self.cluster_encode,
609                                type_clust=self.type_clust,
610                                type_scaling=self.type_scaling,
611                                col_sample=self.col_sample,
612                                row_sample=self.row_sample,
613                                seed=self.seed,
614                                backend=self.backend,
615                            )
616                        )
617
618                        # layer_clf.fit(X_train, y_train)
619
620                    layer_clf.fit(X_train, y_train)
621
622                    self.models_[name] = layer_clf
623                    y_pred = layer_clf.predict(X_test)
624                    accuracy = accuracy_score(y_test, y_pred, normalize=True)
625                    b_accuracy = balanced_accuracy_score(y_test, y_pred)
626                    f1 = f1_score(y_test, y_pred, average="weighted")
627                    try:
628                        roc_auc = roc_auc_score(y_test, y_pred)
629                    except Exception as exception:
630                        roc_auc = None
631                        if self.ignore_warnings is False:
632                            print("ROC AUC couldn't be calculated for " + name)
633                            print(exception)
634                    names.append(name)
635                    Accuracy.append(accuracy)
636                    B_Accuracy.append(b_accuracy)
637                    ROC_AUC.append(roc_auc)
638                    F1.append(f1)
639                    TIME.append(time.time() - start)
640                    if self.custom_metric is not None:
641                        custom_metric = self.custom_metric(y_test, y_pred)
642                        CUSTOM_METRIC.append(custom_metric)
643                    if self.verbose > 0:
644                        if self.custom_metric is not None:
645                            print(
646                                {
647                                    "Model": name,
648                                    "Accuracy": accuracy,
649                                    "Balanced Accuracy": b_accuracy,
650                                    "ROC AUC": roc_auc,
651                                    "F1 Score": f1,
652                                    self.custom_metric.__name__: custom_metric,
653                                    "Time taken": time.time() - start,
654                                }
655                            )
656                        else:
657                            print(
658                                {
659                                    "Model": name,
660                                    "Accuracy": accuracy,
661                                    "Balanced Accuracy": b_accuracy,
662                                    "ROC AUC": roc_auc,
663                                    "F1 Score": f1,
664                                    "Time taken": time.time() - start,
665                                }
666                            )
667                    if self.predictions:
668                        predictions[name] = y_pred
669                except Exception as exception:
670                    if self.ignore_warnings is False:
671                        print(name + " model failed to execute")
672                        print(exception)
673
674        if self.custom_metric is None:
675            scores = pd.DataFrame(
676                {
677                    "Model": names,
678                    "Accuracy": Accuracy,
679                    "Balanced Accuracy": B_Accuracy,
680                    "ROC AUC": ROC_AUC,
681                    "F1 Score": F1,
682                    "Time Taken": TIME,
683                }
684            )
685        else:
686            scores = pd.DataFrame(
687                {
688                    "Model": names,
689                    "Accuracy": Accuracy,
690                    "Balanced Accuracy": B_Accuracy,
691                    "ROC AUC": ROC_AUC,
692                    "F1 Score": F1,
693                    "Custom metric": CUSTOM_METRIC,
694                    "Time Taken": TIME,
695                }
696            )
697        scores = scores.sort_values(by=self.sort_by, ascending=False).set_index(
698            "Model"
699        )
700
701        self.best_model_ = self.models_[scores.index[0]]
702
703        if self.predictions is True:
704
705            return scores, predictions
706
707        return scores
708
709    def get_best_model(self):
710        """
711        This function returns the best model pipeline based on the sort_by metric.
712
713        Returns:
714
715            best_model: object,
716                Returns the best model pipeline based on the sort_by metric.
717
718        """
719        return self.best_model_
720
721    def provide_models(self, X_train, X_test, y_train, y_test):
722        """Returns all the model objects trained. If fit hasn't been called yet,
723        then it's called to return the models.
724
725        Parameters:
726
727        X_train: array-like,
728            Training vectors, where rows is the number of samples
729            and columns is the number of features.
730
731        X_test: array-like,
732            Testing vectors, where rows is the number of samples
733            and columns is the number of features.
734
735        y_train: array-like,
736            Training vectors, where rows is the number of samples
737            and columns is the number of features.
738
739        y_test: array-like,
740            Testing vectors, where rows is the number of samples
741            and columns is the number of features.
742
743        Returns:
744
745            models: dict-object,
746                Returns a dictionary with each model's pipeline as value
747                and key = name of the model.
748        """
749        if len(self.models_.keys()) == 0:
750            self.fit(X_train, X_test, y_train, y_test)
751
752        return self.models_

Fitting -- almost -- all the classification algorithms with layers of nnetsauce's CustomClassifier and returning their scores.

Parameters:

verbose: int, optional (default=0)
    Any positive number for verbosity.

ignore_warnings: bool, optional (default=True)
    When set to True, the warning related to algorigms that are not
    able to run are ignored.

custom_metric: function, optional (default=None)
    When function is provided, models are evaluated based on the custom
      evaluation metric provided.

predictions: bool, optional (default=False)
    When set to True, the predictions of all the models models are
    returned as data frame.

sort_by: string, optional (default='Accuracy')
    Sort models by a metric. Available options are 'Accuracy',
    'Balanced Accuracy', 'ROC AUC', 'F1 Score' or a custom metric
    identified by its name and provided by custom_metric.

random_state: int, optional (default=42)
    Reproducibiility seed.

estimators: list, optional (default='all')
    list of Estimators names or just 'all' for > 90 classifiers
    (default='all')

preprocess: bool, preprocessing is done when set to True

n_jobs: int, when possible, run in parallel
    For now, only used by individual models that support it.

n_layers: int, optional (default=3)
    Number of layers of CustomClassifiers to be used.

All the other parameters are the same as CustomClassifier's.

Attributes:

models_: dict-object
    Returns a dictionary with each model pipeline as value
    with key as name of models.

best_model_: object
    Returns the best model pipeline.

Examples

import nnetsauce as ns
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
data = load_breast_cancer()
X = data.data
y= data.target
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=.2,
    random_state=123)
clf = ns.LazyDeepClassifier(verbose=0, ignore_warnings=True, custom_metric=None)
models, predictions = clf.fit(X_train, X_test, y_train, y_test)
model_dictionary = clf.provide_models(X_train,X_test,y_train,y_test)
print(models)
def fit(self, X_train, X_test, y_train, y_test):
229    def fit(self, X_train, X_test, y_train, y_test):
230        """Fit classifiers to X_train and y_train, predict and score on X_test,
231        y_test.
232
233        Parameters:
234
235            X_train: array-like,
236                Training vectors, where rows is the number of samples
237                and columns is the number of features.
238
239            X_test: array-like,
240                Testing vectors, where rows is the number of samples
241                and columns is the number of features.
242
243            y_train: array-like,
244                Training vectors, where rows is the number of samples
245                and columns is the number of features.
246
247            y_test: array-like,
248                Testing vectors, where rows is the number of samples
249                and columns is the number of features.
250
251        Returns:
252
253            scores: Pandas DataFrame
254                Returns metrics of all the models in a Pandas DataFrame.
255
256            predictions: Pandas DataFrame
257                Returns predictions of all the models in a Pandas DataFrame.
258        """
259        Accuracy = []
260        B_Accuracy = []
261        ROC_AUC = []
262        F1 = []
263        names = []
264        TIME = []
265        predictions = {}
266
267        if self.custom_metric is not None:
268            CUSTOM_METRIC = []
269
270        if isinstance(X_train, np.ndarray):
271            X_train = pd.DataFrame(X_train)
272            X_test = pd.DataFrame(X_test)
273
274        numeric_features = X_train.select_dtypes(include=[np.number]).columns
275        categorical_features = X_train.select_dtypes(include=["object"]).columns
276
277        categorical_low, categorical_high = get_card_split(
278            X_train, categorical_features
279        )
280
281        if self.preprocess is True:
282            preprocessor = ColumnTransformer(
283                transformers=[
284                    ("numeric", numeric_transformer, numeric_features),
285                    (
286                        "categorical_low",
287                        categorical_transformer_low,
288                        categorical_low,
289                    ),
290                    (
291                        "categorical_high",
292                        categorical_transformer_high,
293                        categorical_high,
294                    ),
295                ]
296            )
297
298        # baseline models
299        try:
300            baseline_names = ["RandomForestClassifier", "XGBClassifier"]
301            baseline_models = [RandomForestClassifier(), xgb.XGBClassifier()]
302        except Exception as exception:
303            baseline_names = ["RandomForestClassifier"]
304            baseline_models = [RandomForestClassifier()]
305
306        for name, model in zip(baseline_names, baseline_models):
307            start = time.time()
308            try:
309                model.fit(X_train, y_train)
310                self.models_[name] = model
311                y_pred = model.predict(X_test)
312                accuracy = accuracy_score(y_test, y_pred, normalize=True)
313                b_accuracy = balanced_accuracy_score(y_test, y_pred)
314                f1 = f1_score(y_test, y_pred, average="weighted")
315                try:
316                    roc_auc = roc_auc_score(y_test, y_pred)
317                except Exception as exception:
318                    roc_auc = None
319                    if self.ignore_warnings is False:
320                        print("ROC AUC couldn't be calculated for " + name)
321                        print(exception)
322                names.append(name)
323                Accuracy.append(accuracy)
324                B_Accuracy.append(b_accuracy)
325                ROC_AUC.append(roc_auc)
326                F1.append(f1)
327                TIME.append(time.time() - start)
328                if self.custom_metric is not None:
329                    custom_metric = self.custom_metric(y_test, y_pred)
330                    CUSTOM_METRIC.append(custom_metric)
331                if self.verbose > 0:
332                    if self.custom_metric is not None:
333                        print(
334                            {
335                                "Model": name,
336                                "Accuracy": accuracy,
337                                "Balanced Accuracy": b_accuracy,
338                                "ROC AUC": roc_auc,
339                                "F1 Score": f1,
340                                self.custom_metric.__name__: custom_metric,
341                                "Time taken": time.time() - start,
342                            }
343                        )
344                    else:
345                        print(
346                            {
347                                "Model": name,
348                                "Accuracy": accuracy,
349                                "Balanced Accuracy": b_accuracy,
350                                "ROC AUC": roc_auc,
351                                "F1 Score": f1,
352                                "Time taken": time.time() - start,
353                            }
354                        )
355                if self.predictions:
356                    predictions[name] = y_pred
357            except Exception as exception:
358                if self.ignore_warnings is False:
359                    print(name + " model failed to execute")
360                    print(exception)
361
362        if self.estimators == "all":
363            self.classifiers = [
364                item
365                for sublist in [
366                    DEEPCLASSIFIERS,
367                    DEEPMULTITASKCLASSIFIERS,
368                    DEEPSIMPLEMULTITASKCLASSIFIERS,
369                ]
370                for item in sublist
371            ]
372        else:
373            self.classifiers = (
374                [
375                    ("DeepCustomClassifier(" + est[0] + ")", est[1])
376                    for est in all_estimators()
377                    if (
378                        issubclass(est[1], ClassifierMixin)
379                        and (est[0] in self.estimators)
380                    )
381                ]
382                + [
383                    (
384                        "DeepMultitaskClassifier(" + est[0] + ")",
385                        partial(MultitaskClassifier, obj=est[1]()),
386                    )
387                    for est in all_estimators()
388                    if (
389                        issubclass(est[1], RegressorMixin)
390                        and (est[0] in self.estimators)
391                    )
392                ]
393                + [
394                    (
395                        "DeepSimpleMultitaskClassifier(" + est[0] + ")",
396                        partial(SimpleMultitaskClassifier, obj=est[1]()),
397                    )
398                    for est in all_estimators()
399                    if (
400                        issubclass(est[1], RegressorMixin)
401                        and (est[0] in self.estimators)
402                    )
403                ]
404            )
405
406        if self.preprocess is True:
407
408            for name, model in tqdm(self.classifiers):  # do parallel exec
409
410                other_args = (
411                    {}
412                )  # use this trick for `random_state` too --> refactor
413                try:
414                    if (
415                        "n_jobs" in model().get_params().keys()
416                        and name.find("LogisticRegression") == -1
417                    ):
418                        other_args["n_jobs"] = self.n_jobs
419                except Exception:
420                    pass
421
422                start = time.time()
423
424                try:
425                    if "random_state" in model().get_params().keys():
426                        layer_clf = CustomClassifier(
427                            obj=model(random_state=self.random_state),
428                            n_hidden_features=self.n_hidden_features,
429                            activation_name=self.activation_name,
430                            a=self.a,
431                            nodes_sim=self.nodes_sim,
432                            bias=self.bias,
433                            dropout=self.dropout,
434                            direct_link=self.direct_link,
435                            n_clusters=self.n_clusters,
436                            cluster_encode=self.cluster_encode,
437                            type_clust=self.type_clust,
438                            type_scaling=self.type_scaling,
439                            col_sample=self.col_sample,
440                            row_sample=self.row_sample,
441                            seed=self.seed,
442                            backend=self.backend,
443                        )
444
445                    else:
446                        layer_clf = CustomClassifier(
447                            obj=model(),
448                            n_hidden_features=self.n_hidden_features,
449                            activation_name=self.activation_name,
450                            a=self.a,
451                            nodes_sim=self.nodes_sim,
452                            bias=self.bias,
453                            dropout=self.dropout,
454                            direct_link=self.direct_link,
455                            n_clusters=self.n_clusters,
456                            cluster_encode=self.cluster_encode,
457                            type_clust=self.type_clust,
458                            type_scaling=self.type_scaling,
459                            col_sample=self.col_sample,
460                            row_sample=self.row_sample,
461                            seed=self.seed,
462                            backend=self.backend,
463                        )
464
465                    layer_clf.fit(X_train, y_train)
466
467                    for _ in range(self.n_layers):
468                        layer_clf = deepcopy(
469                            CustomClassifier(
470                                obj=layer_clf,
471                                n_hidden_features=self.n_hidden_features,
472                                activation_name=self.activation_name,
473                                a=self.a,
474                                nodes_sim=self.nodes_sim,
475                                bias=self.bias,
476                                dropout=self.dropout,
477                                direct_link=self.direct_link,
478                                n_clusters=self.n_clusters,
479                                cluster_encode=self.cluster_encode,
480                                type_clust=self.type_clust,
481                                type_scaling=self.type_scaling,
482                                col_sample=self.col_sample,
483                                row_sample=self.row_sample,
484                                seed=self.seed,
485                                backend=self.backend,
486                            )
487                        )
488
489                    pipe = Pipeline(
490                        [
491                            ("preprocessor", preprocessor),
492                            ("classifier", layer_clf),
493                        ]
494                    )
495
496                    pipe.fit(X_train, y_train)
497                    self.models_[name] = pipe
498                    y_pred = pipe.predict(X_test)
499                    accuracy = accuracy_score(y_test, y_pred, normalize=True)
500                    b_accuracy = balanced_accuracy_score(y_test, y_pred)
501                    f1 = f1_score(y_test, y_pred, average="weighted")
502                    try:
503                        roc_auc = roc_auc_score(y_test, y_pred)
504                    except Exception as exception:
505                        roc_auc = None
506                        if self.ignore_warnings is False:
507                            print("ROC AUC couldn't be calculated for " + name)
508                            print(exception)
509                    names.append(name)
510                    Accuracy.append(accuracy)
511                    B_Accuracy.append(b_accuracy)
512                    ROC_AUC.append(roc_auc)
513                    F1.append(f1)
514                    TIME.append(time.time() - start)
515                    if self.custom_metric is not None:
516                        custom_metric = self.custom_metric(y_test, y_pred)
517                        CUSTOM_METRIC.append(custom_metric)
518                    if self.verbose > 0:
519                        if self.custom_metric is not None:
520                            print(
521                                {
522                                    "Model": name,
523                                    "Accuracy": accuracy,
524                                    "Balanced Accuracy": b_accuracy,
525                                    "ROC AUC": roc_auc,
526                                    "F1 Score": f1,
527                                    self.custom_metric.__name__: custom_metric,
528                                    "Time taken": time.time() - start,
529                                }
530                            )
531                        else:
532                            print(
533                                {
534                                    "Model": name,
535                                    "Accuracy": accuracy,
536                                    "Balanced Accuracy": b_accuracy,
537                                    "ROC AUC": roc_auc,
538                                    "F1 Score": f1,
539                                    "Time taken": time.time() - start,
540                                }
541                            )
542                    if self.predictions:
543                        predictions[name] = y_pred
544                except Exception as exception:
545                    if self.ignore_warnings is False:
546                        print(name + " model failed to execute")
547                        print(exception)
548
549        else:  # no preprocessing
550
551            for name, model in tqdm(self.classifiers):  # do parallel exec
552                start = time.time()
553                try:
554                    if "random_state" in model().get_params().keys():
555                        layer_clf = CustomClassifier(
556                            obj=model(random_state=self.random_state),
557                            n_hidden_features=self.n_hidden_features,
558                            activation_name=self.activation_name,
559                            a=self.a,
560                            nodes_sim=self.nodes_sim,
561                            bias=self.bias,
562                            dropout=self.dropout,
563                            direct_link=self.direct_link,
564                            n_clusters=self.n_clusters,
565                            cluster_encode=self.cluster_encode,
566                            type_clust=self.type_clust,
567                            type_scaling=self.type_scaling,
568                            col_sample=self.col_sample,
569                            row_sample=self.row_sample,
570                            seed=self.seed,
571                            backend=self.backend,
572                        )
573
574                    else:
575                        layer_clf = CustomClassifier(
576                            obj=model(),
577                            n_hidden_features=self.n_hidden_features,
578                            activation_name=self.activation_name,
579                            a=self.a,
580                            nodes_sim=self.nodes_sim,
581                            bias=self.bias,
582                            dropout=self.dropout,
583                            direct_link=self.direct_link,
584                            n_clusters=self.n_clusters,
585                            cluster_encode=self.cluster_encode,
586                            type_clust=self.type_clust,
587                            type_scaling=self.type_scaling,
588                            col_sample=self.col_sample,
589                            row_sample=self.row_sample,
590                            seed=self.seed,
591                            backend=self.backend,
592                        )
593
594                    layer_clf.fit(X_train, y_train)
595
596                    for _ in range(self.n_layers):
597                        layer_clf = deepcopy(
598                            CustomClassifier(
599                                obj=layer_clf,
600                                n_hidden_features=self.n_hidden_features,
601                                activation_name=self.activation_name,
602                                a=self.a,
603                                nodes_sim=self.nodes_sim,
604                                bias=self.bias,
605                                dropout=self.dropout,
606                                direct_link=self.direct_link,
607                                n_clusters=self.n_clusters,
608                                cluster_encode=self.cluster_encode,
609                                type_clust=self.type_clust,
610                                type_scaling=self.type_scaling,
611                                col_sample=self.col_sample,
612                                row_sample=self.row_sample,
613                                seed=self.seed,
614                                backend=self.backend,
615                            )
616                        )
617
618                        # layer_clf.fit(X_train, y_train)
619
620                    layer_clf.fit(X_train, y_train)
621
622                    self.models_[name] = layer_clf
623                    y_pred = layer_clf.predict(X_test)
624                    accuracy = accuracy_score(y_test, y_pred, normalize=True)
625                    b_accuracy = balanced_accuracy_score(y_test, y_pred)
626                    f1 = f1_score(y_test, y_pred, average="weighted")
627                    try:
628                        roc_auc = roc_auc_score(y_test, y_pred)
629                    except Exception as exception:
630                        roc_auc = None
631                        if self.ignore_warnings is False:
632                            print("ROC AUC couldn't be calculated for " + name)
633                            print(exception)
634                    names.append(name)
635                    Accuracy.append(accuracy)
636                    B_Accuracy.append(b_accuracy)
637                    ROC_AUC.append(roc_auc)
638                    F1.append(f1)
639                    TIME.append(time.time() - start)
640                    if self.custom_metric is not None:
641                        custom_metric = self.custom_metric(y_test, y_pred)
642                        CUSTOM_METRIC.append(custom_metric)
643                    if self.verbose > 0:
644                        if self.custom_metric is not None:
645                            print(
646                                {
647                                    "Model": name,
648                                    "Accuracy": accuracy,
649                                    "Balanced Accuracy": b_accuracy,
650                                    "ROC AUC": roc_auc,
651                                    "F1 Score": f1,
652                                    self.custom_metric.__name__: custom_metric,
653                                    "Time taken": time.time() - start,
654                                }
655                            )
656                        else:
657                            print(
658                                {
659                                    "Model": name,
660                                    "Accuracy": accuracy,
661                                    "Balanced Accuracy": b_accuracy,
662                                    "ROC AUC": roc_auc,
663                                    "F1 Score": f1,
664                                    "Time taken": time.time() - start,
665                                }
666                            )
667                    if self.predictions:
668                        predictions[name] = y_pred
669                except Exception as exception:
670                    if self.ignore_warnings is False:
671                        print(name + " model failed to execute")
672                        print(exception)
673
674        if self.custom_metric is None:
675            scores = pd.DataFrame(
676                {
677                    "Model": names,
678                    "Accuracy": Accuracy,
679                    "Balanced Accuracy": B_Accuracy,
680                    "ROC AUC": ROC_AUC,
681                    "F1 Score": F1,
682                    "Time Taken": TIME,
683                }
684            )
685        else:
686            scores = pd.DataFrame(
687                {
688                    "Model": names,
689                    "Accuracy": Accuracy,
690                    "Balanced Accuracy": B_Accuracy,
691                    "ROC AUC": ROC_AUC,
692                    "F1 Score": F1,
693                    "Custom metric": CUSTOM_METRIC,
694                    "Time Taken": TIME,
695                }
696            )
697        scores = scores.sort_values(by=self.sort_by, ascending=False).set_index(
698            "Model"
699        )
700
701        self.best_model_ = self.models_[scores.index[0]]
702
703        if self.predictions is True:
704
705            return scores, predictions
706
707        return scores

Fit classifiers to X_train and y_train, predict and score on X_test, y_test.

Parameters:

X_train: array-like,
    Training vectors, where rows is the number of samples
    and columns is the number of features.

X_test: array-like,
    Testing vectors, where rows is the number of samples
    and columns is the number of features.

y_train: array-like,
    Training vectors, where rows is the number of samples
    and columns is the number of features.

y_test: array-like,
    Testing vectors, where rows is the number of samples
    and columns is the number of features.

Returns:

scores: Pandas DataFrame
    Returns metrics of all the models in a Pandas DataFrame.

predictions: Pandas DataFrame
    Returns predictions of all the models in a Pandas DataFrame.
def provide_models(self, X_train, X_test, y_train, y_test):
721    def provide_models(self, X_train, X_test, y_train, y_test):
722        """Returns all the model objects trained. If fit hasn't been called yet,
723        then it's called to return the models.
724
725        Parameters:
726
727        X_train: array-like,
728            Training vectors, where rows is the number of samples
729            and columns is the number of features.
730
731        X_test: array-like,
732            Testing vectors, where rows is the number of samples
733            and columns is the number of features.
734
735        y_train: array-like,
736            Training vectors, where rows is the number of samples
737            and columns is the number of features.
738
739        y_test: array-like,
740            Testing vectors, where rows is the number of samples
741            and columns is the number of features.
742
743        Returns:
744
745            models: dict-object,
746                Returns a dictionary with each model's pipeline as value
747                and key = name of the model.
748        """
749        if len(self.models_.keys()) == 0:
750            self.fit(X_train, X_test, y_train, y_test)
751
752        return self.models_

Returns all the model objects trained. If fit hasn't been called yet, then it's called to return the models.

Parameters:

X_train: array-like, Training vectors, where rows is the number of samples and columns is the number of features.

X_test: array-like, Testing vectors, where rows is the number of samples and columns is the number of features.

y_train: array-like, Training vectors, where rows is the number of samples and columns is the number of features.

y_test: array-like, Testing vectors, where rows is the number of samples and columns is the number of features.

Returns:

models: dict-object,
    Returns a dictionary with each model's pipeline as value
    and key = name of the model.
class LazyDeepRegressor(nnetsauce.custom.custom.Custom, sklearn.base.RegressorMixin):
 90class LazyDeepRegressor(Custom, RegressorMixin):
 91    """
 92        Fitting -- almost -- all the regression algorithms with layers of
 93        nnetsauce's CustomRegressor and returning their scores.
 94
 95    Parameters:
 96
 97        verbose: int, optional (default=0)
 98            Any positive number for verbosity.
 99
100        ignore_warnings: bool, optional (default=True)
101            When set to True, the warning related to algorigms that are not able to run are ignored.
102
103        custom_metric: function, optional (default=None)
104            When function is provided, models are evaluated based on the custom evaluation metric provided.
105
106        predictions: bool, optional (default=False)
107            When set to True, the predictions of all the models models are returned as dataframe.
108
109        sort_by: string, optional (default='RMSE')
110            Sort models by a metric. Available options are 'R-Squared', 'Adjusted R-Squared', 'RMSE', 'Time Taken' and 'Custom Metric'.
111            or a custom metric identified by its name and provided by custom_metric.
112
113        random_state: int, optional (default=42)
114            Reproducibiility seed.
115
116        estimators: list, optional (default='all')
117            list of Estimators names or just 'all' (default='all')
118
119        preprocess: bool
120            preprocessing is done when set to True
121
122        n_jobs : int, when possible, run in parallel
123            For now, only used by individual models that support it.
124
125        n_layers: int, optional (default=3)
126            Number of layers of CustomRegressors to be used.
127
128        All the other parameters are the same as CustomRegressor's.
129
130    Attributes:
131
132        models_: dict-object
133            Returns a dictionary with each model pipeline as value
134            with key as name of models.
135
136        best_model_: object
137            Returns the best model pipeline based on the sort_by metric.
138
139    Examples:
140
141        import nnetsauce as ns
142        import numpy as np
143        from sklearn import datasets
144        from sklearn.utils import shuffle
145
146        diabetes = datasets.load_diabetes()
147        X, y = shuffle(diabetes.data, diabetes.target, random_state=13)
148        X = X.astype(np.float32)
149
150        offset = int(X.shape[0] * 0.9)
151        X_train, y_train = X[:offset], y[:offset]
152        X_test, y_test = X[offset:], y[offset:]
153
154        reg = ns.LazyDeepRegressor(verbose=0, ignore_warnings=False, custom_metric=None)
155        models, predictions = reg.fit(X_train, X_test, y_train, y_test)
156        print(models)
157
158    """
159
160    def __init__(
161        self,
162        verbose=0,
163        ignore_warnings=True,
164        custom_metric=None,
165        predictions=False,
166        sort_by="RMSE",
167        random_state=42,
168        estimators="all",
169        preprocess=False,
170        n_jobs=None,
171        # Defining depth
172        n_layers=3,
173        # CustomRegressor attributes
174        obj=None,
175        n_hidden_features=5,
176        activation_name="relu",
177        a=0.01,
178        nodes_sim="sobol",
179        bias=True,
180        dropout=0,
181        direct_link=True,
182        n_clusters=2,
183        cluster_encode=True,
184        type_clust="kmeans",
185        type_scaling=("std", "std", "std"),
186        col_sample=1,
187        row_sample=1,
188        seed=123,
189        backend="cpu",
190    ):
191        self.verbose = verbose
192        self.ignore_warnings = ignore_warnings
193        self.custom_metric = custom_metric
194        self.predictions = predictions
195        self.sort_by = sort_by
196        self.models_ = {}
197        self.best_model_ = None
198        self.random_state = random_state
199        self.estimators = estimators
200        self.preprocess = preprocess
201        self.n_layers = n_layers - 1
202        self.n_jobs = n_jobs
203        super().__init__(
204            obj=obj,
205            n_hidden_features=n_hidden_features,
206            activation_name=activation_name,
207            a=a,
208            nodes_sim=nodes_sim,
209            bias=bias,
210            dropout=dropout,
211            direct_link=direct_link,
212            n_clusters=n_clusters,
213            cluster_encode=cluster_encode,
214            type_clust=type_clust,
215            type_scaling=type_scaling,
216            col_sample=col_sample,
217            row_sample=row_sample,
218            seed=seed,
219            backend=backend,
220        )
221
222    def fit(self, X_train, X_test, y_train, y_test):
223        """Fit Regression algorithms to X_train and y_train, predict and score on X_test, y_test.
224
225        Parameters:
226
227            X_train : array-like,
228                Training vectors, where rows is the number of samples
229                and columns is the number of features.
230
231            X_test : array-like,
232                Testing vectors, where rows is the number of samples
233                and columns is the number of features.
234
235            y_train : array-like,
236                Training vectors, where rows is the number of samples
237                and columns is the number of features.
238
239            y_test : array-like,
240                Testing vectors, where rows is the number of samples
241                and columns is the number of features.
242
243        Returns:
244        -------
245        scores:  Pandas DataFrame
246            Returns metrics of all the models in a Pandas DataFrame.
247
248        predictions : Pandas DataFrame
249            Returns predictions of all the models in a Pandas DataFrame.
250
251        """
252        R2 = []
253        ADJR2 = []
254        RMSE = []
255        # WIN = []
256        names = []
257        TIME = []
258        predictions = {}
259
260        if self.custom_metric:
261            CUSTOM_METRIC = []
262
263        if isinstance(X_train, np.ndarray):
264            X_train = pd.DataFrame(X_train)
265            X_test = pd.DataFrame(X_test)
266
267        numeric_features = X_train.select_dtypes(include=[np.number]).columns
268        categorical_features = X_train.select_dtypes(include=["object"]).columns
269
270        categorical_low, categorical_high = get_card_split(
271            X_train, categorical_features
272        )
273
274        if self.preprocess is True:
275            preprocessor = ColumnTransformer(
276                transformers=[
277                    ("numeric", numeric_transformer, numeric_features),
278                    (
279                        "categorical_low",
280                        categorical_transformer_low,
281                        categorical_low,
282                    ),
283                    (
284                        "categorical_high",
285                        categorical_transformer_high,
286                        categorical_high,
287                    ),
288                ]
289            )
290
291        # base models
292        try:
293            baseline_names = ["RandomForestRegressor", "XGBRegressor"]
294            baseline_models = [RandomForestRegressor(), xgb.XGBRegressor()]
295        except Exception as exception:
296            baseline_names = ["RandomForestRegressor"]
297            baseline_models = [RandomForestRegressor()]
298
299        for name, model in zip(baseline_names, baseline_models):
300            start = time.time()
301            try:
302                model.fit(X_train, y_train)
303                self.models_[name] = model
304                y_pred = model.predict(X_test)
305                r_squared = r2_score(y_test, y_pred)
306                adj_rsquared = adjusted_rsquared(
307                    r_squared, X_test.shape[0], X_test.shape[1]
308                )
309                rmse = np.sqrt(np.mean((y_test - y_pred) ** 2))
310
311                names.append(name)
312                R2.append(r_squared)
313                ADJR2.append(adj_rsquared)
314                RMSE.append(rmse)
315                TIME.append(time.time() - start)
316
317                if self.custom_metric:
318                    custom_metric = self.custom_metric(y_test, y_pred)
319                    CUSTOM_METRIC.append(custom_metric)
320
321                if self.verbose > 0:
322                    scores_verbose = {
323                        "Model": name,
324                        "R-Squared": r_squared,
325                        "Adjusted R-Squared": adj_rsquared,
326                        "RMSE": rmse,
327                        "Time taken": time.time() - start,
328                    }
329
330                    if self.custom_metric:
331                        scores_verbose[self.custom_metric.__name__] = (
332                            custom_metric
333                        )
334
335                    print(scores_verbose)
336                if self.predictions:
337                    predictions[name] = y_pred
338            except Exception as exception:
339                if self.ignore_warnings is False:
340                    print(name + " model failed to execute")
341                    print(exception)
342
343        if self.estimators == "all":
344            self.regressors = DEEPREGRESSORS
345        else:
346            self.regressors = [
347                ("DeepCustomRegressor(" + est[0] + ")", est[1])
348                for est in all_estimators()
349                if (
350                    issubclass(est[1], RegressorMixin)
351                    and (est[0] in self.estimators)
352                )
353            ]
354
355        if self.preprocess is True:
356
357            for name, model in tqdm(self.regressors):  # do parallel exec
358                start = time.time()
359                try:
360                    if "random_state" in model().get_params().keys():
361                        layer_regr = CustomRegressor(
362                            obj=model(random_state=self.random_state),
363                            n_hidden_features=self.n_hidden_features,
364                            activation_name=self.activation_name,
365                            a=self.a,
366                            nodes_sim=self.nodes_sim,
367                            bias=self.bias,
368                            dropout=self.dropout,
369                            direct_link=self.direct_link,
370                            n_clusters=self.n_clusters,
371                            cluster_encode=self.cluster_encode,
372                            type_clust=self.type_clust,
373                            type_scaling=self.type_scaling,
374                            col_sample=self.col_sample,
375                            row_sample=self.row_sample,
376                            seed=self.seed,
377                            backend=self.backend,
378                        )
379                    else:
380                        layer_regr = CustomRegressor(
381                            obj=model(),
382                            n_hidden_features=self.n_hidden_features,
383                            activation_name=self.activation_name,
384                            a=self.a,
385                            nodes_sim=self.nodes_sim,
386                            bias=self.bias,
387                            dropout=self.dropout,
388                            direct_link=self.direct_link,
389                            n_clusters=self.n_clusters,
390                            cluster_encode=self.cluster_encode,
391                            type_clust=self.type_clust,
392                            type_scaling=self.type_scaling,
393                            col_sample=self.col_sample,
394                            row_sample=self.row_sample,
395                            seed=self.seed,
396                            backend=self.backend,
397                        )
398
399                    for _ in range(self.n_layers):
400                        layer_regr = deepcopy(
401                            CustomRegressor(
402                                obj=layer_regr,
403                                n_hidden_features=self.n_hidden_features,
404                                activation_name=self.activation_name,
405                                a=self.a,
406                                nodes_sim=self.nodes_sim,
407                                bias=self.bias,
408                                dropout=self.dropout,
409                                direct_link=self.direct_link,
410                                n_clusters=self.n_clusters,
411                                cluster_encode=self.cluster_encode,
412                                type_clust=self.type_clust,
413                                type_scaling=self.type_scaling,
414                                col_sample=self.col_sample,
415                                row_sample=self.row_sample,
416                                seed=self.seed,
417                                backend=self.backend,
418                            )
419                        )
420
421                    layer_regr.fit(X_train, y_train)
422
423                    pipe = Pipeline(
424                        steps=[
425                            ("preprocessor", preprocessor),
426                            ("regressor", layer_regr),
427                        ]
428                    )
429
430                    pipe.fit(X_train, y_train)
431
432                    self.models_[name] = pipe
433                    y_pred = pipe.predict(X_test)
434                    r_squared = r2_score(y_test, y_pred)
435                    adj_rsquared = adjusted_rsquared(
436                        r_squared, X_test.shape[0], X_test.shape[1]
437                    )
438                    rmse = np.sqrt(np.mean((y_test - y_pred) ** 2))
439
440                    names.append(name)
441                    R2.append(r_squared)
442                    ADJR2.append(adj_rsquared)
443                    RMSE.append(rmse)
444                    TIME.append(time.time() - start)
445
446                    if self.custom_metric:
447                        custom_metric = self.custom_metric(y_test, y_pred)
448                        CUSTOM_METRIC.append(custom_metric)
449
450                    if self.verbose > 0:
451                        scores_verbose = {
452                            "Model": name,
453                            "R-Squared": r_squared,
454                            "Adjusted R-Squared": adj_rsquared,
455                            "RMSE": rmse,
456                            "Time taken": time.time() - start,
457                        }
458
459                        if self.custom_metric:
460                            scores_verbose[self.custom_metric.__name__] = (
461                                custom_metric
462                            )
463
464                        print(scores_verbose)
465                    if self.predictions:
466                        predictions[name] = y_pred
467                except Exception as exception:
468                    if self.ignore_warnings is False:
469                        print(name + " model failed to execute")
470                        print(exception)
471
472        else:  # no preprocessing
473
474            for name, model in tqdm(self.regressors):  # do parallel exec
475                start = time.time()
476                try:
477                    if "random_state" in model().get_params().keys():
478                        layer_regr = CustomRegressor(
479                            obj=model(random_state=self.random_state),
480                            n_hidden_features=self.n_hidden_features,
481                            activation_name=self.activation_name,
482                            a=self.a,
483                            nodes_sim=self.nodes_sim,
484                            bias=self.bias,
485                            dropout=self.dropout,
486                            direct_link=self.direct_link,
487                            n_clusters=self.n_clusters,
488                            cluster_encode=self.cluster_encode,
489                            type_clust=self.type_clust,
490                            type_scaling=self.type_scaling,
491                            col_sample=self.col_sample,
492                            row_sample=self.row_sample,
493                            seed=self.seed,
494                            backend=self.backend,
495                        )
496                    else:
497                        layer_regr = CustomRegressor(
498                            obj=model(),
499                            n_hidden_features=self.n_hidden_features,
500                            activation_name=self.activation_name,
501                            a=self.a,
502                            nodes_sim=self.nodes_sim,
503                            bias=self.bias,
504                            dropout=self.dropout,
505                            direct_link=self.direct_link,
506                            n_clusters=self.n_clusters,
507                            cluster_encode=self.cluster_encode,
508                            type_clust=self.type_clust,
509                            type_scaling=self.type_scaling,
510                            col_sample=self.col_sample,
511                            row_sample=self.row_sample,
512                            seed=self.seed,
513                            backend=self.backend,
514                        )
515
516                    layer_regr.fit(X_train, y_train)
517
518                    for _ in range(self.n_layers):
519                        layer_regr = deepcopy(
520                            CustomRegressor(
521                                obj=layer_regr,
522                                n_hidden_features=self.n_hidden_features,
523                                activation_name=self.activation_name,
524                                a=self.a,
525                                nodes_sim=self.nodes_sim,
526                                bias=self.bias,
527                                dropout=self.dropout,
528                                direct_link=self.direct_link,
529                                n_clusters=self.n_clusters,
530                                cluster_encode=self.cluster_encode,
531                                type_clust=self.type_clust,
532                                type_scaling=self.type_scaling,
533                                col_sample=self.col_sample,
534                                row_sample=self.row_sample,
535                                seed=self.seed,
536                                backend=self.backend,
537                            )
538                        )
539
540                        # layer_regr.fit(X_train, y_train)
541
542                    layer_regr.fit(X_train, y_train)
543
544                    self.models_[name] = layer_regr
545                    y_pred = layer_regr.predict(X_test)
546
547                    r_squared = r2_score(y_test, y_pred)
548                    adj_rsquared = adjusted_rsquared(
549                        r_squared, X_test.shape[0], X_test.shape[1]
550                    )
551                    rmse = np.sqrt(np.mean((y_test - y_pred) ** 2))
552
553                    names.append(name)
554                    R2.append(r_squared)
555                    ADJR2.append(adj_rsquared)
556                    RMSE.append(rmse)
557                    TIME.append(time.time() - start)
558
559                    if self.custom_metric:
560                        custom_metric = self.custom_metric(y_test, y_pred)
561                        CUSTOM_METRIC.append(custom_metric)
562
563                    if self.verbose > 0:
564                        scores_verbose = {
565                            "Model": name,
566                            "R-Squared": r_squared,
567                            "Adjusted R-Squared": adj_rsquared,
568                            "RMSE": rmse,
569                            "Time taken": time.time() - start,
570                        }
571
572                        if self.custom_metric:
573                            scores_verbose[self.custom_metric.__name__] = (
574                                custom_metric
575                            )
576
577                        print(scores_verbose)
578                    if self.predictions:
579                        predictions[name] = y_pred
580                except Exception as exception:
581                    if self.ignore_warnings is False:
582                        print(name + " model failed to execute")
583                        print(exception)
584
585        scores = {
586            "Model": names,
587            "Adjusted R-Squared": ADJR2,
588            "R-Squared": R2,
589            "RMSE": RMSE,
590            "Time Taken": TIME,
591        }
592
593        if self.custom_metric:
594            scores["Custom metric"] = CUSTOM_METRIC
595
596        scores = pd.DataFrame(scores)
597        scores = scores.sort_values(by=self.sort_by, ascending=True).set_index(
598            "Model"
599        )
600
601        self.best_model_ = self.models_[scores.index[0]]
602
603        if self.predictions is True:
604
605            return scores, predictions
606
607        return scores
608
609    def get_best_model(self):
610        """
611        This function returns the best model pipeline based on the sort_by metric.
612
613        Returns:
614
615            best_model: object,
616                Returns the best model pipeline based on the sort_by metric.
617
618        """
619        return self.best_model_
620
621    def provide_models(self, X_train, X_test, y_train, y_test):
622        """
623        This function returns all the model objects trained in fit function.
624        If fit is not called already, then we call fit and then return the models.
625
626        Parameters:
627
628            X_train : array-like,
629                Training vectors, where rows is the number of samples
630                and columns is the number of features.
631
632            X_test : array-like,
633                Testing vectors, where rows is the number of samples
634                and columns is the number of features.
635
636            y_train : array-like,
637                Training vectors, where rows is the number of samples
638                and columns is the number of features.
639
640            y_test : array-like,
641                Testing vectors, where rows is the number of samples
642                and columns is the number of features.
643
644        Returns:
645
646            models: dict-object,
647                Returns a dictionary with each model pipeline as value
648                with key as name of models.
649
650        """
651        if len(self.models_.keys()) == 0:
652            self.fit(X_train, X_test, y_train, y_test)
653
654        return self.models_

Fitting -- almost -- all the regression algorithms with layers of nnetsauce's CustomRegressor and returning their scores.

Parameters:

verbose: int, optional (default=0)
    Any positive number for verbosity.

ignore_warnings: bool, optional (default=True)
    When set to True, the warning related to algorigms that are not able to run are ignored.

custom_metric: function, optional (default=None)
    When function is provided, models are evaluated based on the custom evaluation metric provided.

predictions: bool, optional (default=False)
    When set to True, the predictions of all the models models are returned as dataframe.

sort_by: string, optional (default='RMSE')
    Sort models by a metric. Available options are 'R-Squared', 'Adjusted R-Squared', 'RMSE', 'Time Taken' and 'Custom Metric'.
    or a custom metric identified by its name and provided by custom_metric.

random_state: int, optional (default=42)
    Reproducibiility seed.

estimators: list, optional (default='all')
    list of Estimators names or just 'all' (default='all')

preprocess: bool
    preprocessing is done when set to True

n_jobs : int, when possible, run in parallel
    For now, only used by individual models that support it.

n_layers: int, optional (default=3)
    Number of layers of CustomRegressors to be used.

All the other parameters are the same as CustomRegressor's.

Attributes:

models_: dict-object
    Returns a dictionary with each model pipeline as value
    with key as name of models.

best_model_: object
    Returns the best model pipeline based on the sort_by metric.

Examples:

import nnetsauce as ns
import numpy as np
from sklearn import datasets
from sklearn.utils import shuffle

diabetes = datasets.load_diabetes()
X, y = shuffle(diabetes.data, diabetes.target, random_state=13)
X = X.astype(np.float32)

offset = int(X.shape[0] * 0.9)
X_train, y_train = X[:offset], y[:offset]
X_test, y_test = X[offset:], y[offset:]

reg = ns.LazyDeepRegressor(verbose=0, ignore_warnings=False, custom_metric=None)
models, predictions = reg.fit(X_train, X_test, y_train, y_test)
print(models)
def fit(self, X_train, X_test, y_train, y_test):
222    def fit(self, X_train, X_test, y_train, y_test):
223        """Fit Regression algorithms to X_train and y_train, predict and score on X_test, y_test.
224
225        Parameters:
226
227            X_train : array-like,
228                Training vectors, where rows is the number of samples
229                and columns is the number of features.
230
231            X_test : array-like,
232                Testing vectors, where rows is the number of samples
233                and columns is the number of features.
234
235            y_train : array-like,
236                Training vectors, where rows is the number of samples
237                and columns is the number of features.
238
239            y_test : array-like,
240                Testing vectors, where rows is the number of samples
241                and columns is the number of features.
242
243        Returns:
244        -------
245        scores:  Pandas DataFrame
246            Returns metrics of all the models in a Pandas DataFrame.
247
248        predictions : Pandas DataFrame
249            Returns predictions of all the models in a Pandas DataFrame.
250
251        """
252        R2 = []
253        ADJR2 = []
254        RMSE = []
255        # WIN = []
256        names = []
257        TIME = []
258        predictions = {}
259
260        if self.custom_metric:
261            CUSTOM_METRIC = []
262
263        if isinstance(X_train, np.ndarray):
264            X_train = pd.DataFrame(X_train)
265            X_test = pd.DataFrame(X_test)
266
267        numeric_features = X_train.select_dtypes(include=[np.number]).columns
268        categorical_features = X_train.select_dtypes(include=["object"]).columns
269
270        categorical_low, categorical_high = get_card_split(
271            X_train, categorical_features
272        )
273
274        if self.preprocess is True:
275            preprocessor = ColumnTransformer(
276                transformers=[
277                    ("numeric", numeric_transformer, numeric_features),
278                    (
279                        "categorical_low",
280                        categorical_transformer_low,
281                        categorical_low,
282                    ),
283                    (
284                        "categorical_high",
285                        categorical_transformer_high,
286                        categorical_high,
287                    ),
288                ]
289            )
290
291        # base models
292        try:
293            baseline_names = ["RandomForestRegressor", "XGBRegressor"]
294            baseline_models = [RandomForestRegressor(), xgb.XGBRegressor()]
295        except Exception as exception:
296            baseline_names = ["RandomForestRegressor"]
297            baseline_models = [RandomForestRegressor()]
298
299        for name, model in zip(baseline_names, baseline_models):
300            start = time.time()
301            try:
302                model.fit(X_train, y_train)
303                self.models_[name] = model
304                y_pred = model.predict(X_test)
305                r_squared = r2_score(y_test, y_pred)
306                adj_rsquared = adjusted_rsquared(
307                    r_squared, X_test.shape[0], X_test.shape[1]
308                )
309                rmse = np.sqrt(np.mean((y_test - y_pred) ** 2))
310
311                names.append(name)
312                R2.append(r_squared)
313                ADJR2.append(adj_rsquared)
314                RMSE.append(rmse)
315                TIME.append(time.time() - start)
316
317                if self.custom_metric:
318                    custom_metric = self.custom_metric(y_test, y_pred)
319                    CUSTOM_METRIC.append(custom_metric)
320
321                if self.verbose > 0:
322                    scores_verbose = {
323                        "Model": name,
324                        "R-Squared": r_squared,
325                        "Adjusted R-Squared": adj_rsquared,
326                        "RMSE": rmse,
327                        "Time taken": time.time() - start,
328                    }
329
330                    if self.custom_metric:
331                        scores_verbose[self.custom_metric.__name__] = (
332                            custom_metric
333                        )
334
335                    print(scores_verbose)
336                if self.predictions:
337                    predictions[name] = y_pred
338            except Exception as exception:
339                if self.ignore_warnings is False:
340                    print(name + " model failed to execute")
341                    print(exception)
342
343        if self.estimators == "all":
344            self.regressors = DEEPREGRESSORS
345        else:
346            self.regressors = [
347                ("DeepCustomRegressor(" + est[0] + ")", est[1])
348                for est in all_estimators()
349                if (
350                    issubclass(est[1], RegressorMixin)
351                    and (est[0] in self.estimators)
352                )
353            ]
354
355        if self.preprocess is True:
356
357            for name, model in tqdm(self.regressors):  # do parallel exec
358                start = time.time()
359                try:
360                    if "random_state" in model().get_params().keys():
361                        layer_regr = CustomRegressor(
362                            obj=model(random_state=self.random_state),
363                            n_hidden_features=self.n_hidden_features,
364                            activation_name=self.activation_name,
365                            a=self.a,
366                            nodes_sim=self.nodes_sim,
367                            bias=self.bias,
368                            dropout=self.dropout,
369                            direct_link=self.direct_link,
370                            n_clusters=self.n_clusters,
371                            cluster_encode=self.cluster_encode,
372                            type_clust=self.type_clust,
373                            type_scaling=self.type_scaling,
374                            col_sample=self.col_sample,
375                            row_sample=self.row_sample,
376                            seed=self.seed,
377                            backend=self.backend,
378                        )
379                    else:
380                        layer_regr = CustomRegressor(
381                            obj=model(),
382                            n_hidden_features=self.n_hidden_features,
383                            activation_name=self.activation_name,
384                            a=self.a,
385                            nodes_sim=self.nodes_sim,
386                            bias=self.bias,
387                            dropout=self.dropout,
388                            direct_link=self.direct_link,
389                            n_clusters=self.n_clusters,
390                            cluster_encode=self.cluster_encode,
391                            type_clust=self.type_clust,
392                            type_scaling=self.type_scaling,
393                            col_sample=self.col_sample,
394                            row_sample=self.row_sample,
395                            seed=self.seed,
396                            backend=self.backend,
397                        )
398
399                    for _ in range(self.n_layers):
400                        layer_regr = deepcopy(
401                            CustomRegressor(
402                                obj=layer_regr,
403                                n_hidden_features=self.n_hidden_features,
404                                activation_name=self.activation_name,
405                                a=self.a,
406                                nodes_sim=self.nodes_sim,
407                                bias=self.bias,
408                                dropout=self.dropout,
409                                direct_link=self.direct_link,
410                                n_clusters=self.n_clusters,
411                                cluster_encode=self.cluster_encode,
412                                type_clust=self.type_clust,
413                                type_scaling=self.type_scaling,
414                                col_sample=self.col_sample,
415                                row_sample=self.row_sample,
416                                seed=self.seed,
417                                backend=self.backend,
418                            )
419                        )
420
421                    layer_regr.fit(X_train, y_train)
422
423                    pipe = Pipeline(
424                        steps=[
425                            ("preprocessor", preprocessor),
426                            ("regressor", layer_regr),
427                        ]
428                    )
429
430                    pipe.fit(X_train, y_train)
431
432                    self.models_[name] = pipe
433                    y_pred = pipe.predict(X_test)
434                    r_squared = r2_score(y_test, y_pred)
435                    adj_rsquared = adjusted_rsquared(
436                        r_squared, X_test.shape[0], X_test.shape[1]
437                    )
438                    rmse = np.sqrt(np.mean((y_test - y_pred) ** 2))
439
440                    names.append(name)
441                    R2.append(r_squared)
442                    ADJR2.append(adj_rsquared)
443                    RMSE.append(rmse)
444                    TIME.append(time.time() - start)
445
446                    if self.custom_metric:
447                        custom_metric = self.custom_metric(y_test, y_pred)
448                        CUSTOM_METRIC.append(custom_metric)
449
450                    if self.verbose > 0:
451                        scores_verbose = {
452                            "Model": name,
453                            "R-Squared": r_squared,
454                            "Adjusted R-Squared": adj_rsquared,
455                            "RMSE": rmse,
456                            "Time taken": time.time() - start,
457                        }
458
459                        if self.custom_metric:
460                            scores_verbose[self.custom_metric.__name__] = (
461                                custom_metric
462                            )
463
464                        print(scores_verbose)
465                    if self.predictions:
466                        predictions[name] = y_pred
467                except Exception as exception:
468                    if self.ignore_warnings is False:
469                        print(name + " model failed to execute")
470                        print(exception)
471
472        else:  # no preprocessing
473
474            for name, model in tqdm(self.regressors):  # do parallel exec
475                start = time.time()
476                try:
477                    if "random_state" in model().get_params().keys():
478                        layer_regr = CustomRegressor(
479                            obj=model(random_state=self.random_state),
480                            n_hidden_features=self.n_hidden_features,
481                            activation_name=self.activation_name,
482                            a=self.a,
483                            nodes_sim=self.nodes_sim,
484                            bias=self.bias,
485                            dropout=self.dropout,
486                            direct_link=self.direct_link,
487                            n_clusters=self.n_clusters,
488                            cluster_encode=self.cluster_encode,
489                            type_clust=self.type_clust,
490                            type_scaling=self.type_scaling,
491                            col_sample=self.col_sample,
492                            row_sample=self.row_sample,
493                            seed=self.seed,
494                            backend=self.backend,
495                        )
496                    else:
497                        layer_regr = CustomRegressor(
498                            obj=model(),
499                            n_hidden_features=self.n_hidden_features,
500                            activation_name=self.activation_name,
501                            a=self.a,
502                            nodes_sim=self.nodes_sim,
503                            bias=self.bias,
504                            dropout=self.dropout,
505                            direct_link=self.direct_link,
506                            n_clusters=self.n_clusters,
507                            cluster_encode=self.cluster_encode,
508                            type_clust=self.type_clust,
509                            type_scaling=self.type_scaling,
510                            col_sample=self.col_sample,
511                            row_sample=self.row_sample,
512                            seed=self.seed,
513                            backend=self.backend,
514                        )
515
516                    layer_regr.fit(X_train, y_train)
517
518                    for _ in range(self.n_layers):
519                        layer_regr = deepcopy(
520                            CustomRegressor(
521                                obj=layer_regr,
522                                n_hidden_features=self.n_hidden_features,
523                                activation_name=self.activation_name,
524                                a=self.a,
525                                nodes_sim=self.nodes_sim,
526                                bias=self.bias,
527                                dropout=self.dropout,
528                                direct_link=self.direct_link,
529                                n_clusters=self.n_clusters,
530                                cluster_encode=self.cluster_encode,
531                                type_clust=self.type_clust,
532                                type_scaling=self.type_scaling,
533                                col_sample=self.col_sample,
534                                row_sample=self.row_sample,
535                                seed=self.seed,
536                                backend=self.backend,
537                            )
538                        )
539
540                        # layer_regr.fit(X_train, y_train)
541
542                    layer_regr.fit(X_train, y_train)
543
544                    self.models_[name] = layer_regr
545                    y_pred = layer_regr.predict(X_test)
546
547                    r_squared = r2_score(y_test, y_pred)
548                    adj_rsquared = adjusted_rsquared(
549                        r_squared, X_test.shape[0], X_test.shape[1]
550                    )
551                    rmse = np.sqrt(np.mean((y_test - y_pred) ** 2))
552
553                    names.append(name)
554                    R2.append(r_squared)
555                    ADJR2.append(adj_rsquared)
556                    RMSE.append(rmse)
557                    TIME.append(time.time() - start)
558
559                    if self.custom_metric:
560                        custom_metric = self.custom_metric(y_test, y_pred)
561                        CUSTOM_METRIC.append(custom_metric)
562
563                    if self.verbose > 0:
564                        scores_verbose = {
565                            "Model": name,
566                            "R-Squared": r_squared,
567                            "Adjusted R-Squared": adj_rsquared,
568                            "RMSE": rmse,
569                            "Time taken": time.time() - start,
570                        }
571
572                        if self.custom_metric:
573                            scores_verbose[self.custom_metric.__name__] = (
574                                custom_metric
575                            )
576
577                        print(scores_verbose)
578                    if self.predictions:
579                        predictions[name] = y_pred
580                except Exception as exception:
581                    if self.ignore_warnings is False:
582                        print(name + " model failed to execute")
583                        print(exception)
584
585        scores = {
586            "Model": names,
587            "Adjusted R-Squared": ADJR2,
588            "R-Squared": R2,
589            "RMSE": RMSE,
590            "Time Taken": TIME,
591        }
592
593        if self.custom_metric:
594            scores["Custom metric"] = CUSTOM_METRIC
595
596        scores = pd.DataFrame(scores)
597        scores = scores.sort_values(by=self.sort_by, ascending=True).set_index(
598            "Model"
599        )
600
601        self.best_model_ = self.models_[scores.index[0]]
602
603        if self.predictions is True:
604
605            return scores, predictions
606
607        return scores

Fit Regression algorithms to X_train and y_train, predict and score on X_test, y_test.

Parameters:

X_train : array-like,
    Training vectors, where rows is the number of samples
    and columns is the number of features.

X_test : array-like,
    Testing vectors, where rows is the number of samples
    and columns is the number of features.

y_train : array-like,
    Training vectors, where rows is the number of samples
    and columns is the number of features.

y_test : array-like,
    Testing vectors, where rows is the number of samples
    and columns is the number of features.

Returns:

scores: Pandas DataFrame Returns metrics of all the models in a Pandas DataFrame.

predictions : Pandas DataFrame Returns predictions of all the models in a Pandas DataFrame.

def provide_models(self, X_train, X_test, y_train, y_test):
621    def provide_models(self, X_train, X_test, y_train, y_test):
622        """
623        This function returns all the model objects trained in fit function.
624        If fit is not called already, then we call fit and then return the models.
625
626        Parameters:
627
628            X_train : array-like,
629                Training vectors, where rows is the number of samples
630                and columns is the number of features.
631
632            X_test : array-like,
633                Testing vectors, where rows is the number of samples
634                and columns is the number of features.
635
636            y_train : array-like,
637                Training vectors, where rows is the number of samples
638                and columns is the number of features.
639
640            y_test : array-like,
641                Testing vectors, where rows is the number of samples
642                and columns is the number of features.
643
644        Returns:
645
646            models: dict-object,
647                Returns a dictionary with each model pipeline as value
648                with key as name of models.
649
650        """
651        if len(self.models_.keys()) == 0:
652            self.fit(X_train, X_test, y_train, y_test)
653
654        return self.models_

This function returns all the model objects trained in fit function. If fit is not called already, then we call fit and then return the models.

Parameters:

X_train : array-like,
    Training vectors, where rows is the number of samples
    and columns is the number of features.

X_test : array-like,
    Testing vectors, where rows is the number of samples
    and columns is the number of features.

y_train : array-like,
    Training vectors, where rows is the number of samples
    and columns is the number of features.

y_test : array-like,
    Testing vectors, where rows is the number of samples
    and columns is the number of features.

Returns:

models: dict-object,
    Returns a dictionary with each model pipeline as value
    with key as name of models.
class LazyMTS(nnetsauce.LazyDeepMTS):
1020class LazyMTS(LazyDeepMTS):
1021    """
1022    Fitting -- almost -- all the regression algorithms to multivariate time series
1023    and returning their scores (no layers).
1024
1025    Parameters:
1026
1027        verbose: int, optional (default=0)
1028            Any positive number for verbosity.
1029
1030        ignore_warnings: bool, optional (default=True)
1031            When set to True, the warning related to algorigms that are not
1032            able to run are ignored.
1033
1034        custom_metric: function, optional (default=None)
1035            When function is provided, models are evaluated based on the custom
1036              evaluation metric provided.
1037
1038        predictions: bool, optional (default=False)
1039            When set to True, the predictions of all the models models are returned as dataframe.
1040
1041        sort_by: string, optional (default='RMSE')
1042            Sort models by a metric. Available options are 'RMSE', 'MAE', 'MPL', 'MPE', 'MAPE',
1043            'R-Squared', 'Adjusted R-Squared' or a custom metric identified by its name and
1044            provided by custom_metric.
1045
1046        random_state: int, optional (default=42)
1047            Reproducibiility seed.
1048
1049        estimators: list, optional (default='all')
1050            list of Estimators (regression algorithms) names or just 'all' (default='all')
1051
1052        preprocess: bool, preprocessing is done when set to True
1053
1054        h: int, optional (default=None)
1055            Number of steps ahead to predict (when used, must be > 0 and < X_test.shape[0]).
1056
1057        All the other parameters are the same as MTS's.
1058
1059    Attributes:
1060
1061        models_: dict-object
1062            Returns a dictionary with each model pipeline as value
1063            with key as name of models.
1064
1065        best_model_: object
1066            Returns the best model pipeline based on the sort_by metric.
1067
1068    Examples:
1069
1070        See https://thierrymoudiki.github.io/blog/2023/10/29/python/quasirandomizednn/MTS-LazyPredict
1071
1072    """
1073
1074    def __init__(
1075        self,
1076        verbose=0,
1077        ignore_warnings=True,
1078        custom_metric=None,
1079        predictions=False,
1080        sort_by=None,  # leave it as is
1081        random_state=42,
1082        estimators="all",
1083        preprocess=False,
1084        h=None,
1085        # MTS attributes
1086        obj=None,
1087        n_hidden_features=5,
1088        activation_name="relu",
1089        a=0.01,
1090        nodes_sim="sobol",
1091        bias=True,
1092        dropout=0,
1093        direct_link=True,
1094        n_clusters=2,
1095        cluster_encode=True,
1096        type_clust="kmeans",
1097        type_scaling=("std", "std", "std"),
1098        lags=15,
1099        type_pi="scp2-kde",
1100        block_size=None,
1101        replications=None,
1102        kernel=None,
1103        agg="mean",
1104        seed=123,
1105        backend="cpu",
1106        show_progress=False,
1107    ):
1108        super().__init__(
1109            verbose=verbose,
1110            ignore_warnings=ignore_warnings,
1111            custom_metric=custom_metric,
1112            predictions=predictions,
1113            sort_by=sort_by,
1114            random_state=random_state,
1115            estimators=estimators,
1116            preprocess=preprocess,
1117            n_layers=1,
1118            h=h,
1119            obj=obj,
1120            n_hidden_features=n_hidden_features,
1121            activation_name=activation_name,
1122            a=a,
1123            nodes_sim=nodes_sim,
1124            bias=bias,
1125            dropout=dropout,
1126            direct_link=direct_link,
1127            n_clusters=n_clusters,
1128            cluster_encode=cluster_encode,
1129            type_clust=type_clust,
1130            type_scaling=type_scaling,
1131            lags=lags,
1132            type_pi=type_pi,
1133            block_size=block_size,
1134            replications=replications,
1135            kernel=kernel,
1136            agg=agg,
1137            seed=seed,
1138            backend=backend,
1139            show_progress=show_progress,
1140        )

Fitting -- almost -- all the regression algorithms to multivariate time series and returning their scores (no layers).

Parameters:

verbose: int, optional (default=0)
    Any positive number for verbosity.

ignore_warnings: bool, optional (default=True)
    When set to True, the warning related to algorigms that are not
    able to run are ignored.

custom_metric: function, optional (default=None)
    When function is provided, models are evaluated based on the custom
      evaluation metric provided.

predictions: bool, optional (default=False)
    When set to True, the predictions of all the models models are returned as dataframe.

sort_by: string, optional (default='RMSE')
    Sort models by a metric. Available options are 'RMSE', 'MAE', 'MPL', 'MPE', 'MAPE',
    'R-Squared', 'Adjusted R-Squared' or a custom metric identified by its name and
    provided by custom_metric.

random_state: int, optional (default=42)
    Reproducibiility seed.

estimators: list, optional (default='all')
    list of Estimators (regression algorithms) names or just 'all' (default='all')

preprocess: bool, preprocessing is done when set to True

h: int, optional (default=None)
    Number of steps ahead to predict (when used, must be > 0 and < X_test.shape[0]).

All the other parameters are the same as MTS's.

Attributes:

models_: dict-object
    Returns a dictionary with each model pipeline as value
    with key as name of models.

best_model_: object
    Returns the best model pipeline based on the sort_by metric.

Examples:

See https://thierrymoudiki.github.io/blog/2023/10/29/python/quasirandomizednn/MTS-LazyPredict
class LazyDeepMTS(nnetsauce.MTS):
 104class LazyDeepMTS(MTS):
 105    """
 106
 107    Fitting -- almost -- all the regression algorithms with layers of
 108    nnetsauce's CustomRegressor to multivariate time series
 109    and returning their scores.
 110
 111    Parameters:
 112
 113        verbose: int, optional (default=0)
 114            Any positive number for verbosity.
 115
 116        ignore_warnings: bool, optional (default=True)
 117            When set to True, the warning related to algorigms that are not
 118            able to run are ignored.
 119
 120        custom_metric: function, optional (default=None)
 121            When function is provided, models are evaluated based on the custom
 122              evaluation metric provided.
 123
 124        predictions: bool, optional (default=False)
 125            When set to True, the predictions of all the models models are returned as dataframe.
 126
 127        sort_by: string, optional (default='RMSE')
 128            Sort models by a metric. Available options are 'RMSE', 'MAE', 'MPL', 'MPE', 'MAPE',
 129            'R-Squared', 'Adjusted R-Squared' or a custom metric identified by its name and
 130            provided by custom_metric.
 131
 132        random_state: int, optional (default=42)
 133            Reproducibiility seed.
 134
 135        estimators: list, optional (default='all')
 136            list of Estimators (regression algorithms) names or just 'all' (default='all')
 137
 138        preprocess: bool, preprocessing is done when set to True
 139
 140        n_layers: int, optional (default=1)
 141            Number of layers in the network. When set to 1, the model is equivalent to a MTS.
 142
 143        h: int, optional (default=None)
 144            Number of steps ahead to predict (when used, must be > 0 and < X_test.shape[0]).
 145
 146        All the other parameters are the same as MTS's.
 147
 148    Attributes:
 149
 150        models_: dict-object
 151            Returns a dictionary with each model pipeline as value
 152            with key as name of models.
 153
 154        best_model_: object
 155            Returns the best model pipeline based on the sort_by metric.
 156
 157    Examples:
 158
 159        See https://thierrymoudiki.github.io/blog/2023/10/29/python/quasirandomizednn/MTS-LazyPredict
 160
 161    """
 162
 163    def __init__(
 164        self,
 165        verbose=0,
 166        ignore_warnings=True,
 167        custom_metric=None,
 168        predictions=False,
 169        sort_by=None,  # leave it as is
 170        random_state=42,
 171        estimators="all",
 172        preprocess=False,
 173        n_layers=1,
 174        h=None,
 175        # MTS attributes
 176        obj=None,
 177        n_hidden_features=5,
 178        activation_name="relu",
 179        a=0.01,
 180        nodes_sim="sobol",
 181        bias=True,
 182        dropout=0,
 183        direct_link=True,
 184        n_clusters=2,
 185        cluster_encode=True,
 186        type_clust="kmeans",
 187        type_scaling=("std", "std", "std"),
 188        lags=15,
 189        type_pi="scp2-kde",
 190        block_size=None,
 191        replications=None,
 192        kernel=None,
 193        agg="mean",
 194        seed=123,
 195        backend="cpu",
 196        show_progress=False,
 197    ):
 198        self.verbose = verbose
 199        self.ignore_warnings = ignore_warnings
 200        self.custom_metric = custom_metric
 201        self.predictions = predictions
 202        self.sort_by = sort_by
 203        self.models_ = {}
 204        self.best_model_ = None
 205        self.random_state = random_state
 206        self.estimators = estimators
 207        self.preprocess = preprocess
 208        self.n_layers = n_layers
 209        self.h = h
 210        super().__init__(
 211            obj=obj,
 212            n_hidden_features=n_hidden_features,
 213            activation_name=activation_name,
 214            a=a,
 215            nodes_sim=nodes_sim,
 216            bias=bias,
 217            dropout=dropout,
 218            direct_link=direct_link,
 219            n_clusters=n_clusters,
 220            cluster_encode=cluster_encode,
 221            type_clust=type_clust,
 222            type_scaling=type_scaling,
 223            seed=seed,
 224            backend=backend,
 225            lags=lags,
 226            type_pi=type_pi,
 227            block_size=block_size,
 228            replications=replications,
 229            kernel=kernel,
 230            agg=agg,
 231            verbose=verbose,
 232            show_progress=show_progress,
 233        )
 234        if self.replications is not None or self.type_pi == "gaussian":
 235            if self.sort_by is None:
 236                self.sort_by = "WINKLERSCORE"
 237        else:
 238            if self.sort_by is None:
 239                self.sort_by = "RMSE"
 240
 241    def fit(self, X_train, X_test, xreg=None, per_series=False, **kwargs):
 242        """Fit Regression algorithms to X_train, predict and score on X_test.
 243
 244        Parameters:
 245
 246            X_train: array-like or data frame,
 247                Training vectors, where rows is the number of samples
 248                and columns is the number of features.
 249
 250            X_test: array-like or data frame,
 251                Testing vectors, where rows is the number of samples
 252                and columns is the number of features.
 253
 254            xreg: array-like, optional (default=None)
 255                Additional (external) regressors to be passed to self.obj
 256                xreg must be in 'increasing' order (most recent observations last)
 257
 258            per_series: bool, optional (default=False)
 259                When set to True, the metrics are computed series by series.
 260
 261            **kwargs: dict, optional (default=None)
 262                Additional parameters to be passed to `fit` method of `obj`.
 263
 264        Returns:
 265
 266            scores: Pandas DataFrame
 267                Returns metrics of all the models in a Pandas DataFrame.
 268
 269            predictions: Pandas DataFrame
 270                Returns predictions of all the models in a Pandas DataFrame.
 271
 272        """
 273        R2 = []
 274        ADJR2 = []
 275        ME = []
 276        MPL = []
 277        RMSE = []
 278        MAE = []
 279        MPE = []
 280        MAPE = []
 281        WINKLERSCORE = []
 282        COVERAGE = []
 283
 284        # WIN = []
 285        names = []
 286        TIME = []
 287        predictions = {}
 288
 289        if self.custom_metric is not None:
 290            CUSTOM_METRIC = []
 291
 292        if self.h is None:
 293            assert X_test is not None, "If h is None, X_test must be provided."
 294
 295        if isinstance(X_train, np.ndarray):
 296            X_train = pd.DataFrame(X_train)
 297            X_test = pd.DataFrame(X_test)
 298
 299        self.series_names = X_train.columns.tolist()
 300
 301        X_train = convert_df_to_numeric(X_train)
 302        X_test = convert_df_to_numeric(X_test)
 303
 304        numeric_features = X_train.select_dtypes(include=[np.number]).columns
 305        categorical_features = X_train.select_dtypes(include=["object"]).columns
 306
 307        categorical_low, categorical_high = get_card_split(
 308            X_train, categorical_features
 309        )
 310
 311        if self.preprocess:
 312            preprocessor = ColumnTransformer(
 313                transformers=[
 314                    ("numeric", numeric_transformer, numeric_features),
 315                    (
 316                        "categorical_low",
 317                        categorical_transformer_low,
 318                        categorical_low,
 319                    ),
 320                    (
 321                        "categorical_high",
 322                        categorical_transformer_high,
 323                        categorical_high,
 324                    ),
 325                ]
 326            )
 327
 328        # baselines (Classical MTS) ----
 329        for i, name in enumerate(["ARIMA", "ETS", "Theta", "VAR", "VECM"]):
 330            try:
 331                start = time.time()
 332                regr = ClassicalMTS(model=name)
 333                regr.fit(X_train, **kwargs)
 334                self.models_[name] = regr
 335                if self.h is None:
 336                    X_pred = regr.predict(h=X_test.shape[0], **kwargs)
 337                else:
 338                    assert self.h > 0, "h must be > 0"
 339                    X_pred = regr.predict(h=self.h, **kwargs)
 340                    try:
 341                        X_test = X_test[0: self.h, :]
 342                    except Exception as e:
 343                        X_test = X_test.iloc[0: self.h, :]
 344
 345                print(f"X_test: {X_test}")
 346                print(f"X_pred: {X_pred}")
 347                rmse = mean_errors(
 348                    actual=X_test,
 349                    pred=X_pred,
 350                    scoring="root_mean_squared_error",
 351                    per_series=per_series,
 352                )
 353                mae = mean_errors(
 354                    actual=X_test,
 355                    pred=X_pred,
 356                    scoring="mean_absolute_error",
 357                    per_series=per_series,
 358                )
 359                mpl = mean_errors(
 360                    actual=X_test,
 361                    pred=X_pred,
 362                    scoring="mean_pinball_loss",
 363                    per_series=per_series,
 364                )
 365            except Exception:
 366
 367                continue
 368
 369            names.append(name)
 370            RMSE.append(rmse)
 371            MAE.append(mae)
 372            MPL.append(mpl)
 373
 374            if self.custom_metric is not None:
 375                try:
 376                    if self.h is None:
 377                        custom_metric = self.custom_metric(X_test, X_pred)
 378                    else:
 379                        custom_metric = self.custom_metric(X_test_h, X_pred)
 380                    CUSTOM_METRIC.append(custom_metric)
 381                except Exception as e:
 382                    custom_metric = np.iinfo(np.float32).max
 383                    CUSTOM_METRIC.append(np.iinfo(np.float32).max)
 384
 385            if (self.replications is not None) or (self.type_pi == "gaussian"):
 386                if per_series == False:
 387                    winklerscore = winkler_score(
 388                        obj=X_pred, actual=X_test, level=95
 389                    )
 390                    coveragecalc = coverage(X_pred, X_test, level=95)
 391                else:
 392                    winklerscore = winkler_score(
 393                        obj=X_pred, actual=X_test, level=95, per_series=True
 394                    )
 395                    coveragecalc = coverage(
 396                        X_pred, X_test, level=95, per_series=True
 397                    )
 398                WINKLERSCORE.append(winklerscore)
 399                COVERAGE.append(coveragecalc)
 400            TIME.append(time.time() - start)
 401
 402        if self.estimators == "all":
 403            if self.n_layers <= 1:
 404                self.regressors = REGRESSORSMTS
 405            else:
 406                self.regressors = DEEPREGRESSORSMTS
 407        else:
 408            if self.n_layers <= 1:
 409                self.regressors = [
 410                    ("MTS(" + est[0] + ")", est[1])
 411                    for est in all_estimators()
 412                    if (
 413                        issubclass(est[1], RegressorMixin)
 414                        and (est[0] in self.estimators)
 415                    )
 416                ]
 417            else:  # self.n_layers > 1
 418                self.regressors = [
 419                    ("DeepMTS(" + est[0] + ")", est[1])
 420                    for est in all_estimators()
 421                    if (
 422                        issubclass(est[1], RegressorMixin)
 423                        and (est[0] in self.estimators)
 424                    )
 425                ]
 426
 427        if self.preprocess is True:
 428            for name, model in tqdm(self.regressors):  # do parallel exec
 429                start = time.time()
 430                try:
 431                    if "random_state" in model().get_params().keys():
 432                        pipe = Pipeline(
 433                            steps=[
 434                                ("preprocessor", preprocessor),
 435                                (
 436                                    "regressor",
 437                                    DeepMTS(
 438                                        obj=model(
 439                                            random_state=self.random_state,
 440                                            **kwargs,
 441                                        ),
 442                                        n_layers=self.n_layers,
 443                                        n_hidden_features=self.n_hidden_features,
 444                                        activation_name=self.activation_name,
 445                                        a=self.a,
 446                                        nodes_sim=self.nodes_sim,
 447                                        bias=self.bias,
 448                                        dropout=self.dropout,
 449                                        direct_link=self.direct_link,
 450                                        n_clusters=self.n_clusters,
 451                                        cluster_encode=self.cluster_encode,
 452                                        type_clust=self.type_clust,
 453                                        type_scaling=self.type_scaling,
 454                                        lags=self.lags,
 455                                        type_pi=self.type_pi,
 456                                        block_size=self.block_size,
 457                                        replications=self.replications,
 458                                        kernel=self.kernel,
 459                                        agg=self.agg,
 460                                        seed=self.seed,
 461                                        backend=self.backend,
 462                                        show_progress=self.show_progress,
 463                                    ),
 464                                ),
 465                            ]
 466                        )
 467                    else:  # "random_state" in model().get_params().keys()
 468                        pipe = Pipeline(
 469                            steps=[
 470                                ("preprocessor", preprocessor),
 471                                (
 472                                    "regressor",
 473                                    DeepMTS(
 474                                        obj=model(**kwargs),
 475                                        n_layers=self.n_layers,
 476                                        n_hidden_features=self.n_hidden_features,
 477                                        activation_name=self.activation_name,
 478                                        a=self.a,
 479                                        nodes_sim=self.nodes_sim,
 480                                        bias=self.bias,
 481                                        dropout=self.dropout,
 482                                        direct_link=self.direct_link,
 483                                        n_clusters=self.n_clusters,
 484                                        cluster_encode=self.cluster_encode,
 485                                        type_clust=self.type_clust,
 486                                        type_scaling=self.type_scaling,
 487                                        lags=self.lags,
 488                                        type_pi=self.type_pi,
 489                                        block_size=self.block_size,
 490                                        replications=self.replications,
 491                                        kernel=self.kernel,
 492                                        agg=self.agg,
 493                                        seed=self.seed,
 494                                        backend=self.backend,
 495                                        show_progress=self.show_progress,
 496                                    ),
 497                                ),
 498                            ]
 499                        )
 500
 501                    pipe.fit(X_train, **kwargs)
 502                    # pipe.fit(X_train, xreg=xreg)
 503
 504                    self.models_[name] = pipe
 505
 506                    if self.h is None:
 507                        X_pred = pipe["regressor"].predict(h=self.h, **kwargs)
 508                    else:
 509                        assert self.h > 0, "h must be > 0"
 510                        X_pred = pipe["regressor"].predict(h=self.h, **kwargs)
 511
 512                    if (self.replications is not None) or (
 513                        self.type_pi == "gaussian"
 514                    ):
 515                        print(f"X_test: {X_test}")
 516                        print(f"X_pred: {X_pred}")
 517                        rmse = mean_errors(
 518                            actual=X_test,
 519                            pred=X_pred,
 520                            scoring="root_mean_squared_error",
 521                            per_series=per_series,
 522                        )
 523                        mae = mean_errors(
 524                            actual=X_test,
 525                            pred=X_pred,
 526                            scoring="mean_absolute_error",
 527                            per_series=per_series,
 528                        )
 529                        mpl = mean_errors(
 530                            actual=X_test,
 531                            pred=X_pred,
 532                            scoring="mean_pinball_loss",
 533                            per_series=per_series,
 534                        )
 535                        winklerscore = winkler_score(
 536                            obj=X_pred,
 537                            actual=X_test,
 538                            level=95,
 539                            per_series=per_series,
 540                        )
 541                        coveragecalc = coverage(
 542                            X_pred, X_test, level=95, per_series=per_series
 543                        )
 544                    else:
 545                        print(f"X_test: {X_test}")
 546                        print(f"X_pred: {X_pred}")
 547                        rmse = mean_errors(
 548                            actual=X_test,
 549                            pred=X_pred,
 550                            scoring="root_mean_squared_error",
 551                            per_series=per_series,
 552                        )
 553                        mae = mean_errors(
 554                            actual=X_test,
 555                            pred=X_pred,
 556                            scoring="mean_absolute_error",
 557                            per_series=per_series,
 558                        )
 559                        mpl = mean_errors(
 560                            actual=X_test,
 561                            pred=X_pred,
 562                            scoring="mean_pinball_loss",
 563                            per_series=per_series,
 564                        )
 565
 566                    names.append(name)
 567                    RMSE.append(rmse)
 568                    MAE.append(mae)
 569                    MPL.append(mpl)
 570
 571                    if (self.replications is not None) or (
 572                        self.type_pi == "gaussian"
 573                    ):
 574                        WINKLERSCORE.append(winklerscore)
 575                        COVERAGE.append(coveragecalc)
 576                    TIME.append(time.time() - start)
 577
 578                    if self.custom_metric is not None:
 579                        try:
 580                            custom_metric = self.custom_metric(X_test, X_pred)
 581                            CUSTOM_METRIC.append(custom_metric)
 582                        except Exception as e:
 583                            custom_metric = np.iinfo(np.float32).max
 584                            CUSTOM_METRIC.append(custom_metric)
 585
 586                    if self.verbose > 0:
 587                        if (self.replications is not None) or (
 588                            self.type_pi == "gaussian"
 589                        ):
 590                            scores_verbose = {
 591                                "Model": name,
 592                                "RMSE": rmse,
 593                                "MAE": mae,
 594                                "MPL": mpl,
 595                                "WINKLERSCORE": winklerscore,
 596                                "COVERAGE": coveragecalc,
 597                                "Time taken": time.time() - start,
 598                            }
 599                        else:
 600                            scores_verbose = {
 601                                "Model": name,
 602                                "RMSE": rmse,
 603                                "MAE": mae,
 604                                "MPL": mpl,
 605                                "Time taken": time.time() - start,
 606                            }
 607
 608                        if self.custom_metric is not None:
 609                            scores_verbose["Custom metric"] = custom_metric
 610
 611                    if self.predictions:
 612                        predictions[name] = X_pred
 613                except Exception as exception:
 614                    if self.ignore_warnings is False:
 615                        print(name + " model failed to execute")
 616                        print(exception)
 617
 618        else:  # no preprocessing
 619
 620            for name, model in tqdm(self.regressors):  # do parallel exec
 621                start = time.time()
 622                try:
 623                    if "random_state" in model().get_params().keys():
 624                        pipe = DeepMTS(
 625                            obj=model(random_state=self.random_state, **kwargs),
 626                            n_layers=self.n_layers,
 627                            n_hidden_features=self.n_hidden_features,
 628                            activation_name=self.activation_name,
 629                            a=self.a,
 630                            nodes_sim=self.nodes_sim,
 631                            bias=self.bias,
 632                            dropout=self.dropout,
 633                            direct_link=self.direct_link,
 634                            n_clusters=self.n_clusters,
 635                            cluster_encode=self.cluster_encode,
 636                            type_clust=self.type_clust,
 637                            type_scaling=self.type_scaling,
 638                            lags=self.lags,
 639                            type_pi=self.type_pi,
 640                            block_size=self.block_size,
 641                            replications=self.replications,
 642                            kernel=self.kernel,
 643                            agg=self.agg,
 644                            seed=self.seed,
 645                            backend=self.backend,
 646                            show_progress=self.show_progress,
 647                        )
 648                    else:
 649                        pipe = DeepMTS(
 650                            obj=model(**kwargs),
 651                            n_layers=self.n_layers,
 652                            n_hidden_features=self.n_hidden_features,
 653                            activation_name=self.activation_name,
 654                            a=self.a,
 655                            nodes_sim=self.nodes_sim,
 656                            bias=self.bias,
 657                            dropout=self.dropout,
 658                            direct_link=self.direct_link,
 659                            n_clusters=self.n_clusters,
 660                            cluster_encode=self.cluster_encode,
 661                            type_clust=self.type_clust,
 662                            type_scaling=self.type_scaling,
 663                            lags=self.lags,
 664                            type_pi=self.type_pi,
 665                            block_size=self.block_size,
 666                            replications=self.replications,
 667                            kernel=self.kernel,
 668                            agg=self.agg,
 669                            seed=self.seed,
 670                            backend=self.backend,
 671                            show_progress=self.show_progress,
 672                        )
 673
 674                    pipe.fit(X_train, xreg, **kwargs)
 675                    # pipe.fit(X_train, xreg=xreg) # DO xreg like in `ahead`
 676
 677                    self.models_[name] = pipe
 678
 679                    if self.preprocess is True:
 680                        if self.h is None:
 681                            X_pred = pipe["regressor"].predict(
 682                                h=X_test.shape[0], **kwargs
 683                            )
 684                        else:
 685                            assert (
 686                                self.h > 0 and self.h <= X_test.shape[0]
 687                            ), "h must be > 0 and < X_test.shape[0]"
 688                            X_pred = pipe["regressor"].predict(
 689                                h=self.h, **kwargs
 690                            )
 691
 692                    else:
 693
 694                        if self.h is None:
 695                            X_pred = pipe.predict(
 696                                h=X_test.shape[0], **kwargs
 697                            )  # X_pred = pipe.predict(h=X_test.shape[0], new_xreg=new_xreg) ## DO xreg like in `ahead`
 698                        else:
 699                            assert (
 700                                self.h > 0 and self.h <= X_test.shape[0]
 701                            ), "h must be > 0 and < X_test.shape[0]"
 702                            X_pred = pipe.predict(h=self.h, **kwargs)
 703
 704                    if self.h is None:
 705                        if (self.replications is not None) or (
 706                            self.type_pi == "gaussian"
 707                        ):
 708                            print(f"X_test: {X_test}")
 709                            print(f"X_pred: {X_pred}")
 710                            rmse = mean_errors(
 711                                actual=X_test,
 712                                pred=X_pred.mean,
 713                                scoring="root_mean_squared_error",
 714                                per_series=per_series,
 715                            )
 716                            mae = mean_errors(
 717                                actual=X_test,
 718                                pred=X_pred.mean,
 719                                scoring="mean_absolute_error",
 720                                per_series=per_series,
 721                            )
 722                            mpl = mean_errors(
 723                                actual=X_test,
 724                                pred=X_pred.mean,
 725                                scoring="mean_pinball_loss",
 726                                per_series=per_series,
 727                            )
 728                            winklerscore = winkler_score(
 729                                obj=X_pred,
 730                                actual=X_test,
 731                                level=95,
 732                                per_series=per_series,
 733                            )
 734                            coveragecalc = coverage(
 735                                X_pred, X_test, level=95, per_series=per_series
 736                            )
 737                        else:  # no prediction interval
 738                            print(f"X_test: {X_test}")
 739                            print(f"X_pred: {X_pred}")
 740                            rmse = mean_errors(
 741                                actual=X_test,
 742                                pred=X_pred,
 743                                scoring="root_mean_squared_error",
 744                                per_series=per_series,
 745                            )
 746                            mae = mean_errors(
 747                                actual=X_test,
 748                                pred=X_pred,
 749                                scoring="mean_absolute_error",
 750                                per_series=per_series,
 751                            )
 752                            mpl = mean_errors(
 753                                actual=X_test,
 754                                pred=X_pred,
 755                                scoring="mean_pinball_loss",
 756                                per_series=per_series,
 757                            )
 758                    else:  # self.h is not None
 759                        if (self.replications is not None) or (
 760                            self.type_pi == "gaussian"
 761                        ):
 762
 763                            if isinstance(X_test, pd.DataFrame):
 764                                X_test_h = X_test.iloc[0: self.h, :]
 765                                print(f"X_test: {X_test}")
 766                                print(f"X_pred: {X_pred}")
 767                                rmse = mean_errors(
 768                                    actual=X_test_h,
 769                                    pred=X_pred,
 770                                    scoring="root_mean_squared_error",
 771                                    per_series=per_series,
 772                                )
 773                                mae = mean_errors(
 774                                    actual=X_test_h,
 775                                    pred=X_pred,
 776                                    scoring="mean_absolute_error",
 777                                    per_series=per_series,
 778                                )
 779                                mpl = mean_errors(
 780                                    actual=X_test_h,
 781                                    pred=X_pred,
 782                                    scoring="mean_pinball_loss",
 783                                    per_series=per_series,
 784                                )
 785                                winklerscore = winkler_score(
 786                                    obj=X_pred,
 787                                    actual=X_test_h,
 788                                    level=95,
 789                                    per_series=per_series,
 790                                )
 791                                coveragecalc = coverage(
 792                                    X_pred,
 793                                    X_test_h,
 794                                    level=95,
 795                                    per_series=per_series,
 796                                )
 797                            else:
 798                                X_test_h = X_test[0: self.h, :]
 799                                print(f"X_test: {X_test}")
 800                                print(f"X_pred: {X_pred}")
 801                                rmse = mean_errors(
 802                                    actual=X_test_h,
 803                                    pred=X_pred,
 804                                    scoring="root_mean_squared_error",
 805                                    per_series=per_series,
 806                                )
 807                                mae = mean_errors(
 808                                    actual=X_test_h,
 809                                    pred=X_pred,
 810                                    scoring="mean_absolute_error",
 811                                    per_series=per_series,
 812                                )
 813                                mpl = mean_errors(
 814                                    actual=X_test_h,
 815                                    pred=X_pred,
 816                                    scoring="mean_pinball_loss",
 817                                    per_series=per_series,
 818                                )
 819                                winklerscore = winkler_score(
 820                                    obj=X_pred,
 821                                    actual=X_test_h,
 822                                    level=95,
 823                                    per_series=per_series,
 824                                )
 825                                coveragecalc = coverage(
 826                                    X_pred,
 827                                    X_test_h,
 828                                    level=95,
 829                                    per_series=per_series,
 830                                )
 831                        else:  # no prediction interval
 832
 833                            if isinstance(X_test, pd.DataFrame):
 834                                print(f"X_test: {X_test}")
 835                                print(f"X_pred: {X_pred}")
 836                                X_test_h = X_test.iloc[0: self.h, :]
 837                                rmse = mean_errors(
 838                                    actual=X_test_h,
 839                                    pred=X_pred,
 840                                    scoring="root_mean_squared_error",
 841                                    per_series=per_series,
 842                                )
 843                                mae = mean_errors(
 844                                    actual=X_test_h,
 845                                    pred=X_pred,
 846                                    scoring="mean_absolute_error",
 847                                    per_series=per_series,
 848                                )
 849                                mpl = mean_errors(
 850                                    actual=X_test_h,
 851                                    pred=X_pred,
 852                                    scoring="mean_pinball_loss",
 853                                    per_series=per_series,
 854                                )
 855                            else:
 856                                X_test_h = X_test[0: self.h, :]
 857                                print(f"X_test: {X_test}")
 858                                print(f"X_pred: {X_pred}")
 859                                rmse = mean_errors(
 860                                    actual=X_test_h,
 861                                    pred=X_pred,
 862                                    scoring="root_mean_squared_error",
 863                                    per_series=per_series,
 864                                )
 865                                mae = mean_errors(
 866                                    actual=X_test_h,
 867                                    pred=X_pred,
 868                                    scoring="mean_absolute_error",
 869                                    per_series=per_series,
 870                                )
 871
 872                    names.append(name)
 873                    RMSE.append(rmse)
 874                    MAE.append(mae)
 875                    MPL.append(mpl)
 876                    if (self.replications is not None) or (
 877                        self.type_pi == "gaussian"
 878                    ):
 879                        WINKLERSCORE.append(winklerscore)
 880                        COVERAGE.append(coveragecalc)
 881                    TIME.append(time.time() - start)
 882
 883                    if self.custom_metric is not None:
 884                        try:
 885                            if self.h is None:
 886                                custom_metric = self.custom_metric(
 887                                    X_test, X_pred
 888                                )
 889                            else:
 890                                custom_metric = self.custom_metric(
 891                                    X_test_h, X_pred
 892                                )
 893                            CUSTOM_METRIC.append(custom_metric)
 894                        except Exception as e:
 895                            custom_metric = np.iinfo(np.float32).max
 896                            CUSTOM_METRIC.append(np.iinfo(np.float32).max)
 897
 898                    if self.verbose > 0:
 899                        if (self.replications is not None) or (
 900                            self.type_pi == "gaussian"
 901                        ):
 902                            scores_verbose = {
 903                                "Model": name,
 904                                "RMSE": rmse,
 905                                "MAE": mae,
 906                                "MPL": mpl,
 907                                "WINKLERSCORE": winklerscore,
 908                                "COVERAGE": coveragecalc,
 909                                "Time taken": time.time() - start,
 910                            }
 911                        else:
 912                            scores_verbose = {
 913                                "Model": name,
 914                                "RMSE": rmse,
 915                                "MAE": mae,
 916                                "MPL": mpl,
 917                                "Time taken": time.time() - start,
 918                            }
 919
 920                        if self.custom_metric is not None:
 921                            scores_verbose["Custom metric"] = custom_metric
 922
 923                    if self.predictions:
 924                        predictions[name] = X_pred
 925
 926                except Exception as exception:
 927                    if self.ignore_warnings is False:
 928                        print(name + " model failed to execute")
 929                        print(exception)
 930
 931        if (self.replications is not None) or (self.type_pi == "gaussian"):
 932            scores = {
 933                "Model": names,
 934                "RMSE": RMSE,
 935                "MAE": MAE,
 936                "MPL": MPL,
 937                "WINKLERSCORE": WINKLERSCORE,
 938                "COVERAGE": COVERAGE,
 939                "Time Taken": TIME,
 940            }
 941        else:
 942            scores = {
 943                "Model": names,
 944                "RMSE": RMSE,
 945                "MAE": MAE,
 946                "MPL": MPL,
 947                "Time Taken": TIME,
 948            }
 949
 950        if self.custom_metric is not None:
 951            scores["Custom metric"] = CUSTOM_METRIC
 952
 953        if per_series:
 954            scores = dict_to_dataframe_series(scores, self.series_names)
 955        else:
 956            scores = pd.DataFrame(scores)
 957
 958        try:  # case per_series, can't be sorted
 959            scores = scores.sort_values(
 960                by=self.sort_by, ascending=True
 961            ).set_index("Model")
 962
 963            self.best_model_ = self.models_[scores.index[0]]
 964        except Exception as e:
 965            pass
 966
 967        if self.predictions is True:
 968
 969            return scores, predictions
 970
 971        return scores
 972
 973    def get_best_model(self):
 974        """
 975        This function returns the best model pipeline based on the sort_by metric.
 976
 977        Returns:
 978
 979            best_model: object,
 980                Returns the best model pipeline based on the sort_by metric.
 981
 982        """
 983        return self.best_model_
 984
 985    def provide_models(self, X_train, X_test):
 986        """
 987        This function returns all the model objects trained in fit function.
 988        If fit is not called already, then we call fit and then return the models.
 989
 990        Parameters:
 991
 992            X_train : array-like,
 993                Training vectors, where rows is the number of samples
 994                and columns is the number of features.
 995
 996            X_test : array-like,
 997                Testing vectors, where rows is the number of samples
 998                and columns is the number of features.
 999
1000        Returns:
1001
1002            models: dict-object,
1003                Returns a dictionary with each model pipeline as value
1004                with key as name of models.
1005
1006        """
1007        if self.h is None:
1008            if len(self.models_.keys()) == 0:
1009                self.fit(X_train, X_test)
1010        else:
1011            if len(self.models_.keys()) == 0:
1012                if isinstance(X_test, pd.DataFrame):
1013                    self.fit(X_train, X_test.iloc[0: self.h, :])
1014                else:
1015                    self.fit(X_train, X_test[0: self.h, :])
1016
1017        return self.models_

Fitting -- almost -- all the regression algorithms with layers of nnetsauce's CustomRegressor to multivariate time series and returning their scores.

Parameters:

verbose: int, optional (default=0)
    Any positive number for verbosity.

ignore_warnings: bool, optional (default=True)
    When set to True, the warning related to algorigms that are not
    able to run are ignored.

custom_metric: function, optional (default=None)
    When function is provided, models are evaluated based on the custom
      evaluation metric provided.

predictions: bool, optional (default=False)
    When set to True, the predictions of all the models models are returned as dataframe.

sort_by: string, optional (default='RMSE')
    Sort models by a metric. Available options are 'RMSE', 'MAE', 'MPL', 'MPE', 'MAPE',
    'R-Squared', 'Adjusted R-Squared' or a custom metric identified by its name and
    provided by custom_metric.

random_state: int, optional (default=42)
    Reproducibiility seed.

estimators: list, optional (default='all')
    list of Estimators (regression algorithms) names or just 'all' (default='all')

preprocess: bool, preprocessing is done when set to True

n_layers: int, optional (default=1)
    Number of layers in the network. When set to 1, the model is equivalent to a MTS.

h: int, optional (default=None)
    Number of steps ahead to predict (when used, must be > 0 and < X_test.shape[0]).

All the other parameters are the same as MTS's.

Attributes:

models_: dict-object
    Returns a dictionary with each model pipeline as value
    with key as name of models.

best_model_: object
    Returns the best model pipeline based on the sort_by metric.

Examples:

See https://thierrymoudiki.github.io/blog/2023/10/29/python/quasirandomizednn/MTS-LazyPredict
def fit(self, X_train, X_test, xreg=None, per_series=False, **kwargs):
241    def fit(self, X_train, X_test, xreg=None, per_series=False, **kwargs):
242        """Fit Regression algorithms to X_train, predict and score on X_test.
243
244        Parameters:
245
246            X_train: array-like or data frame,
247                Training vectors, where rows is the number of samples
248                and columns is the number of features.
249
250            X_test: array-like or data frame,
251                Testing vectors, where rows is the number of samples
252                and columns is the number of features.
253
254            xreg: array-like, optional (default=None)
255                Additional (external) regressors to be passed to self.obj
256                xreg must be in 'increasing' order (most recent observations last)
257
258            per_series: bool, optional (default=False)
259                When set to True, the metrics are computed series by series.
260
261            **kwargs: dict, optional (default=None)
262                Additional parameters to be passed to `fit` method of `obj`.
263
264        Returns:
265
266            scores: Pandas DataFrame
267                Returns metrics of all the models in a Pandas DataFrame.
268
269            predictions: Pandas DataFrame
270                Returns predictions of all the models in a Pandas DataFrame.
271
272        """
273        R2 = []
274        ADJR2 = []
275        ME = []
276        MPL = []
277        RMSE = []
278        MAE = []
279        MPE = []
280        MAPE = []
281        WINKLERSCORE = []
282        COVERAGE = []
283
284        # WIN = []
285        names = []
286        TIME = []
287        predictions = {}
288
289        if self.custom_metric is not None:
290            CUSTOM_METRIC = []
291
292        if self.h is None:
293            assert X_test is not None, "If h is None, X_test must be provided."
294
295        if isinstance(X_train, np.ndarray):
296            X_train = pd.DataFrame(X_train)
297            X_test = pd.DataFrame(X_test)
298
299        self.series_names = X_train.columns.tolist()
300
301        X_train = convert_df_to_numeric(X_train)
302        X_test = convert_df_to_numeric(X_test)
303
304        numeric_features = X_train.select_dtypes(include=[np.number]).columns
305        categorical_features = X_train.select_dtypes(include=["object"]).columns
306
307        categorical_low, categorical_high = get_card_split(
308            X_train, categorical_features
309        )
310
311        if self.preprocess:
312            preprocessor = ColumnTransformer(
313                transformers=[
314                    ("numeric", numeric_transformer, numeric_features),
315                    (
316                        "categorical_low",
317                        categorical_transformer_low,
318                        categorical_low,
319                    ),
320                    (
321                        "categorical_high",
322                        categorical_transformer_high,
323                        categorical_high,
324                    ),
325                ]
326            )
327
328        # baselines (Classical MTS) ----
329        for i, name in enumerate(["ARIMA", "ETS", "Theta", "VAR", "VECM"]):
330            try:
331                start = time.time()
332                regr = ClassicalMTS(model=name)
333                regr.fit(X_train, **kwargs)
334                self.models_[name] = regr
335                if self.h is None:
336                    X_pred = regr.predict(h=X_test.shape[0], **kwargs)
337                else:
338                    assert self.h > 0, "h must be > 0"
339                    X_pred = regr.predict(h=self.h, **kwargs)
340                    try:
341                        X_test = X_test[0: self.h, :]
342                    except Exception as e:
343                        X_test = X_test.iloc[0: self.h, :]
344
345                print(f"X_test: {X_test}")
346                print(f"X_pred: {X_pred}")
347                rmse = mean_errors(
348                    actual=X_test,
349                    pred=X_pred,
350                    scoring="root_mean_squared_error",
351                    per_series=per_series,
352                )
353                mae = mean_errors(
354                    actual=X_test,
355                    pred=X_pred,
356                    scoring="mean_absolute_error",
357                    per_series=per_series,
358                )
359                mpl = mean_errors(
360                    actual=X_test,
361                    pred=X_pred,
362                    scoring="mean_pinball_loss",
363                    per_series=per_series,
364                )
365            except Exception:
366
367                continue
368
369            names.append(name)
370            RMSE.append(rmse)
371            MAE.append(mae)
372            MPL.append(mpl)
373
374            if self.custom_metric is not None:
375                try:
376                    if self.h is None:
377                        custom_metric = self.custom_metric(X_test, X_pred)
378                    else:
379                        custom_metric = self.custom_metric(X_test_h, X_pred)
380                    CUSTOM_METRIC.append(custom_metric)
381                except Exception as e:
382                    custom_metric = np.iinfo(np.float32).max
383                    CUSTOM_METRIC.append(np.iinfo(np.float32).max)
384
385            if (self.replications is not None) or (self.type_pi == "gaussian"):
386                if per_series == False:
387                    winklerscore = winkler_score(
388                        obj=X_pred, actual=X_test, level=95
389                    )
390                    coveragecalc = coverage(X_pred, X_test, level=95)
391                else:
392                    winklerscore = winkler_score(
393                        obj=X_pred, actual=X_test, level=95, per_series=True
394                    )
395                    coveragecalc = coverage(
396                        X_pred, X_test, level=95, per_series=True
397                    )
398                WINKLERSCORE.append(winklerscore)
399                COVERAGE.append(coveragecalc)
400            TIME.append(time.time() - start)
401
402        if self.estimators == "all":
403            if self.n_layers <= 1:
404                self.regressors = REGRESSORSMTS
405            else:
406                self.regressors = DEEPREGRESSORSMTS
407        else:
408            if self.n_layers <= 1:
409                self.regressors = [
410                    ("MTS(" + est[0] + ")", est[1])
411                    for est in all_estimators()
412                    if (
413                        issubclass(est[1], RegressorMixin)
414                        and (est[0] in self.estimators)
415                    )
416                ]
417            else:  # self.n_layers > 1
418                self.regressors = [
419                    ("DeepMTS(" + est[0] + ")", est[1])
420                    for est in all_estimators()
421                    if (
422                        issubclass(est[1], RegressorMixin)
423                        and (est[0] in self.estimators)
424                    )
425                ]
426
427        if self.preprocess is True:
428            for name, model in tqdm(self.regressors):  # do parallel exec
429                start = time.time()
430                try:
431                    if "random_state" in model().get_params().keys():
432                        pipe = Pipeline(
433                            steps=[
434                                ("preprocessor", preprocessor),
435                                (
436                                    "regressor",
437                                    DeepMTS(
438                                        obj=model(
439                                            random_state=self.random_state,
440                                            **kwargs,
441                                        ),
442                                        n_layers=self.n_layers,
443                                        n_hidden_features=self.n_hidden_features,
444                                        activation_name=self.activation_name,
445                                        a=self.a,
446                                        nodes_sim=self.nodes_sim,
447                                        bias=self.bias,
448                                        dropout=self.dropout,
449                                        direct_link=self.direct_link,
450                                        n_clusters=self.n_clusters,
451                                        cluster_encode=self.cluster_encode,
452                                        type_clust=self.type_clust,
453                                        type_scaling=self.type_scaling,
454                                        lags=self.lags,
455                                        type_pi=self.type_pi,
456                                        block_size=self.block_size,
457                                        replications=self.replications,
458                                        kernel=self.kernel,
459                                        agg=self.agg,
460                                        seed=self.seed,
461                                        backend=self.backend,
462                                        show_progress=self.show_progress,
463                                    ),
464                                ),
465                            ]
466                        )
467                    else:  # "random_state" in model().get_params().keys()
468                        pipe = Pipeline(
469                            steps=[
470                                ("preprocessor", preprocessor),
471                                (
472                                    "regressor",
473                                    DeepMTS(
474                                        obj=model(**kwargs),
475                                        n_layers=self.n_layers,
476                                        n_hidden_features=self.n_hidden_features,
477                                        activation_name=self.activation_name,
478                                        a=self.a,
479                                        nodes_sim=self.nodes_sim,
480                                        bias=self.bias,
481                                        dropout=self.dropout,
482                                        direct_link=self.direct_link,
483                                        n_clusters=self.n_clusters,
484                                        cluster_encode=self.cluster_encode,
485                                        type_clust=self.type_clust,
486                                        type_scaling=self.type_scaling,
487                                        lags=self.lags,
488                                        type_pi=self.type_pi,
489                                        block_size=self.block_size,
490                                        replications=self.replications,
491                                        kernel=self.kernel,
492                                        agg=self.agg,
493                                        seed=self.seed,
494                                        backend=self.backend,
495                                        show_progress=self.show_progress,
496                                    ),
497                                ),
498                            ]
499                        )
500
501                    pipe.fit(X_train, **kwargs)
502                    # pipe.fit(X_train, xreg=xreg)
503
504                    self.models_[name] = pipe
505
506                    if self.h is None:
507                        X_pred = pipe["regressor"].predict(h=self.h, **kwargs)
508                    else:
509                        assert self.h > 0, "h must be > 0"
510                        X_pred = pipe["regressor"].predict(h=self.h, **kwargs)
511
512                    if (self.replications is not None) or (
513                        self.type_pi == "gaussian"
514                    ):
515                        print(f"X_test: {X_test}")
516                        print(f"X_pred: {X_pred}")
517                        rmse = mean_errors(
518                            actual=X_test,
519                            pred=X_pred,
520                            scoring="root_mean_squared_error",
521                            per_series=per_series,
522                        )
523                        mae = mean_errors(
524                            actual=X_test,
525                            pred=X_pred,
526                            scoring="mean_absolute_error",
527                            per_series=per_series,
528                        )
529                        mpl = mean_errors(
530                            actual=X_test,
531                            pred=X_pred,
532                            scoring="mean_pinball_loss",
533                            per_series=per_series,
534                        )
535                        winklerscore = winkler_score(
536                            obj=X_pred,
537                            actual=X_test,
538                            level=95,
539                            per_series=per_series,
540                        )
541                        coveragecalc = coverage(
542                            X_pred, X_test, level=95, per_series=per_series
543                        )
544                    else:
545                        print(f"X_test: {X_test}")
546                        print(f"X_pred: {X_pred}")
547                        rmse = mean_errors(
548                            actual=X_test,
549                            pred=X_pred,
550                            scoring="root_mean_squared_error",
551                            per_series=per_series,
552                        )
553                        mae = mean_errors(
554                            actual=X_test,
555                            pred=X_pred,
556                            scoring="mean_absolute_error",
557                            per_series=per_series,
558                        )
559                        mpl = mean_errors(
560                            actual=X_test,
561                            pred=X_pred,
562                            scoring="mean_pinball_loss",
563                            per_series=per_series,
564                        )
565
566                    names.append(name)
567                    RMSE.append(rmse)
568                    MAE.append(mae)
569                    MPL.append(mpl)
570
571                    if (self.replications is not None) or (
572                        self.type_pi == "gaussian"
573                    ):
574                        WINKLERSCORE.append(winklerscore)
575                        COVERAGE.append(coveragecalc)
576                    TIME.append(time.time() - start)
577
578                    if self.custom_metric is not None:
579                        try:
580                            custom_metric = self.custom_metric(X_test, X_pred)
581                            CUSTOM_METRIC.append(custom_metric)
582                        except Exception as e:
583                            custom_metric = np.iinfo(np.float32).max
584                            CUSTOM_METRIC.append(custom_metric)
585
586                    if self.verbose > 0:
587                        if (self.replications is not None) or (
588                            self.type_pi == "gaussian"
589                        ):
590                            scores_verbose = {
591                                "Model": name,
592                                "RMSE": rmse,
593                                "MAE": mae,
594                                "MPL": mpl,
595                                "WINKLERSCORE": winklerscore,
596                                "COVERAGE": coveragecalc,
597                                "Time taken": time.time() - start,
598                            }
599                        else:
600                            scores_verbose = {
601                                "Model": name,
602                                "RMSE": rmse,
603                                "MAE": mae,
604                                "MPL": mpl,
605                                "Time taken": time.time() - start,
606                            }
607
608                        if self.custom_metric is not None:
609                            scores_verbose["Custom metric"] = custom_metric
610
611                    if self.predictions:
612                        predictions[name] = X_pred
613                except Exception as exception:
614                    if self.ignore_warnings is False:
615                        print(name + " model failed to execute")
616                        print(exception)
617
618        else:  # no preprocessing
619
620            for name, model in tqdm(self.regressors):  # do parallel exec
621                start = time.time()
622                try:
623                    if "random_state" in model().get_params().keys():
624                        pipe = DeepMTS(
625                            obj=model(random_state=self.random_state, **kwargs),
626                            n_layers=self.n_layers,
627                            n_hidden_features=self.n_hidden_features,
628                            activation_name=self.activation_name,
629                            a=self.a,
630                            nodes_sim=self.nodes_sim,
631                            bias=self.bias,
632                            dropout=self.dropout,
633                            direct_link=self.direct_link,
634                            n_clusters=self.n_clusters,
635                            cluster_encode=self.cluster_encode,
636                            type_clust=self.type_clust,
637                            type_scaling=self.type_scaling,
638                            lags=self.lags,
639                            type_pi=self.type_pi,
640                            block_size=self.block_size,
641                            replications=self.replications,
642                            kernel=self.kernel,
643                            agg=self.agg,
644                            seed=self.seed,
645                            backend=self.backend,
646                            show_progress=self.show_progress,
647                        )
648                    else:
649                        pipe = DeepMTS(
650                            obj=model(**kwargs),
651                            n_layers=self.n_layers,
652                            n_hidden_features=self.n_hidden_features,
653                            activation_name=self.activation_name,
654                            a=self.a,
655                            nodes_sim=self.nodes_sim,
656                            bias=self.bias,
657                            dropout=self.dropout,
658                            direct_link=self.direct_link,
659                            n_clusters=self.n_clusters,
660                            cluster_encode=self.cluster_encode,
661                            type_clust=self.type_clust,
662                            type_scaling=self.type_scaling,
663                            lags=self.lags,
664                            type_pi=self.type_pi,
665                            block_size=self.block_size,
666                            replications=self.replications,
667                            kernel=self.kernel,
668                            agg=self.agg,
669                            seed=self.seed,
670                            backend=self.backend,
671                            show_progress=self.show_progress,
672                        )
673
674                    pipe.fit(X_train, xreg, **kwargs)
675                    # pipe.fit(X_train, xreg=xreg) # DO xreg like in `ahead`
676
677                    self.models_[name] = pipe
678
679                    if self.preprocess is True:
680                        if self.h is None:
681                            X_pred = pipe["regressor"].predict(
682                                h=X_test.shape[0], **kwargs
683                            )
684                        else:
685                            assert (
686                                self.h > 0 and self.h <= X_test.shape[0]
687                            ), "h must be > 0 and < X_test.shape[0]"
688                            X_pred = pipe["regressor"].predict(
689                                h=self.h, **kwargs
690                            )
691
692                    else:
693
694                        if self.h is None:
695                            X_pred = pipe.predict(
696                                h=X_test.shape[0], **kwargs
697                            )  # X_pred = pipe.predict(h=X_test.shape[0], new_xreg=new_xreg) ## DO xreg like in `ahead`
698                        else:
699                            assert (
700                                self.h > 0 and self.h <= X_test.shape[0]
701                            ), "h must be > 0 and < X_test.shape[0]"
702                            X_pred = pipe.predict(h=self.h, **kwargs)
703
704                    if self.h is None:
705                        if (self.replications is not None) or (
706                            self.type_pi == "gaussian"
707                        ):
708                            print(f"X_test: {X_test}")
709                            print(f"X_pred: {X_pred}")
710                            rmse = mean_errors(
711                                actual=X_test,
712                                pred=X_pred.mean,
713                                scoring="root_mean_squared_error",
714                                per_series=per_series,
715                            )
716                            mae = mean_errors(
717                                actual=X_test,
718                                pred=X_pred.mean,
719                                scoring="mean_absolute_error",
720                                per_series=per_series,
721                            )
722                            mpl = mean_errors(
723                                actual=X_test,
724                                pred=X_pred.mean,
725                                scoring="mean_pinball_loss",
726                                per_series=per_series,
727                            )
728                            winklerscore = winkler_score(
729                                obj=X_pred,
730                                actual=X_test,
731                                level=95,
732                                per_series=per_series,
733                            )
734                            coveragecalc = coverage(
735                                X_pred, X_test, level=95, per_series=per_series
736                            )
737                        else:  # no prediction interval
738                            print(f"X_test: {X_test}")
739                            print(f"X_pred: {X_pred}")
740                            rmse = mean_errors(
741                                actual=X_test,
742                                pred=X_pred,
743                                scoring="root_mean_squared_error",
744                                per_series=per_series,
745                            )
746                            mae = mean_errors(
747                                actual=X_test,
748                                pred=X_pred,
749                                scoring="mean_absolute_error",
750                                per_series=per_series,
751                            )
752                            mpl = mean_errors(
753                                actual=X_test,
754                                pred=X_pred,
755                                scoring="mean_pinball_loss",
756                                per_series=per_series,
757                            )
758                    else:  # self.h is not None
759                        if (self.replications is not None) or (
760                            self.type_pi == "gaussian"
761                        ):
762
763                            if isinstance(X_test, pd.DataFrame):
764                                X_test_h = X_test.iloc[0: self.h, :]
765                                print(f"X_test: {X_test}")
766                                print(f"X_pred: {X_pred}")
767                                rmse = mean_errors(
768                                    actual=X_test_h,
769                                    pred=X_pred,
770                                    scoring="root_mean_squared_error",
771                                    per_series=per_series,
772                                )
773                                mae = mean_errors(
774                                    actual=X_test_h,
775                                    pred=X_pred,
776                                    scoring="mean_absolute_error",
777                                    per_series=per_series,
778                                )
779                                mpl = mean_errors(
780                                    actual=X_test_h,
781                                    pred=X_pred,
782                                    scoring="mean_pinball_loss",
783                                    per_series=per_series,
784                                )
785                                winklerscore = winkler_score(
786                                    obj=X_pred,
787                                    actual=X_test_h,
788                                    level=95,
789                                    per_series=per_series,
790                                )
791                                coveragecalc = coverage(
792                                    X_pred,
793                                    X_test_h,
794                                    level=95,
795                                    per_series=per_series,
796                                )
797                            else:
798                                X_test_h = X_test[0: self.h, :]
799                                print(f"X_test: {X_test}")
800                                print(f"X_pred: {X_pred}")
801                                rmse = mean_errors(
802                                    actual=X_test_h,
803                                    pred=X_pred,
804                                    scoring="root_mean_squared_error",
805                                    per_series=per_series,
806                                )
807                                mae = mean_errors(
808                                    actual=X_test_h,
809                                    pred=X_pred,
810                                    scoring="mean_absolute_error",
811                                    per_series=per_series,
812                                )
813                                mpl = mean_errors(
814                                    actual=X_test_h,
815                                    pred=X_pred,
816                                    scoring="mean_pinball_loss",
817                                    per_series=per_series,
818                                )
819                                winklerscore = winkler_score(
820                                    obj=X_pred,
821                                    actual=X_test_h,
822                                    level=95,
823                                    per_series=per_series,
824                                )
825                                coveragecalc = coverage(
826                                    X_pred,
827                                    X_test_h,
828                                    level=95,
829                                    per_series=per_series,
830                                )
831                        else:  # no prediction interval
832
833                            if isinstance(X_test, pd.DataFrame):
834                                print(f"X_test: {X_test}")
835                                print(f"X_pred: {X_pred}")
836                                X_test_h = X_test.iloc[0: self.h, :]
837                                rmse = mean_errors(
838                                    actual=X_test_h,
839                                    pred=X_pred,
840                                    scoring="root_mean_squared_error",
841                                    per_series=per_series,
842                                )
843                                mae = mean_errors(
844                                    actual=X_test_h,
845                                    pred=X_pred,
846                                    scoring="mean_absolute_error",
847                                    per_series=per_series,
848                                )
849                                mpl = mean_errors(
850                                    actual=X_test_h,
851                                    pred=X_pred,
852                                    scoring="mean_pinball_loss",
853                                    per_series=per_series,
854                                )
855                            else:
856                                X_test_h = X_test[0: self.h, :]
857                                print(f"X_test: {X_test}")
858                                print(f"X_pred: {X_pred}")
859                                rmse = mean_errors(
860                                    actual=X_test_h,
861                                    pred=X_pred,
862                                    scoring="root_mean_squared_error",
863                                    per_series=per_series,
864                                )
865                                mae = mean_errors(
866                                    actual=X_test_h,
867                                    pred=X_pred,
868                                    scoring="mean_absolute_error",
869                                    per_series=per_series,
870                                )
871
872                    names.append(name)
873                    RMSE.append(rmse)
874                    MAE.append(mae)
875                    MPL.append(mpl)
876                    if (self.replications is not None) or (
877                        self.type_pi == "gaussian"
878                    ):
879                        WINKLERSCORE.append(winklerscore)
880                        COVERAGE.append(coveragecalc)
881                    TIME.append(time.time() - start)
882
883                    if self.custom_metric is not None:
884                        try:
885                            if self.h is None:
886                                custom_metric = self.custom_metric(
887                                    X_test, X_pred
888                                )
889                            else:
890                                custom_metric = self.custom_metric(
891                                    X_test_h, X_pred
892                                )
893                            CUSTOM_METRIC.append(custom_metric)
894                        except Exception as e:
895                            custom_metric = np.iinfo(np.float32).max
896                            CUSTOM_METRIC.append(np.iinfo(np.float32).max)
897
898                    if self.verbose > 0:
899                        if (self.replications is not None) or (
900                            self.type_pi == "gaussian"
901                        ):
902                            scores_verbose = {
903                                "Model": name,
904                                "RMSE": rmse,
905                                "MAE": mae,
906                                "MPL": mpl,
907                                "WINKLERSCORE": winklerscore,
908                                "COVERAGE": coveragecalc,
909                                "Time taken": time.time() - start,
910                            }
911                        else:
912                            scores_verbose = {
913                                "Model": name,
914                                "RMSE": rmse,
915                                "MAE": mae,
916                                "MPL": mpl,
917                                "Time taken": time.time() - start,
918                            }
919
920                        if self.custom_metric is not None:
921                            scores_verbose["Custom metric"] = custom_metric
922
923                    if self.predictions:
924                        predictions[name] = X_pred
925
926                except Exception as exception:
927                    if self.ignore_warnings is False:
928                        print(name + " model failed to execute")
929                        print(exception)
930
931        if (self.replications is not None) or (self.type_pi == "gaussian"):
932            scores = {
933                "Model": names,
934                "RMSE": RMSE,
935                "MAE": MAE,
936                "MPL": MPL,
937                "WINKLERSCORE": WINKLERSCORE,
938                "COVERAGE": COVERAGE,
939                "Time Taken": TIME,
940            }
941        else:
942            scores = {
943                "Model": names,
944                "RMSE": RMSE,
945                "MAE": MAE,
946                "MPL": MPL,
947                "Time Taken": TIME,
948            }
949
950        if self.custom_metric is not None:
951            scores["Custom metric"] = CUSTOM_METRIC
952
953        if per_series:
954            scores = dict_to_dataframe_series(scores, self.series_names)
955        else:
956            scores = pd.DataFrame(scores)
957
958        try:  # case per_series, can't be sorted
959            scores = scores.sort_values(
960                by=self.sort_by, ascending=True
961            ).set_index("Model")
962
963            self.best_model_ = self.models_[scores.index[0]]
964        except Exception as e:
965            pass
966
967        if self.predictions is True:
968
969            return scores, predictions
970
971        return scores

Fit Regression algorithms to X_train, predict and score on X_test.

Parameters:

X_train: array-like or data frame,
    Training vectors, where rows is the number of samples
    and columns is the number of features.

X_test: array-like or data frame,
    Testing vectors, where rows is the number of samples
    and columns is the number of features.

xreg: array-like, optional (default=None)
    Additional (external) regressors to be passed to self.obj
    xreg must be in 'increasing' order (most recent observations last)

per_series: bool, optional (default=False)
    When set to True, the metrics are computed series by series.

**kwargs: dict, optional (default=None)
    Additional parameters to be passed to `fit` method of `obj`.

Returns:

scores: Pandas DataFrame
    Returns metrics of all the models in a Pandas DataFrame.

predictions: Pandas DataFrame
    Returns predictions of all the models in a Pandas DataFrame.
def provide_models(self, X_train, X_test):
 985    def provide_models(self, X_train, X_test):
 986        """
 987        This function returns all the model objects trained in fit function.
 988        If fit is not called already, then we call fit and then return the models.
 989
 990        Parameters:
 991
 992            X_train : array-like,
 993                Training vectors, where rows is the number of samples
 994                and columns is the number of features.
 995
 996            X_test : array-like,
 997                Testing vectors, where rows is the number of samples
 998                and columns is the number of features.
 999
1000        Returns:
1001
1002            models: dict-object,
1003                Returns a dictionary with each model pipeline as value
1004                with key as name of models.
1005
1006        """
1007        if self.h is None:
1008            if len(self.models_.keys()) == 0:
1009                self.fit(X_train, X_test)
1010        else:
1011            if len(self.models_.keys()) == 0:
1012                if isinstance(X_test, pd.DataFrame):
1013                    self.fit(X_train, X_test.iloc[0: self.h, :])
1014                else:
1015                    self.fit(X_train, X_test[0: self.h, :])
1016
1017        return self.models_

This function returns all the model objects trained in fit function. If fit is not called already, then we call fit and then return the models.

Parameters:

X_train : array-like,
    Training vectors, where rows is the number of samples
    and columns is the number of features.

X_test : array-like,
    Testing vectors, where rows is the number of samples
    and columns is the number of features.

Returns:

models: dict-object,
    Returns a dictionary with each model pipeline as value
    with key as name of models.
class MedianVotingRegressor(sklearn.ensemble._voting.VotingRegressor):
 6class MedianVotingRegressor(VotingRegressor):
 7    def predict(self, X):
 8        """
 9        Predict using the median of the base regressors' predictions.
10
11        Parameters:
12        X (array-like): Feature matrix for predictions.
13
14        Returns:
15        y_pred (array): Median of predictions from the base regressors.
16        """
17        predictions = np.asarray(
18            [regressor.predict(X) for regressor in self.estimators_]
19        )
20        return np.median(predictions, axis=0)

Prediction voting regressor for unfitted estimators.

A voting regressor is an ensemble meta-estimator that fits several base regressors, each on the whole dataset. Then it averages the individual predictions to form a final prediction.

Read more in the :ref:User Guide <voting_regressor>.

New in version 0.21.

Parameters

estimators : list of (str, estimator) tuples Invoking the fit method on the VotingRegressor will fit clones of those original estimators that will be stored in the class attribute self.estimators_. An estimator can be set to 'drop' using set_params().

*Changed in version 0.21:*
``'drop'`` is accepted. Using None was deprecated in 0.22 and
support was removed in 0.24.

weights : array-like of shape (n_regressors,), default=None Sequence of weights (float or int) to weight the occurrences of predicted values before averaging. Uses uniform weights if None.

n_jobs : int, default=None The number of jobs to run in parallel for fit. None means 1 unless in a joblib.parallel_backend context. -1 means using all processors. See :term:Glossary <n_jobs> for more details.

verbose : bool, default=False If True, the time elapsed while fitting will be printed as it is completed.

*New in version 0.23.*

Attributes

estimators_ : list of regressors The collection of fitted sub-estimators as defined in estimators that are not 'drop'.

named_estimators_ : ~sklearn.utils.Bunch Attribute to access any fitted sub-estimators by name.

*New in version 0.20.*

n_features_in_ : int Number of features seen during :term:fit. Only defined if the underlying regressor exposes such an attribute when fit.

*New in version 0.24.*

feature_names_in_ : ndarray of shape (n_features_in_,) Names of features seen during :term:fit. Only defined if the underlying estimators expose such an attribute when fit.

*New in version 1.0.*

See Also

VotingClassifier : Soft Voting/Majority Rule classifier.

Examples

>>> import numpy as np
>>> from sklearn.linear_model import LinearRegression
>>> from sklearn.ensemble import RandomForestRegressor
>>> from sklearn.ensemble import VotingRegressor
>>> from sklearn.neighbors import KNeighborsRegressor
>>> r1 = LinearRegression()
>>> r2 = RandomForestRegressor(n_estimators=10, random_state=1)
>>> r3 = KNeighborsRegressor()
>>> X = np.array([[1, 1], [2, 4], [3, 9], [4, 16], [5, 25], [6, 36]])
>>> y = np.array([2, 6, 12, 20, 30, 42])
>>> er = VotingRegressor([('lr', r1), ('rf', r2), ('r3', r3)])
>>> print(er.fit(X, y).predict(X))
[ 6.8...  8.4... 12.5... 17.8... 26...  34...]

In the following example, we drop the 'lr' estimator with ~VotingRegressor.set_params() and fit the remaining two estimators:

>>> er = er.set_params(lr='drop')
>>> er = er.fit(X, y)
>>> len(er.estimators_)
2
def predict(self, X):
 7    def predict(self, X):
 8        """
 9        Predict using the median of the base regressors' predictions.
10
11        Parameters:
12        X (array-like): Feature matrix for predictions.
13
14        Returns:
15        y_pred (array): Median of predictions from the base regressors.
16        """
17        predictions = np.asarray(
18            [regressor.predict(X) for regressor in self.estimators_]
19        )
20        return np.median(predictions, axis=0)

Predict using the median of the base regressors' predictions.

Parameters: X (array-like): Feature matrix for predictions.

Returns: y_pred (array): Median of predictions from the base regressors.

class MTS(nnetsauce.Base):
  28class MTS(Base):
  29    """Univariate and multivariate time series (MTS) forecasting with Quasi-Randomized networks
  30
  31    Parameters:
  32
  33        obj: object.
  34            any object containing a method fit (obj.fit()) and a method predict
  35            (obj.predict()).
  36
  37        n_hidden_features: int.
  38            number of nodes in the hidden layer.
  39
  40        activation_name: str.
  41            activation function: 'relu', 'tanh', 'sigmoid', 'prelu' or 'elu'.
  42
  43        a: float.
  44            hyperparameter for 'prelu' or 'elu' activation function.
  45
  46        nodes_sim: str.
  47            type of simulation for the nodes: 'sobol', 'hammersley', 'halton',
  48            'uniform'.
  49
  50        bias: boolean.
  51            indicates if the hidden layer contains a bias term (True) or not
  52            (False).
  53
  54        dropout: float.
  55            regularization parameter; (random) percentage of nodes dropped out
  56            of the training.
  57
  58        direct_link: boolean.
  59            indicates if the original predictors are included (True) in model's fitting or not (False).
  60
  61        n_clusters: int.
  62            number of clusters for 'kmeans' or 'gmm' clustering (could be 0: no clustering).
  63
  64        cluster_encode: bool.
  65            defines how the variable containing clusters is treated (default is one-hot)
  66            if `False`, then labels are used, without one-hot encoding.
  67
  68        type_clust: str.
  69            type of clustering method: currently k-means ('kmeans') or Gaussian
  70            Mixture Model ('gmm').
  71
  72        type_scaling: a tuple of 3 strings.
  73            scaling methods for inputs, hidden layer, and clustering respectively
  74            (and when relevant).
  75            Currently available: standardization ('std') or MinMax scaling ('minmax').
  76
  77        lags: int.
  78            number of lags used for each time series.
  79
  80        type_pi: str.
  81            type of prediction interval; currently:
  82            - "gaussian": simple, fast, but: assumes stationarity of Gaussian in-sample residuals and independence in the multivariate case
  83            - "kde": based on Kernel Density Estimation of in-sample residuals
  84            - "bootstrap": based on independent bootstrap of in-sample residuals
  85            - "block-bootstrap": based on basic block bootstrap of in-sample residuals
  86            - "scp-kde": Sequential split conformal prediction with Kernel Density Estimation of calibrated residuals
  87            - "scp-bootstrap": Sequential split conformal prediction with independent bootstrap of calibrated residuals
  88            - "scp-block-bootstrap": Sequential split conformal prediction with basic block bootstrap of calibrated residuals
  89            - "scp2-kde": Sequential split conformal prediction with Kernel Density Estimation of standardized calibrated residuals
  90            - "scp2-bootstrap": Sequential split conformal prediction with independent bootstrap of standardized calibrated residuals
  91            - "scp2-block-bootstrap": Sequential split conformal prediction with basic block bootstrap of standardized calibrated residuals
  92            - based on copulas of in-sample residuals: 'vine-tll', 'vine-bb1', 'vine-bb6', 'vine-bb7', 'vine-bb8', 'vine-clayton',
  93            'vine-frank', 'vine-gaussian', 'vine-gumbel', 'vine-indep', 'vine-joe', 'vine-student'
  94            - 'scp-vine-tll', 'scp-vine-bb1', 'scp-vine-bb6', 'scp-vine-bb7', 'scp-vine-bb8', 'scp-vine-clayton',
  95            'scp-vine-frank', 'scp-vine-gaussian', 'scp-vine-gumbel', 'scp-vine-indep', 'scp-vine-joe', 'scp-vine-student'
  96            - 'scp2-vine-tll', 'scp2-vine-bb1', 'scp2-vine-bb6', 'scp2-vine-bb7', 'scp2-vine-bb8', 'scp2-vine-clayton',
  97            'scp2-vine-frank', 'scp2-vine-gaussian', 'scp2-vine-gumbel', 'scp2-vine-indep', 'scp2-vine-joe', 'scp2-vine-student'
  98
  99        block_size: int.
 100            size of block for 'type_pi' in ("block-bootstrap", "scp-block-bootstrap", "scp2-block-bootstrap").
 101            Default is round(3.15*(n_residuals^1/3))
 102
 103        replications: int.
 104            number of replications (if needed, for predictive simulation). Default is 'None'.
 105
 106        kernel: str.
 107            the kernel to use for residuals density estimation (used for predictive simulation). Currently, either 'gaussian' or 'tophat'.
 108
 109        agg: str.
 110            either "mean" or "median" for simulation of bootstrap aggregating
 111
 112        seed: int.
 113            reproducibility seed for nodes_sim=='uniform' or predictive simulation.
 114
 115        backend: str.
 116            "cpu" or "gpu" or "tpu".
 117
 118        verbose: int.
 119            0: not printing; 1: printing
 120
 121        show_progress: bool.
 122            True: progress bar when fitting each series; False: no progress bar when fitting each series
 123
 124    Attributes:
 125
 126        fit_objs_: dict
 127            objects adjusted to each individual time series
 128
 129        y_: {array-like}
 130            MTS responses (most recent observations first)
 131
 132        X_: {array-like}
 133            MTS lags
 134
 135        xreg_: {array-like}
 136            external regressors
 137
 138        y_means_: dict
 139            a dictionary of each series mean values
 140
 141        preds_: {array-like}
 142            successive model predictions
 143
 144        preds_std_: {array-like}
 145            standard deviation around the predictions for Bayesian base learners (`obj`)
 146
 147        gaussian_preds_std_: {array-like}
 148            standard deviation around the predictions for `type_pi='gaussian'`
 149
 150        return_std_: boolean
 151            return uncertainty or not (set in predict)
 152
 153        df_: data frame
 154            the input data frame, in case a data.frame is provided to `fit`
 155
 156        n_obs_: int
 157            number of time series observations (number of rows for multivariate)
 158
 159        level_: int
 160            level of confidence for prediction intervals (default is 95)
 161
 162        residuals_: {array-like}
 163            in-sample residuals (for `type_pi` not conformal prediction) or calibrated residuals
 164            (for `type_pi` in conformal prediction)
 165
 166        residuals_sims_: tuple of {array-like}
 167            simulations of in-sample residuals (for `type_pi` not conformal prediction) or
 168            calibrated residuals (for `type_pi` in conformal prediction)
 169
 170        kde_: A scikit-learn object, see https://scikit-learn.org/stable/modules/generated/sklearn.neighbors.KernelDensity.html
 171
 172        residuals_std_dev_: residuals standard deviation
 173
 174    Examples:
 175
 176    Example 1:
 177
 178    ```python
 179    import nnetsauce as ns
 180    import numpy as np
 181    from sklearn import linear_model
 182    np.random.seed(123)
 183
 184    M = np.random.rand(10, 3)
 185    M[:,0] = 10*M[:,0]
 186    M[:,2] = 25*M[:,2]
 187    print(M)
 188
 189    # Adjust Bayesian Ridge
 190    regr4 = linear_model.BayesianRidge()
 191    obj_MTS = ns.MTS(regr4, lags = 1, n_hidden_features=5)
 192    obj_MTS.fit(M)
 193    print(obj_MTS.predict())
 194
 195    # with credible intervals
 196    print(obj_MTS.predict(return_std=True, level=80))
 197
 198    print(obj_MTS.predict(return_std=True, level=95))
 199    ```
 200
 201    Example 2:
 202
 203    ```python
 204    import nnetsauce as ns
 205    import numpy as np
 206    from sklearn import linear_model
 207
 208    dataset = {
 209    'date' : ['2001-01-01', '2002-01-01', '2003-01-01', '2004-01-01', '2005-01-01'],
 210    'series1' : [34, 30, 35.6, 33.3, 38.1],
 211    'series2' : [4, 5.5, 5.6, 6.3, 5.1],
 212    'series3' : [100, 100.5, 100.6, 100.2, 100.1]}
 213    df = pd.DataFrame(dataset).set_index('date')
 214    print(df)
 215
 216    # Adjust Bayesian Ridge
 217    regr5 = linear_model.BayesianRidge()
 218    obj_MTS = ns.MTS(regr5, lags = 1, n_hidden_features=5)
 219    obj_MTS.fit(df)
 220    print(obj_MTS.predict())
 221
 222    # with credible intervals
 223    print(obj_MTS.predict(return_std=True, level=80))
 224
 225    print(obj_MTS.predict(return_std=True, level=95))
 226    ```
 227    """
 228
 229    # construct the object -----
 230
 231    def __init__(
 232        self,
 233        obj,
 234        n_hidden_features=5,
 235        activation_name="relu",
 236        a=0.01,
 237        nodes_sim="sobol",
 238        bias=True,
 239        dropout=0,
 240        direct_link=True,
 241        n_clusters=2,
 242        cluster_encode=True,
 243        type_clust="kmeans",
 244        type_scaling=("std", "std", "std"),
 245        lags=1,
 246        type_pi="kde",
 247        block_size=None,
 248        replications=None,
 249        kernel="gaussian",
 250        agg="mean",
 251        seed=123,
 252        backend="cpu",
 253        verbose=0,
 254        show_progress=True,
 255    ):
 256        assert int(lags) == lags, "parameter 'lags' should be an integer"
 257
 258        super().__init__(
 259            n_hidden_features=n_hidden_features,
 260            activation_name=activation_name,
 261            a=a,
 262            nodes_sim=nodes_sim,
 263            bias=bias,
 264            dropout=dropout,
 265            direct_link=direct_link,
 266            n_clusters=n_clusters,
 267            cluster_encode=cluster_encode,
 268            type_clust=type_clust,
 269            type_scaling=type_scaling,
 270            seed=seed,
 271            backend=backend,
 272        )
 273
 274        self.obj = obj
 275        self.n_series = None
 276        self.lags = lags
 277        self.type_pi = type_pi
 278        self.block_size = block_size
 279        self.replications = replications
 280        self.kernel = kernel
 281        self.agg = agg
 282        self.verbose = verbose
 283        self.show_progress = show_progress
 284        self.series_names = None
 285        self.input_dates = None
 286        self.fit_objs_ = {}
 287        self.y_ = None  # MTS responses (most recent observations first)
 288        self.X_ = None  # MTS lags
 289        self.xreg_ = None
 290        self.y_means_ = {}
 291        self.mean_ = None
 292        self.upper_ = None
 293        self.lower_ = None
 294        self.output_dates_ = None
 295        self.preds_std_ = []
 296        self.gaussian_preds_std_ = None
 297        self.alpha_ = None
 298        self.return_std_ = None
 299        self.df_ = None
 300        self.residuals_ = []
 301        self.abs_calib_residuals_ = None
 302        self.calib_residuals_quantile_ = None
 303        self.residuals_sims_ = None
 304        self.kde_ = None
 305        self.sims_ = None
 306        self.residuals_std_dev_ = None
 307        self.n_obs_ = None
 308        self.level_ = None
 309        self.scaled_Z_ = None
 310
 311    def fit(self, X, xreg=None, **kwargs):
 312        """Fit MTS model to training data X, with optional regressors xreg
 313
 314        Parameters:
 315
 316        X: {array-like}, shape = [n_samples, n_features]
 317            Training time series, where n_samples is the number
 318            of samples and n_features is the number of features;
 319            X must be in increasing order (most recent observations last)
 320
 321        xreg: {array-like}, shape = [n_samples, n_features_xreg]
 322            Additional (external) regressors to be passed to self.obj
 323            xreg must be in 'increasing' order (most recent observations last)
 324
 325        **kwargs: for now, additional parameters to be passed to for kernel density estimation, when needed (see sklearn.neighbors.KernelDensity)
 326
 327        Returns:
 328
 329        self: object
 330        """
 331
 332        if (
 333            isinstance(X, pd.DataFrame) is False
 334        ):  # input data set is a numpy array
 335
 336            if xreg is None:
 337                X = pd.DataFrame(X)
 338                self.series_names = [
 339                    "series" + str(i) for i in range(X.shape[1])
 340                ]
 341            else:  # xreg is not None
 342                X = mo.cbind(X, xreg)
 343                self.xreg_ = xreg
 344
 345        else:  # input data set is a DataFrame with column names
 346
 347            # if "date" in X.columns:
 348            #    X.index = X["date"]
 349            #    X.drop(['date'], axis=1, inplace=True)
 350
 351            X_index = None
 352            if X.index is not None:
 353                X_index = X.index
 354            if xreg is None:
 355                X = copy.deepcopy(mo.convert_df_to_numeric(X))
 356            else:
 357                X = copy.deepcopy(mo.cbind(mo.convert_df_to_numeric(X), xreg))
 358                self.xreg_ = xreg
 359            if X_index is not None:
 360                X.index = X_index
 361            self.series_names = X.columns.tolist()
 362
 363        if isinstance(X, pd.DataFrame):
 364            if self.df_ is None:
 365                self.df_ = X
 366                X = X.values
 367            else:
 368                input_dates_prev = pd.DatetimeIndex(self.df_.index.values)
 369                frequency = pd.infer_freq(input_dates_prev)
 370                self.df_ = pd.concat([self.df_, X], axis=0)
 371                self.input_dates = pd.date_range(
 372                    start=input_dates_prev[0],
 373                    periods=len(input_dates_prev) + X.shape[0],
 374                    freq=frequency,
 375                ).values.tolist()
 376                self.df_.index = self.input_dates
 377                X = self.df_.values
 378            self.df_.columns = self.series_names
 379        else:
 380            if self.df_ is None:
 381                self.df_ = pd.DataFrame(X, columns=self.series_names)
 382            else:
 383                self.df_ = pd.concat(
 384                    [self.df_, pd.DataFrame(X, columns=self.series_names)],
 385                    axis=0,
 386                )
 387
 388        self.input_dates = ts.compute_input_dates(self.df_)
 389
 390        try:
 391            # multivariate time series
 392            n, p = X.shape
 393        except:
 394            # univariate time series
 395            n = X.shape[0]
 396            p = 1
 397
 398        self.n_obs_ = n
 399
 400        rep_1_n = np.repeat(1, n)
 401
 402        self.y_ = None
 403        self.X_ = None
 404        self.n_series = p
 405        self.fit_objs_.clear()
 406        try:
 407            self.y_means_.clear()
 408        except AttributeError:
 409            self.y_means_ = None
 410        residuals_ = []
 411        self.residuals_ = None
 412        self.residuals_sims_ = None
 413        self.kde_ = None
 414        self.sims_ = None
 415        self.scaled_Z_ = None
 416        self.centered_y_is_ = []
 417
 418        if p > 1:
 419            # multivariate time series
 420            mts_input = ts.create_train_inputs(X[::-1], self.lags)
 421        else:
 422            # univariate time series
 423            mts_input = ts.create_train_inputs(
 424                X.reshape(-1, 1)[::-1], self.lags
 425            )
 426
 427        self.y_ = mts_input[0]
 428
 429        self.X_ = mts_input[1]
 430
 431        dummy_y, scaled_Z = self.cook_training_set(y=rep_1_n, X=self.X_)
 432
 433        self.scaled_Z_ = scaled_Z
 434
 435        # loop on all the time series and adjust self.obj.fit
 436        if self.verbose > 0:
 437            print(
 438                f"\n Adjusting {type(self.obj).__name__} to multivariate time series... \n "
 439            )
 440
 441        if self.type_pi in (
 442            "gaussian",
 443            "kde",
 444            "bootstrap",
 445            "block-bootstrap",
 446        ) or self.type_pi.startswith("vine"):
 447
 448            try:  # multioutput regressor
 449
 450                self.y_means_ = np.mean(self.y_, axis=0)
 451                centered_y = self.y_ - self.y_means_
 452                self.obj.fit(X=scaled_Z, y=centered_y)
 453                residuals_ = centered_y - self.obj.predict(scaled_Z)
 454                self.residuals_ = residuals_
 455
 456            except Exception:  # single output regressor
 457
 458                if self.show_progress is True:
 459                    iterator = tqdm(range(p))
 460                else:
 461                    iterator = range(p)
 462
 463                for i in iterator:
 464                    y_mean = np.mean(self.y_[:, i])
 465                    self.y_means_[i] = y_mean
 466                    centered_y_i = self.y_[:, i] - y_mean
 467                    self.centered_y_is_.append(centered_y_i)
 468                    self.obj.fit(X=scaled_Z, y=centered_y_i)
 469                    self.fit_objs_[i] = deepcopy(self.obj)
 470                    residuals_.append(
 471                        (
 472                            centered_y_i - self.fit_objs_[i].predict(scaled_Z)
 473                        ).tolist()
 474                    )
 475
 476        if self.type_pi.startswith("scp"):
 477
 478            # split conformal prediction
 479            n_y = self.y_.shape[0]
 480            n_y_half = n_y // 2
 481            first_half_idx = range(0, n_y_half)
 482            second_half_idx = range(n_y_half, n_y)
 483
 484            try:  # multioutput regressor
 485
 486                y_mean_temp = np.mean(self.y_[first_half_idx, :], axis=0)
 487                centered_y_temp = self.y_[first_half_idx, :] - y_mean_temp
 488                self.obj.fit(X=scaled_Z[first_half_idx, :], y=centered_y_temp)
 489                residuals_ = (
 490                    self.y_[second_half_idx, :]
 491                    - y_mean_temp
 492                    - self.obj.predict(scaled_Z[second_half_idx, :])
 493                )
 494                self.y_means_ = np.mean(self.y_[second_half_idx, :], axis=0)
 495                centered_y = (
 496                    self.y_[second_half_idx, :] - self.y_means_[:, np.newaxis]
 497                )
 498                self.obj.fit(X=scaled_Z[second_half_idx, :], y=centered_y)
 499                self.residuals_ = np.asarray(residuals_)
 500
 501            except Exception:  # single output regressor
 502
 503                if self.show_progress is True:
 504                    iterator = tqdm(range(p))
 505                else:
 506                    iterator = range(p)
 507
 508                residuals_ = []
 509
 510                for i in iterator:
 511                    y_mean_temp = np.mean(self.y_[first_half_idx, i])
 512                    centered_y_i_temp = self.y_[first_half_idx, i] - y_mean_temp
 513                    self.obj.fit(
 514                        X=scaled_Z[first_half_idx, :], y=centered_y_i_temp
 515                    )
 516                    # calibrated residuals actually
 517                    residuals_.append(
 518                        (
 519                            self.y_[second_half_idx, i]
 520                            - (
 521                                y_mean_temp
 522                                + self.obj.predict(scaled_Z[second_half_idx, :])
 523                            )
 524                        ).tolist()
 525                    )
 526                    # fit on the second half
 527                    y_mean = np.mean(self.y_[second_half_idx, i])
 528                    self.y_means_[i] = y_mean
 529                    centered_y_i = self.y_[second_half_idx, i] - y_mean
 530                    self.obj.fit(X=scaled_Z[second_half_idx, :], y=centered_y_i)
 531                    self.fit_objs_[i] = deepcopy(self.obj)
 532
 533                self.residuals_ = np.asarray(residuals_).T
 534
 535        if self.type_pi == "gaussian":
 536            self.gaussian_preds_std_ = np.std(self.residuals_, axis=0)
 537
 538        if self.type_pi.startswith("scp2"):
 539            # Calculate mean and standard deviation for each column
 540            data_mean = np.mean(self.residuals_, axis=0)
 541            self.residuals_std_dev_ = np.std(self.residuals_, axis=0)
 542            # Center and scale the array using broadcasting
 543            self.residuals_ = (
 544                self.residuals_ - data_mean[np.newaxis, :]
 545            ) / self.residuals_std_dev_[np.newaxis, :]
 546
 547        if self.replications != None and "kde" in self.type_pi:
 548            if self.verbose > 0:
 549                print(f"\n Simulate residuals using {self.kernel} kernel... \n")
 550            assert self.kernel in (
 551                "gaussian",
 552                "tophat",
 553            ), "currently, 'kernel' must be either 'gaussian' or 'tophat'"
 554            kernel_bandwidths = {"bandwidth": np.logspace(-6, 6, 150)}
 555            grid = GridSearchCV(
 556                KernelDensity(kernel=self.kernel, **kwargs),
 557                param_grid=kernel_bandwidths,
 558            )
 559            grid.fit(self.residuals_)
 560
 561            if self.verbose > 0:
 562                print(
 563                    f"\n Best parameters for {self.kernel} kernel: {grid.best_params_} \n"
 564                )
 565
 566            self.kde_ = grid.best_estimator_
 567
 568        return self
 569
 570    def partial_fit(self, X, xreg=None, **kwargs):
 571        """Update the model with new observations X, with optional regressors xreg
 572
 573        Parameters:
 574
 575        X: {array-like}, shape = [n_samples, n_features]
 576            Training time series, where n_samples is the number
 577            of samples and n_features is the number of features;
 578            X must be in increasing order (most recent observations last)
 579
 580        xreg: {array-like}, shape = [n_samples, n_features_xreg]
 581            Additional (external) regressors to be passed to self.obj
 582            xreg must be in 'increasing' order (most recent observations last)
 583
 584        **kwargs: for now, additional parameters to be passed to for kernel density estimation, when needed (see sklearn.neighbors.KernelDensity)
 585
 586        Returns:
 587
 588        self: object
 589        """
 590
 591        assert self.df_ is not None, "fit() must be called before partial_fit()"
 592
 593        if (isinstance(X, pd.DataFrame) is False) and isinstance(
 594            X, pd.Series
 595        ) is False:
 596            if len(X.shape) == 1:
 597                X = X.reshape(1, -1)
 598
 599            return self.fit(X, xreg, **kwargs)
 600
 601        if len(X.shape) == 1:
 602            X = pd.DataFrame(X.values.reshape(1, -1), columns=self.df_.columns)
 603
 604        return self.fit(X, xreg, **kwargs)
 605
 606    def predict(self, h=5, level=95, **kwargs):
 607        """Forecast all the time series, h steps ahead
 608
 609        Parameters:
 610
 611        h: {integer}
 612            Forecasting horizon
 613
 614        level: {integer}
 615            Level of confidence (if obj has option 'return_std' and the
 616            posterior is gaussian)
 617
 618        new_xreg: {array-like}, shape = [n_samples = h, n_new_xreg]
 619            New values of additional (deterministic) regressors on horizon = h
 620            new_xreg must be in increasing order (most recent observations last)
 621
 622        **kwargs: additional parameters to be passed to
 623                self.cook_test_set
 624
 625        Returns:
 626
 627        model predictions for horizon = h: {array-like}, data frame or tuple.
 628        Standard deviation and prediction intervals are returned when
 629        `obj.predict` can return standard deviation
 630
 631        """
 632
 633        self.output_dates_, frequency = ts.compute_output_dates(self.df_, h)
 634
 635        self.level_ = level
 636
 637        self.return_std_ = False  # do not remove (/!\)
 638
 639        self.mean_ = None  # do not remove (/!\)
 640
 641        self.mean_ = deepcopy(self.y_)  # do not remove (/!\)
 642
 643        self.lower_ = None  # do not remove (/!\)
 644
 645        self.upper_ = None  # do not remove (/!\)
 646
 647        self.sims_ = None  # do not remove (/!\)
 648
 649        y_means_ = np.asarray([self.y_means_[i] for i in range(self.n_series)])
 650
 651        n_features = self.n_series * self.lags
 652
 653        self.alpha_ = 100 - level
 654
 655        pi_multiplier = norm.ppf(1 - self.alpha_ / 200)
 656
 657        if "return_std" in kwargs:  # bayesian forecasting
 658            self.return_std_ = True
 659            self.preds_std_ = []
 660            DescribeResult = namedtuple(
 661                "DescribeResult", ("mean", "lower", "upper")
 662            )  # to be updated
 663
 664        if "return_pi" in kwargs:  # split conformal, without simulation
 665            mean_pi_ = []
 666            lower_pi_ = []
 667            upper_pi_ = []
 668            DescribeResult = namedtuple(
 669                "DescribeResult", ("mean", "lower", "upper")
 670            )  # to be updated
 671
 672        if self.kde_ != None and "kde" in self.type_pi:  # kde
 673            if self.verbose == 1:
 674                self.residuals_sims_ = tuple(
 675                    self.kde_.sample(
 676                        n_samples=h, random_state=self.seed + 100 * i
 677                    )
 678                    for i in tqdm(range(self.replications))
 679                )
 680            elif self.verbose == 0:
 681                self.residuals_sims_ = tuple(
 682                    self.kde_.sample(
 683                        n_samples=h, random_state=self.seed + 100 * i
 684                    )
 685                    for i in range(self.replications)
 686                )
 687
 688        if self.type_pi in ("bootstrap", "scp-bootstrap", "scp2-bootstrap"):
 689            assert self.replications is not None and isinstance(
 690                self.replications, int
 691            ), "'replications' must be provided and be an integer"
 692            if self.verbose == 1:
 693                self.residuals_sims_ = tuple(
 694                    ts.bootstrap(
 695                        self.residuals_,
 696                        h=h,
 697                        block_size=None,
 698                        seed=self.seed + 100 * i,
 699                    )
 700                    for i in tqdm(range(self.replications))
 701                )
 702            elif self.verbose == 0:
 703                self.residuals_sims_ = tuple(
 704                    ts.bootstrap(
 705                        self.residuals_,
 706                        h=h,
 707                        block_size=None,
 708                        seed=self.seed + 100 * i,
 709                    )
 710                    for i in range(self.replications)
 711                )
 712
 713        if self.type_pi in (
 714            "block-bootstrap",
 715            "scp-block-bootstrap",
 716            "scp2-block-bootstrap",
 717        ):
 718            if self.block_size is None:
 719                self.block_size = int(
 720                    np.ceil(3.15 * (self.residuals_.shape[0] ** (1 / 3)))
 721                )
 722
 723            assert self.replications is not None and isinstance(
 724                self.replications, int
 725            ), "'replications' must be provided and be an integer"
 726            if self.verbose == 1:
 727                self.residuals_sims_ = tuple(
 728                    ts.bootstrap(
 729                        self.residuals_,
 730                        h=h,
 731                        block_size=self.block_size,
 732                        seed=self.seed + 100 * i,
 733                    )
 734                    for i in tqdm(range(self.replications))
 735                )
 736            elif self.verbose == 0:
 737                self.residuals_sims_ = tuple(
 738                    ts.bootstrap(
 739                        self.residuals_,
 740                        h=h,
 741                        block_size=self.block_size,
 742                        seed=self.seed + 100 * i,
 743                    )
 744                    for i in range(self.replications)
 745                )
 746
 747        if "vine" in self.type_pi:
 748            if self.verbose == 1:
 749                self.residuals_sims_ = tuple(
 750                    vinecopula_sample(
 751                        x=self.residuals_,
 752                        n_samples=h,
 753                        method=self.type_pi,
 754                        random_state=self.seed + 100 * i,
 755                    )
 756                    for i in tqdm(range(self.replications))
 757                )
 758            elif self.verbose == 0:
 759                self.residuals_sims_ = tuple(
 760                    vinecopula_sample(
 761                        x=self.residuals_,
 762                        n_samples=h,
 763                        method=self.type_pi,
 764                        random_state=self.seed + 100 * i,
 765                    )
 766                    for i in range(self.replications)
 767                )
 768
 769        for _ in range(h):
 770
 771            new_obs = ts.reformat_response(self.mean_, self.lags)
 772
 773            new_X = new_obs.reshape(1, n_features)
 774
 775            cooked_new_X = self.cook_test_set(new_X, **kwargs)
 776
 777            if "return_std" in kwargs:
 778                try:  # multioutput regressor
 779                    self.preds_std_ = self.obj.predict(
 780                        cooked_new_X, return_std=True
 781                    )[1]
 782                except Exception:  # single output regressor
 783                    self.preds_std_.append(
 784                        [
 785                            np.asarray(
 786                                self.fit_objs_[i].predict(
 787                                    cooked_new_X, return_std=True
 788                                )[1]
 789                            ).item()
 790                            for i in range(self.n_series)
 791                        ]
 792                    )
 793
 794            if "return_pi" in kwargs:
 795                try:
 796                    preds_pi = self.obj.predict(cooked_new_X, return_pi=True)
 797                    mean_pi_.append(preds_pi.mean[0])
 798                    lower_pi_.append(preds_pi.lower[0])
 799                    upper_pi_.append(preds_pi.upper[0])
 800                except Exception:
 801                    for i in range(self.n_series):
 802                        preds_pi = self.fit_objs_[i].predict(
 803                            cooked_new_X, return_pi=True
 804                        )
 805                        mean_pi_.append(preds_pi.mean[0])
 806                        lower_pi_.append(preds_pi.lower[0])
 807                        upper_pi_.append(preds_pi.upper[0])
 808
 809            try:
 810                predicted_cooked_new_X = self.obj.predict(cooked_new_X)
 811            except Exception:
 812                predicted_cooked_new_X = np.asarray(
 813                    [
 814                        np.asarray(
 815                            self.fit_objs_[i].predict(cooked_new_X)
 816                        ).item()
 817                        for i in range(self.n_series)
 818                    ]
 819                )
 820
 821            preds = np.asarray(y_means_ + predicted_cooked_new_X)
 822
 823            self.mean_ = mo.rbind(preds, self.mean_)  # preallocate?
 824
 825        # function's return ----------------------------------------------------------------------
 826        self.mean_ = pd.DataFrame(
 827            self.mean_[0:h, :][::-1],
 828            columns=self.df_.columns,
 829            index=self.output_dates_,
 830        )
 831
 832        if (
 833            (("return_std" not in kwargs) and ("return_pi" not in kwargs))
 834            and (self.type_pi not in ("gaussian", "scp"))
 835        ) or ("vine" in self.type_pi):
 836
 837            if self.replications is None:
 838                return self.mean_
 839
 840            # if "return_std" not in kwargs and self.replications is not None
 841            meanf = []
 842            lower = []
 843            upper = []
 844
 845            if "scp2" in self.type_pi:
 846
 847                if self.verbose == 1:
 848                    self.sims_ = tuple(
 849                        (
 850                            self.mean_
 851                            + self.residuals_sims_[i]
 852                            * self.residuals_std_dev_[np.newaxis, :]
 853                            for i in tqdm(range(self.replications))
 854                        )
 855                    )
 856                elif self.verbose == 0:
 857                    self.sims_ = tuple(
 858                        (
 859                            self.mean_
 860                            + self.residuals_sims_[i]
 861                            * self.residuals_std_dev_[np.newaxis, :]
 862                            for i in range(self.replications)
 863                        )
 864                    )
 865            else:
 866
 867                if self.verbose == 1:
 868                    self.sims_ = tuple(
 869                        (
 870                            self.mean_ + self.residuals_sims_[i]
 871                            for i in tqdm(range(self.replications))
 872                        )
 873                    )
 874                elif self.verbose == 0:
 875                    self.sims_ = tuple(
 876                        (
 877                            self.mean_ + self.residuals_sims_[i]
 878                            for i in range(self.replications)
 879                        )
 880                    )
 881
 882            DescribeResult = namedtuple(
 883                "DescribeResult", ("mean", "sims", "lower", "upper")
 884            )
 885            for ix in range(self.n_series):
 886                sims_ix = getsims(self.sims_, ix)
 887                if self.agg == "mean":
 888                    meanf.append(np.mean(sims_ix, axis=1))
 889                else:
 890                    meanf.append(np.median(sims_ix, axis=1))
 891                lower.append(np.quantile(sims_ix, q=self.alpha_ / 200, axis=1))
 892                upper.append(
 893                    np.quantile(sims_ix, q=1 - self.alpha_ / 200, axis=1)
 894                )
 895
 896            self.mean_ = pd.DataFrame(
 897                np.asarray(meanf).T,
 898                columns=self.series_names,  # self.df_.columns,
 899                index=self.output_dates_,
 900            )
 901
 902            self.lower_ = pd.DataFrame(
 903                np.asarray(lower).T,
 904                columns=self.series_names,  # self.df_.columns,
 905                index=self.output_dates_,
 906            )
 907
 908            self.upper_ = pd.DataFrame(
 909                np.asarray(upper).T,
 910                columns=self.series_names,  # self.df_.columns,
 911                index=self.output_dates_,
 912            )
 913
 914            res = DescribeResult(
 915                self.mean_, self.sims_, self.lower_, self.upper_
 916            )
 917
 918            if self.xreg_ is not None:
 919
 920                if len(self.xreg_.shape) > 1:
 921
 922                    res2 = mx.tuple_map(
 923                        res,
 924                        lambda x: mo.delete_last_columns(
 925                            x, num_columns=self.xreg_.shape[1]
 926                        ),
 927                    )
 928
 929                else:
 930
 931                    res2 = mx.tuple_map(
 932                        res, lambda x: mo.delete_last_columns(x, num_columns=1)
 933                    )
 934
 935                return res2
 936
 937            else:
 938
 939                return res
 940
 941        if (
 942            (("return_std" in kwargs) or ("return_pi" in kwargs))
 943            and (self.type_pi not in ("gaussian", "scp"))
 944        ) or "vine" in self.type_pi:
 945            DescribeResult = namedtuple(
 946                "DescribeResult", ("mean", "lower", "upper")
 947            )
 948
 949            self.mean_ = pd.DataFrame(
 950                np.asarray(self.mean_),
 951                columns=self.series_names,  # self.df_.columns,
 952                index=self.output_dates_,
 953            )
 954
 955            if "return_std" in kwargs:
 956
 957                self.preds_std_ = np.asarray(self.preds_std_)
 958
 959                self.lower_ = pd.DataFrame(
 960                    self.mean_.values - pi_multiplier * self.preds_std_,
 961                    columns=self.series_names,  # self.df_.columns,
 962                    index=self.output_dates_,
 963                )
 964
 965                self.upper_ = pd.DataFrame(
 966                    self.mean_.values + pi_multiplier * self.preds_std_,
 967                    columns=self.series_names,  # self.df_.columns,
 968                    index=self.output_dates_,
 969                )
 970
 971            if "return_pi" in kwargs:
 972
 973                self.lower_ = pd.DataFrame(
 974                    np.asarray(lower_pi_).reshape(h, self.n_series)
 975                    + y_means_[np.newaxis, :],
 976                    columns=self.series_names,  # self.df_.columns,
 977                    index=self.output_dates_,
 978                )
 979
 980                self.upper_ = pd.DataFrame(
 981                    np.asarray(upper_pi_).reshape(h, self.n_series)
 982                    + y_means_[np.newaxis, :],
 983                    columns=self.series_names,  # self.df_.columns,
 984                    index=self.output_dates_,
 985                )
 986
 987            res = DescribeResult(self.mean_, self.lower_, self.upper_)
 988
 989            if self.xreg_ is not None:
 990                if len(self.xreg_.shape) > 1:
 991                    res2 = mx.tuple_map(
 992                        res,
 993                        lambda x: mo.delete_last_columns(
 994                            x, num_columns=self.xreg_.shape[1]
 995                        ),
 996                    )
 997                else:
 998                    res2 = mx.tuple_map(
 999                        res, lambda x: mo.delete_last_columns(x, num_columns=1)
1000                    )
1001                return DescribeResult(res2[0], res2[1], res2[2])
1002
1003            return res
1004
1005        if self.type_pi == "gaussian":
1006
1007            DescribeResult = namedtuple(
1008                "DescribeResult", ("mean", "lower", "upper")
1009            )
1010
1011            self.mean_ = pd.DataFrame(
1012                np.asarray(self.mean_),
1013                columns=self.series_names,  # self.df_.columns,
1014                index=self.output_dates_,
1015            )
1016
1017            self.lower_ = pd.DataFrame(
1018                self.mean_.values - pi_multiplier * self.gaussian_preds_std_,
1019                columns=self.series_names,  # self.df_.columns,
1020                index=self.output_dates_,
1021            )
1022
1023            self.upper_ = pd.DataFrame(
1024                self.mean_.values + pi_multiplier * self.gaussian_preds_std_,
1025                columns=self.series_names,  # self.df_.columns,
1026                index=self.output_dates_,
1027            )
1028
1029            res = DescribeResult(self.mean_, self.lower_, self.upper_)
1030
1031            if self.xreg_ is not None:
1032                if len(self.xreg_.shape) > 1:
1033                    res2 = mx.tuple_map(
1034                        res,
1035                        lambda x: mo.delete_last_columns(
1036                            x, num_columns=self.xreg_.shape[1]
1037                        ),
1038                    )
1039                else:
1040                    res2 = mx.tuple_map(
1041                        res, lambda x: mo.delete_last_columns(x, num_columns=1)
1042                    )
1043                return DescribeResult(res2[0], res2[1], res2[2])
1044
1045            return res
1046
1047    def score(self, X, training_index, testing_index, scoring=None, **kwargs):
1048        """Train on training_index, score on testing_index."""
1049
1050        assert (
1051            bool(set(training_index).intersection(set(testing_index))) == False
1052        ), "Non-overlapping 'training_index' and 'testing_index' required"
1053
1054        # Dimensions
1055        try:
1056            # multivariate time series
1057            n, p = X.shape
1058        except:
1059            # univariate time series
1060            n = X.shape[0]
1061            p = 1
1062
1063        # Training and testing sets
1064        if p > 1:
1065            X_train = X[training_index, :]
1066            X_test = X[testing_index, :]
1067        else:
1068            X_train = X[training_index]
1069            X_test = X[testing_index]
1070
1071        # Horizon
1072        h = len(testing_index)
1073        assert (
1074            len(training_index) + h
1075        ) <= n, "Please check lengths of training and testing windows"
1076
1077        # Fit and predict
1078        self.fit(X_train, **kwargs)
1079        preds = self.predict(h=h, **kwargs)
1080
1081        if scoring is None:
1082            scoring = "neg_root_mean_squared_error"
1083
1084        # check inputs
1085        assert scoring in (
1086            "explained_variance",
1087            "neg_mean_absolute_error",
1088            "neg_mean_squared_error",
1089            "neg_root_mean_squared_error",
1090            "neg_mean_squared_log_error",
1091            "neg_median_absolute_error",
1092            "r2",
1093        ), "'scoring' should be in ('explained_variance', 'neg_mean_absolute_error', \
1094                               'neg_mean_squared_error', 'neg_root_mean_squared_error', 'neg_mean_squared_log_error', \
1095                               'neg_median_absolute_error', 'r2')"
1096
1097        scoring_options = {
1098            "explained_variance": skm2.explained_variance_score,
1099            "neg_mean_absolute_error": skm2.mean_absolute_error,
1100            "neg_mean_squared_error": lambda x, y: np.mean((x - y) ** 2),
1101            "neg_root_mean_squared_error": lambda x, y: np.sqrt(
1102                np.mean((x - y) ** 2)
1103            ),
1104            "neg_mean_squared_log_error": skm2.mean_squared_log_error,
1105            "neg_median_absolute_error": skm2.median_absolute_error,
1106            "r2": skm2.r2_score,
1107        }
1108
1109        # if p > 1:
1110        #     return tuple(
1111        #         [
1112        #             scoring_options[scoring](
1113        #                 X_test[:, i], preds[:, i]#, **kwargs
1114        #             )
1115        #             for i in range(p)
1116        #         ]
1117        #     )
1118        # else:
1119        return scoring_options[scoring](X_test, preds)
1120
1121    def plot(self, series=None, type_axis="dates", type_plot="pi"):
1122        """Plot time series forecast
1123
1124        Parameters:
1125
1126        series: {integer} or {string}
1127            series index or name
1128
1129        """
1130
1131        assert all(
1132            [
1133                self.mean_ is not None,
1134                self.lower_ is not None,
1135                self.upper_ is not None,
1136                self.output_dates_ is not None,
1137            ]
1138        ), "model forecasting must be obtained first (with predict)"
1139
1140        if series is None:
1141            assert (
1142                self.n_series == 1
1143            ), "please specify series index or name (n_series > 1)"
1144            series = 0
1145
1146        if isinstance(series, str):
1147            assert (
1148                series in self.series_names
1149            ), f"series {series} doesn't exist in the input dataset"
1150            series_idx = self.df_.columns.get_loc(series)
1151        else:
1152            assert isinstance(series, int) and (
1153                0 <= series < self.n_series
1154            ), f"check series index (< {self.n_series})"
1155            series_idx = series
1156
1157        y_all = list(self.df_.iloc[:, series_idx]) + list(
1158            self.mean_.iloc[:, series_idx]
1159        )
1160        y_test = list(self.mean_.iloc[:, series_idx])
1161        n_points_all = len(y_all)
1162        n_points_train = self.df_.shape[0]
1163
1164        if type_axis == "numeric":
1165            x_all = [i for i in range(n_points_all)]
1166            x_test = [i for i in range(n_points_train, n_points_all)]
1167
1168        if type_axis == "dates":  # use dates
1169            x_all = np.concatenate(
1170                (self.input_dates.values, self.output_dates_.values), axis=None
1171            )
1172            x_test = self.output_dates_.values
1173
1174        if type_plot == "pi":
1175            fig, ax = plt.subplots()
1176            ax.plot(x_all, y_all, "-")
1177            ax.plot(x_test, y_test, "-", color="orange")
1178            ax.fill_between(
1179                x_test,
1180                self.lower_.iloc[:, series_idx],
1181                self.upper_.iloc[:, series_idx],
1182                alpha=0.2,
1183                color="orange",
1184            )
1185            if self.replications is None:
1186                if self.n_series > 1:
1187                    plt.title(
1188                        f"prediction intervals for {series}",
1189                        loc="left",
1190                        fontsize=12,
1191                        fontweight=0,
1192                        color="black",
1193                    )
1194                else:
1195                    plt.title(
1196                        f"prediction intervals for input time series",
1197                        loc="left",
1198                        fontsize=12,
1199                        fontweight=0,
1200                        color="black",
1201                    )
1202                plt.show()
1203            else:  # self.replications is not None
1204                if self.n_series > 1:
1205                    plt.title(
1206                        f"prediction intervals for {self.replications} simulations of {series}",
1207                        loc="left",
1208                        fontsize=12,
1209                        fontweight=0,
1210                        color="black",
1211                    )
1212                else:
1213                    plt.title(
1214                        f"prediction intervals for {self.replications} simulations of input time series",
1215                        loc="left",
1216                        fontsize=12,
1217                        fontweight=0,
1218                        color="black",
1219                    )
1220                plt.show()
1221
1222        if type_plot == "spaghetti":
1223            palette = plt.get_cmap("Set1")
1224            sims_ix = getsims(self.sims_, series_idx)
1225            plt.plot(x_all, y_all, "-")
1226            for col_ix in range(
1227                sims_ix.shape[1]
1228            ):  # avoid this when there are thousands of simulations
1229                plt.plot(
1230                    x_test,
1231                    sims_ix[:, col_ix],
1232                    "-",
1233                    color=palette(col_ix),
1234                    linewidth=1,
1235                    alpha=0.9,
1236                )
1237            plt.plot(x_all, y_all, "-", color="black")
1238            plt.plot(x_test, y_test, "-", color="blue")
1239            # Add titles
1240            if self.n_series > 1:
1241                plt.title(
1242                    f"{self.replications} simulations of {series}",
1243                    loc="left",
1244                    fontsize=12,
1245                    fontweight=0,
1246                    color="black",
1247                )
1248            else:
1249                plt.title(
1250                    f"{self.replications} simulations of input time series",
1251                    loc="left",
1252                    fontsize=12,
1253                    fontweight=0,
1254                    color="black",
1255                )
1256            plt.xlabel("Time")
1257            plt.ylabel("Values")
1258            # Show the graph
1259            plt.show()
1260
1261    def cross_val_score(
1262        self,
1263        X,
1264        scoring="root_mean_squared_error",
1265        n_jobs=None,
1266        verbose=0,
1267        xreg=None,
1268        initial_window=5,
1269        horizon=3,
1270        fixed_window=False,
1271        show_progress=True,
1272        level=95,
1273        **kwargs,
1274    ):
1275        """Evaluate a score by time series cross-validation.
1276
1277        Parameters:
1278
1279            X: {array-like, sparse matrix} of shape (n_samples, n_features)
1280                The data to fit.
1281
1282            scoring: str or a function
1283                A str in ('root_mean_squared_error', 'mean_squared_error', 'mean_error',
1284                'mean_absolute_error', 'mean_error', 'mean_percentage_error',
1285                'mean_absolute_percentage_error',  'winkler_score', 'coverage')
1286                Or a function defined as 'coverage' and 'winkler_score' in `utils.timeseries`
1287
1288            n_jobs: int, default=None
1289                Number of jobs to run in parallel.
1290
1291            verbose: int, default=0
1292                The verbosity level.
1293
1294            xreg: array-like, optional (default=None)
1295                Additional (external) regressors to be passed to `fit`
1296                xreg must be in 'increasing' order (most recent observations last)
1297
1298            initial_window: int
1299                initial number of consecutive values in each training set sample
1300
1301            horizon: int
1302                number of consecutive values in test set sample
1303
1304            fixed_window: boolean
1305                if False, all training samples start at index 0, and the training
1306                window's size is increasing.
1307                if True, the training window's size is fixed, and the window is
1308                rolling forward
1309
1310            show_progress: boolean
1311                if True, a progress bar is printed
1312
1313            **kwargs: dict
1314                additional parameters to be passed to `fit` and `predict`
1315
1316        Returns:
1317
1318            A tuple: descriptive statistics or errors and raw errors
1319
1320        """
1321        tscv = TimeSeriesSplit()
1322
1323        tscv_obj = tscv.split(
1324            X,
1325            initial_window=initial_window,
1326            horizon=horizon,
1327            fixed_window=fixed_window,
1328        )
1329
1330        if isinstance(scoring, str):
1331
1332            assert scoring in (
1333                "root_mean_squared_error",
1334                "mean_squared_error",
1335                "mean_error",
1336                "mean_absolute_error",
1337                "mean_percentage_error",
1338                "mean_absolute_percentage_error",
1339                "winkler_score",
1340                "coverage",
1341            ), "must have scoring in ('root_mean_squared_error', 'mean_squared_error', 'mean_error', 'mean_absolute_error', 'mean_error', 'mean_percentage_error', 'mean_absolute_percentage_error',  'winkler_score', 'coverage')"
1342
1343            def err_func(X_test, X_pred, scoring):
1344                if (self.replications is not None) or (
1345                    self.type_pi == "gaussian"
1346                ):  # probabilistic
1347                    if scoring == "winkler_score":
1348                        return winkler_score(X_pred, X_test, level=level)
1349                    elif scoring == "coverage":
1350                        return coverage(X_pred, X_test, level=level)
1351                    else:
1352                        return mean_errors(
1353                            pred=X_pred.mean, actual=X_test, scoring=scoring
1354                        )
1355                else:  # not probabilistic
1356                    return mean_errors(
1357                        pred=X_pred, actual=X_test, scoring=scoring
1358                    )
1359
1360        else:  # isinstance(scoring, str) = False
1361
1362            err_func = scoring
1363
1364        errors = []
1365
1366        train_indices = []
1367
1368        test_indices = []
1369
1370        for train_index, test_index in tscv_obj:
1371            train_indices.append(train_index)
1372            test_indices.append(test_index)
1373
1374        if show_progress is True:
1375            iterator = tqdm(
1376                zip(train_indices, test_indices), total=len(train_indices)
1377            )
1378        else:
1379            iterator = zip(train_indices, test_indices)
1380
1381        for train_index, test_index in iterator:
1382
1383            if verbose == 1:
1384                print(f"TRAIN: {train_index}")
1385                print(f"TEST: {test_index}")
1386
1387            if isinstance(X, pd.DataFrame):
1388                self.fit(X.iloc[train_index, :], xreg=xreg, **kwargs)
1389                X_test = X.iloc[test_index, :]
1390            else:
1391                self.fit(X[train_index, :], xreg=xreg, **kwargs)
1392                X_test = X[test_index, :]
1393            X_pred = self.predict(h=int(len(test_index)), level=level, **kwargs)
1394
1395            errors.append(err_func(X_test, X_pred, scoring))
1396
1397        res = np.asarray(errors)
1398
1399        return res, describe(res)

Univariate and multivariate time series (MTS) forecasting with Quasi-Randomized networks

Parameters:

obj: object.
    any object containing a method fit (obj.fit()) and a method predict
    (obj.predict()).

n_hidden_features: int.
    number of nodes in the hidden layer.

activation_name: str.
    activation function: 'relu', 'tanh', 'sigmoid', 'prelu' or 'elu'.

a: float.
    hyperparameter for 'prelu' or 'elu' activation function.

nodes_sim: str.
    type of simulation for the nodes: 'sobol', 'hammersley', 'halton',
    'uniform'.

bias: boolean.
    indicates if the hidden layer contains a bias term (True) or not
    (False).

dropout: float.
    regularization parameter; (random) percentage of nodes dropped out
    of the training.

direct_link: boolean.
    indicates if the original predictors are included (True) in model's fitting or not (False).

n_clusters: int.
    number of clusters for 'kmeans' or 'gmm' clustering (could be 0: no clustering).

cluster_encode: bool.
    defines how the variable containing clusters is treated (default is one-hot)
    if `False`, then labels are used, without one-hot encoding.

type_clust: str.
    type of clustering method: currently k-means ('kmeans') or Gaussian
    Mixture Model ('gmm').

type_scaling: a tuple of 3 strings.
    scaling methods for inputs, hidden layer, and clustering respectively
    (and when relevant).
    Currently available: standardization ('std') or MinMax scaling ('minmax').

lags: int.
    number of lags used for each time series.

type_pi: str.
    type of prediction interval; currently:
    - "gaussian": simple, fast, but: assumes stationarity of Gaussian in-sample residuals and independence in the multivariate case
    - "kde": based on Kernel Density Estimation of in-sample residuals
    - "bootstrap": based on independent bootstrap of in-sample residuals
    - "block-bootstrap": based on basic block bootstrap of in-sample residuals
    - "scp-kde": Sequential split conformal prediction with Kernel Density Estimation of calibrated residuals
    - "scp-bootstrap": Sequential split conformal prediction with independent bootstrap of calibrated residuals
    - "scp-block-bootstrap": Sequential split conformal prediction with basic block bootstrap of calibrated residuals
    - "scp2-kde": Sequential split conformal prediction with Kernel Density Estimation of standardized calibrated residuals
    - "scp2-bootstrap": Sequential split conformal prediction with independent bootstrap of standardized calibrated residuals
    - "scp2-block-bootstrap": Sequential split conformal prediction with basic block bootstrap of standardized calibrated residuals
    - based on copulas of in-sample residuals: 'vine-tll', 'vine-bb1', 'vine-bb6', 'vine-bb7', 'vine-bb8', 'vine-clayton',
    'vine-frank', 'vine-gaussian', 'vine-gumbel', 'vine-indep', 'vine-joe', 'vine-student'
    - 'scp-vine-tll', 'scp-vine-bb1', 'scp-vine-bb6', 'scp-vine-bb7', 'scp-vine-bb8', 'scp-vine-clayton',
    'scp-vine-frank', 'scp-vine-gaussian', 'scp-vine-gumbel', 'scp-vine-indep', 'scp-vine-joe', 'scp-vine-student'
    - 'scp2-vine-tll', 'scp2-vine-bb1', 'scp2-vine-bb6', 'scp2-vine-bb7', 'scp2-vine-bb8', 'scp2-vine-clayton',
    'scp2-vine-frank', 'scp2-vine-gaussian', 'scp2-vine-gumbel', 'scp2-vine-indep', 'scp2-vine-joe', 'scp2-vine-student'

block_size: int.
    size of block for 'type_pi' in ("block-bootstrap", "scp-block-bootstrap", "scp2-block-bootstrap").
    Default is round(3.15*(n_residuals^1/3))

replications: int.
    number of replications (if needed, for predictive simulation). Default is 'None'.

kernel: str.
    the kernel to use for residuals density estimation (used for predictive simulation). Currently, either 'gaussian' or 'tophat'.

agg: str.
    either "mean" or "median" for simulation of bootstrap aggregating

seed: int.
    reproducibility seed for nodes_sim=='uniform' or predictive simulation.

backend: str.
    "cpu" or "gpu" or "tpu".

verbose: int.
    0: not printing; 1: printing

show_progress: bool.
    True: progress bar when fitting each series; False: no progress bar when fitting each series

Attributes:

fit_objs_: dict
    objects adjusted to each individual time series

y_: {array-like}
    MTS responses (most recent observations first)

X_: {array-like}
    MTS lags

xreg_: {array-like}
    external regressors

y_means_: dict
    a dictionary of each series mean values

preds_: {array-like}
    successive model predictions

preds_std_: {array-like}
    standard deviation around the predictions for Bayesian base learners (`obj`)

gaussian_preds_std_: {array-like}
    standard deviation around the predictions for `type_pi='gaussian'`

return_std_: boolean
    return uncertainty or not (set in predict)

df_: data frame
    the input data frame, in case a data.frame is provided to `fit`

n_obs_: int
    number of time series observations (number of rows for multivariate)

level_: int
    level of confidence for prediction intervals (default is 95)

residuals_: {array-like}
    in-sample residuals (for `type_pi` not conformal prediction) or calibrated residuals
    (for `type_pi` in conformal prediction)

residuals_sims_: tuple of {array-like}
    simulations of in-sample residuals (for `type_pi` not conformal prediction) or
    calibrated residuals (for `type_pi` in conformal prediction)

kde_: A scikit-learn object, see https://scikit-learn.org/stable/modules/generated/sklearn.neighbors.KernelDensity.html

residuals_std_dev_: residuals standard deviation

Examples:

Example 1:

import nnetsauce as ns
import numpy as np
from sklearn import linear_model
np.random.seed(123)

M = np.random.rand(10, 3)
M[:,0] = 10*M[:,0]
M[:,2] = 25*M[:,2]
print(M)

# Adjust Bayesian Ridge
regr4 = linear_model.BayesianRidge()
obj_MTS = ns.MTS(regr4, lags = 1, n_hidden_features=5)
obj_MTS.fit(M)
print(obj_MTS.predict())

# with credible intervals
print(obj_MTS.predict(return_std=True, level=80))

print(obj_MTS.predict(return_std=True, level=95))

Example 2:

import nnetsauce as ns
import numpy as np
from sklearn import linear_model

dataset = {
'date' : ['2001-01-01', '2002-01-01', '2003-01-01', '2004-01-01', '2005-01-01'],
'series1' : [34, 30, 35.6, 33.3, 38.1],
'series2' : [4, 5.5, 5.6, 6.3, 5.1],
'series3' : [100, 100.5, 100.6, 100.2, 100.1]}
df = pd.DataFrame(dataset).set_index('date')
print(df)

# Adjust Bayesian Ridge
regr5 = linear_model.BayesianRidge()
obj_MTS = ns.MTS(regr5, lags = 1, n_hidden_features=5)
obj_MTS.fit(df)
print(obj_MTS.predict())

# with credible intervals
print(obj_MTS.predict(return_std=True, level=80))

print(obj_MTS.predict(return_std=True, level=95))
def fit(self, X, xreg=None, **kwargs):
311    def fit(self, X, xreg=None, **kwargs):
312        """Fit MTS model to training data X, with optional regressors xreg
313
314        Parameters:
315
316        X: {array-like}, shape = [n_samples, n_features]
317            Training time series, where n_samples is the number
318            of samples and n_features is the number of features;
319            X must be in increasing order (most recent observations last)
320
321        xreg: {array-like}, shape = [n_samples, n_features_xreg]
322            Additional (external) regressors to be passed to self.obj
323            xreg must be in 'increasing' order (most recent observations last)
324
325        **kwargs: for now, additional parameters to be passed to for kernel density estimation, when needed (see sklearn.neighbors.KernelDensity)
326
327        Returns:
328
329        self: object
330        """
331
332        if (
333            isinstance(X, pd.DataFrame) is False
334        ):  # input data set is a numpy array
335
336            if xreg is None:
337                X = pd.DataFrame(X)
338                self.series_names = [
339                    "series" + str(i) for i in range(X.shape[1])
340                ]
341            else:  # xreg is not None
342                X = mo.cbind(X, xreg)
343                self.xreg_ = xreg
344
345        else:  # input data set is a DataFrame with column names
346
347            # if "date" in X.columns:
348            #    X.index = X["date"]
349            #    X.drop(['date'], axis=1, inplace=True)
350
351            X_index = None
352            if X.index is not None:
353                X_index = X.index
354            if xreg is None:
355                X = copy.deepcopy(mo.convert_df_to_numeric(X))
356            else:
357                X = copy.deepcopy(mo.cbind(mo.convert_df_to_numeric(X), xreg))
358                self.xreg_ = xreg
359            if X_index is not None:
360                X.index = X_index
361            self.series_names = X.columns.tolist()
362
363        if isinstance(X, pd.DataFrame):
364            if self.df_ is None:
365                self.df_ = X
366                X = X.values
367            else:
368                input_dates_prev = pd.DatetimeIndex(self.df_.index.values)
369                frequency = pd.infer_freq(input_dates_prev)
370                self.df_ = pd.concat([self.df_, X], axis=0)
371                self.input_dates = pd.date_range(
372                    start=input_dates_prev[0],
373                    periods=len(input_dates_prev) + X.shape[0],
374                    freq=frequency,
375                ).values.tolist()
376                self.df_.index = self.input_dates
377                X = self.df_.values
378            self.df_.columns = self.series_names
379        else:
380            if self.df_ is None:
381                self.df_ = pd.DataFrame(X, columns=self.series_names)
382            else:
383                self.df_ = pd.concat(
384                    [self.df_, pd.DataFrame(X, columns=self.series_names)],
385                    axis=0,
386                )
387
388        self.input_dates = ts.compute_input_dates(self.df_)
389
390        try:
391            # multivariate time series
392            n, p = X.shape
393        except:
394            # univariate time series
395            n = X.shape[0]
396            p = 1
397
398        self.n_obs_ = n
399
400        rep_1_n = np.repeat(1, n)
401
402        self.y_ = None
403        self.X_ = None
404        self.n_series = p
405        self.fit_objs_.clear()
406        try:
407            self.y_means_.clear()
408        except AttributeError:
409            self.y_means_ = None
410        residuals_ = []
411        self.residuals_ = None
412        self.residuals_sims_ = None
413        self.kde_ = None
414        self.sims_ = None
415        self.scaled_Z_ = None
416        self.centered_y_is_ = []
417
418        if p > 1:
419            # multivariate time series
420            mts_input = ts.create_train_inputs(X[::-1], self.lags)
421        else:
422            # univariate time series
423            mts_input = ts.create_train_inputs(
424                X.reshape(-1, 1)[::-1], self.lags
425            )
426
427        self.y_ = mts_input[0]
428
429        self.X_ = mts_input[1]
430
431        dummy_y, scaled_Z = self.cook_training_set(y=rep_1_n, X=self.X_)
432
433        self.scaled_Z_ = scaled_Z
434
435        # loop on all the time series and adjust self.obj.fit
436        if self.verbose > 0:
437            print(
438                f"\n Adjusting {type(self.obj).__name__} to multivariate time series... \n "
439            )
440
441        if self.type_pi in (
442            "gaussian",
443            "kde",
444            "bootstrap",
445            "block-bootstrap",
446        ) or self.type_pi.startswith("vine"):
447
448            try:  # multioutput regressor
449
450                self.y_means_ = np.mean(self.y_, axis=0)
451                centered_y = self.y_ - self.y_means_
452                self.obj.fit(X=scaled_Z, y=centered_y)
453                residuals_ = centered_y - self.obj.predict(scaled_Z)
454                self.residuals_ = residuals_
455
456            except Exception:  # single output regressor
457
458                if self.show_progress is True:
459                    iterator = tqdm(range(p))
460                else:
461                    iterator = range(p)
462
463                for i in iterator:
464                    y_mean = np.mean(self.y_[:, i])
465                    self.y_means_[i] = y_mean
466                    centered_y_i = self.y_[:, i] - y_mean
467                    self.centered_y_is_.append(centered_y_i)
468                    self.obj.fit(X=scaled_Z, y=centered_y_i)
469                    self.fit_objs_[i] = deepcopy(self.obj)
470                    residuals_.append(
471                        (
472                            centered_y_i - self.fit_objs_[i].predict(scaled_Z)
473                        ).tolist()
474                    )
475
476        if self.type_pi.startswith("scp"):
477
478            # split conformal prediction
479            n_y = self.y_.shape[0]
480            n_y_half = n_y // 2
481            first_half_idx = range(0, n_y_half)
482            second_half_idx = range(n_y_half, n_y)
483
484            try:  # multioutput regressor
485
486                y_mean_temp = np.mean(self.y_[first_half_idx, :], axis=0)
487                centered_y_temp = self.y_[first_half_idx, :] - y_mean_temp
488                self.obj.fit(X=scaled_Z[first_half_idx, :], y=centered_y_temp)
489                residuals_ = (
490                    self.y_[second_half_idx, :]
491                    - y_mean_temp
492                    - self.obj.predict(scaled_Z[second_half_idx, :])
493                )
494                self.y_means_ = np.mean(self.y_[second_half_idx, :], axis=0)
495                centered_y = (
496                    self.y_[second_half_idx, :] - self.y_means_[:, np.newaxis]
497                )
498                self.obj.fit(X=scaled_Z[second_half_idx, :], y=centered_y)
499                self.residuals_ = np.asarray(residuals_)
500
501            except Exception:  # single output regressor
502
503                if self.show_progress is True:
504                    iterator = tqdm(range(p))
505                else:
506                    iterator = range(p)
507
508                residuals_ = []
509
510                for i in iterator:
511                    y_mean_temp = np.mean(self.y_[first_half_idx, i])
512                    centered_y_i_temp = self.y_[first_half_idx, i] - y_mean_temp
513                    self.obj.fit(
514                        X=scaled_Z[first_half_idx, :], y=centered_y_i_temp
515                    )
516                    # calibrated residuals actually
517                    residuals_.append(
518                        (
519                            self.y_[second_half_idx, i]
520                            - (
521                                y_mean_temp
522                                + self.obj.predict(scaled_Z[second_half_idx, :])
523                            )
524                        ).tolist()
525                    )
526                    # fit on the second half
527                    y_mean = np.mean(self.y_[second_half_idx, i])
528                    self.y_means_[i] = y_mean
529                    centered_y_i = self.y_[second_half_idx, i] - y_mean
530                    self.obj.fit(X=scaled_Z[second_half_idx, :], y=centered_y_i)
531                    self.fit_objs_[i] = deepcopy(self.obj)
532
533                self.residuals_ = np.asarray(residuals_).T
534
535        if self.type_pi == "gaussian":
536            self.gaussian_preds_std_ = np.std(self.residuals_, axis=0)
537
538        if self.type_pi.startswith("scp2"):
539            # Calculate mean and standard deviation for each column
540            data_mean = np.mean(self.residuals_, axis=0)
541            self.residuals_std_dev_ = np.std(self.residuals_, axis=0)
542            # Center and scale the array using broadcasting
543            self.residuals_ = (
544                self.residuals_ - data_mean[np.newaxis, :]
545            ) / self.residuals_std_dev_[np.newaxis, :]
546
547        if self.replications != None and "kde" in self.type_pi:
548            if self.verbose > 0:
549                print(f"\n Simulate residuals using {self.kernel} kernel... \n")
550            assert self.kernel in (
551                "gaussian",
552                "tophat",
553            ), "currently, 'kernel' must be either 'gaussian' or 'tophat'"
554            kernel_bandwidths = {"bandwidth": np.logspace(-6, 6, 150)}
555            grid = GridSearchCV(
556                KernelDensity(kernel=self.kernel, **kwargs),
557                param_grid=kernel_bandwidths,
558            )
559            grid.fit(self.residuals_)
560
561            if self.verbose > 0:
562                print(
563                    f"\n Best parameters for {self.kernel} kernel: {grid.best_params_} \n"
564                )
565
566            self.kde_ = grid.best_estimator_
567
568        return self

Fit MTS model to training data X, with optional regressors xreg

Parameters:

X: {array-like}, shape = [n_samples, n_features] Training time series, where n_samples is the number of samples and n_features is the number of features; X must be in increasing order (most recent observations last)

xreg: {array-like}, shape = [n_samples, n_features_xreg] Additional (external) regressors to be passed to self.obj xreg must be in 'increasing' order (most recent observations last)

**kwargs: for now, additional parameters to be passed to for kernel density estimation, when needed (see sklearn.neighbors.KernelDensity)

Returns:

self: object

def predict(self, h=5, level=95, **kwargs):
 606    def predict(self, h=5, level=95, **kwargs):
 607        """Forecast all the time series, h steps ahead
 608
 609        Parameters:
 610
 611        h: {integer}
 612            Forecasting horizon
 613
 614        level: {integer}
 615            Level of confidence (if obj has option 'return_std' and the
 616            posterior is gaussian)
 617
 618        new_xreg: {array-like}, shape = [n_samples = h, n_new_xreg]
 619            New values of additional (deterministic) regressors on horizon = h
 620            new_xreg must be in increasing order (most recent observations last)
 621
 622        **kwargs: additional parameters to be passed to
 623                self.cook_test_set
 624
 625        Returns:
 626
 627        model predictions for horizon = h: {array-like}, data frame or tuple.
 628        Standard deviation and prediction intervals are returned when
 629        `obj.predict` can return standard deviation
 630
 631        """
 632
 633        self.output_dates_, frequency = ts.compute_output_dates(self.df_, h)
 634
 635        self.level_ = level
 636
 637        self.return_std_ = False  # do not remove (/!\)
 638
 639        self.mean_ = None  # do not remove (/!\)
 640
 641        self.mean_ = deepcopy(self.y_)  # do not remove (/!\)
 642
 643        self.lower_ = None  # do not remove (/!\)
 644
 645        self.upper_ = None  # do not remove (/!\)
 646
 647        self.sims_ = None  # do not remove (/!\)
 648
 649        y_means_ = np.asarray([self.y_means_[i] for i in range(self.n_series)])
 650
 651        n_features = self.n_series * self.lags
 652
 653        self.alpha_ = 100 - level
 654
 655        pi_multiplier = norm.ppf(1 - self.alpha_ / 200)
 656
 657        if "return_std" in kwargs:  # bayesian forecasting
 658            self.return_std_ = True
 659            self.preds_std_ = []
 660            DescribeResult = namedtuple(
 661                "DescribeResult", ("mean", "lower", "upper")
 662            )  # to be updated
 663
 664        if "return_pi" in kwargs:  # split conformal, without simulation
 665            mean_pi_ = []
 666            lower_pi_ = []
 667            upper_pi_ = []
 668            DescribeResult = namedtuple(
 669                "DescribeResult", ("mean", "lower", "upper")
 670            )  # to be updated
 671
 672        if self.kde_ != None and "kde" in self.type_pi:  # kde
 673            if self.verbose == 1:
 674                self.residuals_sims_ = tuple(
 675                    self.kde_.sample(
 676                        n_samples=h, random_state=self.seed + 100 * i
 677                    )
 678                    for i in tqdm(range(self.replications))
 679                )
 680            elif self.verbose == 0:
 681                self.residuals_sims_ = tuple(
 682                    self.kde_.sample(
 683                        n_samples=h, random_state=self.seed + 100 * i
 684                    )
 685                    for i in range(self.replications)
 686                )
 687
 688        if self.type_pi in ("bootstrap", "scp-bootstrap", "scp2-bootstrap"):
 689            assert self.replications is not None and isinstance(
 690                self.replications, int
 691            ), "'replications' must be provided and be an integer"
 692            if self.verbose == 1:
 693                self.residuals_sims_ = tuple(
 694                    ts.bootstrap(
 695                        self.residuals_,
 696                        h=h,
 697                        block_size=None,
 698                        seed=self.seed + 100 * i,
 699                    )
 700                    for i in tqdm(range(self.replications))
 701                )
 702            elif self.verbose == 0:
 703                self.residuals_sims_ = tuple(
 704                    ts.bootstrap(
 705                        self.residuals_,
 706                        h=h,
 707                        block_size=None,
 708                        seed=self.seed + 100 * i,
 709                    )
 710                    for i in range(self.replications)
 711                )
 712
 713        if self.type_pi in (
 714            "block-bootstrap",
 715            "scp-block-bootstrap",
 716            "scp2-block-bootstrap",
 717        ):
 718            if self.block_size is None:
 719                self.block_size = int(
 720                    np.ceil(3.15 * (self.residuals_.shape[0] ** (1 / 3)))
 721                )
 722
 723            assert self.replications is not None and isinstance(
 724                self.replications, int
 725            ), "'replications' must be provided and be an integer"
 726            if self.verbose == 1:
 727                self.residuals_sims_ = tuple(
 728                    ts.bootstrap(
 729                        self.residuals_,
 730                        h=h,
 731                        block_size=self.block_size,
 732                        seed=self.seed + 100 * i,
 733                    )
 734                    for i in tqdm(range(self.replications))
 735                )
 736            elif self.verbose == 0:
 737                self.residuals_sims_ = tuple(
 738                    ts.bootstrap(
 739                        self.residuals_,
 740                        h=h,
 741                        block_size=self.block_size,
 742                        seed=self.seed + 100 * i,
 743                    )
 744                    for i in range(self.replications)
 745                )
 746
 747        if "vine" in self.type_pi:
 748            if self.verbose == 1:
 749                self.residuals_sims_ = tuple(
 750                    vinecopula_sample(
 751                        x=self.residuals_,
 752                        n_samples=h,
 753                        method=self.type_pi,
 754                        random_state=self.seed + 100 * i,
 755                    )
 756                    for i in tqdm(range(self.replications))
 757                )
 758            elif self.verbose == 0:
 759                self.residuals_sims_ = tuple(
 760                    vinecopula_sample(
 761                        x=self.residuals_,
 762                        n_samples=h,
 763                        method=self.type_pi,
 764                        random_state=self.seed + 100 * i,
 765                    )
 766                    for i in range(self.replications)
 767                )
 768
 769        for _ in range(h):
 770
 771            new_obs = ts.reformat_response(self.mean_, self.lags)
 772
 773            new_X = new_obs.reshape(1, n_features)
 774
 775            cooked_new_X = self.cook_test_set(new_X, **kwargs)
 776
 777            if "return_std" in kwargs:
 778                try:  # multioutput regressor
 779                    self.preds_std_ = self.obj.predict(
 780                        cooked_new_X, return_std=True
 781                    )[1]
 782                except Exception:  # single output regressor
 783                    self.preds_std_.append(
 784                        [
 785                            np.asarray(
 786                                self.fit_objs_[i].predict(
 787                                    cooked_new_X, return_std=True
 788                                )[1]
 789                            ).item()
 790                            for i in range(self.n_series)
 791                        ]
 792                    )
 793
 794            if "return_pi" in kwargs:
 795                try:
 796                    preds_pi = self.obj.predict(cooked_new_X, return_pi=True)
 797                    mean_pi_.append(preds_pi.mean[0])
 798                    lower_pi_.append(preds_pi.lower[0])
 799                    upper_pi_.append(preds_pi.upper[0])
 800                except Exception:
 801                    for i in range(self.n_series):
 802                        preds_pi = self.fit_objs_[i].predict(
 803                            cooked_new_X, return_pi=True
 804                        )
 805                        mean_pi_.append(preds_pi.mean[0])
 806                        lower_pi_.append(preds_pi.lower[0])
 807                        upper_pi_.append(preds_pi.upper[0])
 808
 809            try:
 810                predicted_cooked_new_X = self.obj.predict(cooked_new_X)
 811            except Exception:
 812                predicted_cooked_new_X = np.asarray(
 813                    [
 814                        np.asarray(
 815                            self.fit_objs_[i].predict(cooked_new_X)
 816                        ).item()
 817                        for i in range(self.n_series)
 818                    ]
 819                )
 820
 821            preds = np.asarray(y_means_ + predicted_cooked_new_X)
 822
 823            self.mean_ = mo.rbind(preds, self.mean_)  # preallocate?
 824
 825        # function's return ----------------------------------------------------------------------
 826        self.mean_ = pd.DataFrame(
 827            self.mean_[0:h, :][::-1],
 828            columns=self.df_.columns,
 829            index=self.output_dates_,
 830        )
 831
 832        if (
 833            (("return_std" not in kwargs) and ("return_pi" not in kwargs))
 834            and (self.type_pi not in ("gaussian", "scp"))
 835        ) or ("vine" in self.type_pi):
 836
 837            if self.replications is None:
 838                return self.mean_
 839
 840            # if "return_std" not in kwargs and self.replications is not None
 841            meanf = []
 842            lower = []
 843            upper = []
 844
 845            if "scp2" in self.type_pi:
 846
 847                if self.verbose == 1:
 848                    self.sims_ = tuple(
 849                        (
 850                            self.mean_
 851                            + self.residuals_sims_[i]
 852                            * self.residuals_std_dev_[np.newaxis, :]
 853                            for i in tqdm(range(self.replications))
 854                        )
 855                    )
 856                elif self.verbose == 0:
 857                    self.sims_ = tuple(
 858                        (
 859                            self.mean_
 860                            + self.residuals_sims_[i]
 861                            * self.residuals_std_dev_[np.newaxis, :]
 862                            for i in range(self.replications)
 863                        )
 864                    )
 865            else:
 866
 867                if self.verbose == 1:
 868                    self.sims_ = tuple(
 869                        (
 870                            self.mean_ + self.residuals_sims_[i]
 871                            for i in tqdm(range(self.replications))
 872                        )
 873                    )
 874                elif self.verbose == 0:
 875                    self.sims_ = tuple(
 876                        (
 877                            self.mean_ + self.residuals_sims_[i]
 878                            for i in range(self.replications)
 879                        )
 880                    )
 881
 882            DescribeResult = namedtuple(
 883                "DescribeResult", ("mean", "sims", "lower", "upper")
 884            )
 885            for ix in range(self.n_series):
 886                sims_ix = getsims(self.sims_, ix)
 887                if self.agg == "mean":
 888                    meanf.append(np.mean(sims_ix, axis=1))
 889                else:
 890                    meanf.append(np.median(sims_ix, axis=1))
 891                lower.append(np.quantile(sims_ix, q=self.alpha_ / 200, axis=1))
 892                upper.append(
 893                    np.quantile(sims_ix, q=1 - self.alpha_ / 200, axis=1)
 894                )
 895
 896            self.mean_ = pd.DataFrame(
 897                np.asarray(meanf).T,
 898                columns=self.series_names,  # self.df_.columns,
 899                index=self.output_dates_,
 900            )
 901
 902            self.lower_ = pd.DataFrame(
 903                np.asarray(lower).T,
 904                columns=self.series_names,  # self.df_.columns,
 905                index=self.output_dates_,
 906            )
 907
 908            self.upper_ = pd.DataFrame(
 909                np.asarray(upper).T,
 910                columns=self.series_names,  # self.df_.columns,
 911                index=self.output_dates_,
 912            )
 913
 914            res = DescribeResult(
 915                self.mean_, self.sims_, self.lower_, self.upper_
 916            )
 917
 918            if self.xreg_ is not None:
 919
 920                if len(self.xreg_.shape) > 1:
 921
 922                    res2 = mx.tuple_map(
 923                        res,
 924                        lambda x: mo.delete_last_columns(
 925                            x, num_columns=self.xreg_.shape[1]
 926                        ),
 927                    )
 928
 929                else:
 930
 931                    res2 = mx.tuple_map(
 932                        res, lambda x: mo.delete_last_columns(x, num_columns=1)
 933                    )
 934
 935                return res2
 936
 937            else:
 938
 939                return res
 940
 941        if (
 942            (("return_std" in kwargs) or ("return_pi" in kwargs))
 943            and (self.type_pi not in ("gaussian", "scp"))
 944        ) or "vine" in self.type_pi:
 945            DescribeResult = namedtuple(
 946                "DescribeResult", ("mean", "lower", "upper")
 947            )
 948
 949            self.mean_ = pd.DataFrame(
 950                np.asarray(self.mean_),
 951                columns=self.series_names,  # self.df_.columns,
 952                index=self.output_dates_,
 953            )
 954
 955            if "return_std" in kwargs:
 956
 957                self.preds_std_ = np.asarray(self.preds_std_)
 958
 959                self.lower_ = pd.DataFrame(
 960                    self.mean_.values - pi_multiplier * self.preds_std_,
 961                    columns=self.series_names,  # self.df_.columns,
 962                    index=self.output_dates_,
 963                )
 964
 965                self.upper_ = pd.DataFrame(
 966                    self.mean_.values + pi_multiplier * self.preds_std_,
 967                    columns=self.series_names,  # self.df_.columns,
 968                    index=self.output_dates_,
 969                )
 970
 971            if "return_pi" in kwargs:
 972
 973                self.lower_ = pd.DataFrame(
 974                    np.asarray(lower_pi_).reshape(h, self.n_series)
 975                    + y_means_[np.newaxis, :],
 976                    columns=self.series_names,  # self.df_.columns,
 977                    index=self.output_dates_,
 978                )
 979
 980                self.upper_ = pd.DataFrame(
 981                    np.asarray(upper_pi_).reshape(h, self.n_series)
 982                    + y_means_[np.newaxis, :],
 983                    columns=self.series_names,  # self.df_.columns,
 984                    index=self.output_dates_,
 985                )
 986
 987            res = DescribeResult(self.mean_, self.lower_, self.upper_)
 988
 989            if self.xreg_ is not None:
 990                if len(self.xreg_.shape) > 1:
 991                    res2 = mx.tuple_map(
 992                        res,
 993                        lambda x: mo.delete_last_columns(
 994                            x, num_columns=self.xreg_.shape[1]
 995                        ),
 996                    )
 997                else:
 998                    res2 = mx.tuple_map(
 999                        res, lambda x: mo.delete_last_columns(x, num_columns=1)
1000                    )
1001                return DescribeResult(res2[0], res2[1], res2[2])
1002
1003            return res
1004
1005        if self.type_pi == "gaussian":
1006
1007            DescribeResult = namedtuple(
1008                "DescribeResult", ("mean", "lower", "upper")
1009            )
1010
1011            self.mean_ = pd.DataFrame(
1012                np.asarray(self.mean_),
1013                columns=self.series_names,  # self.df_.columns,
1014                index=self.output_dates_,
1015            )
1016
1017            self.lower_ = pd.DataFrame(
1018                self.mean_.values - pi_multiplier * self.gaussian_preds_std_,
1019                columns=self.series_names,  # self.df_.columns,
1020                index=self.output_dates_,
1021            )
1022
1023            self.upper_ = pd.DataFrame(
1024                self.mean_.values + pi_multiplier * self.gaussian_preds_std_,
1025                columns=self.series_names,  # self.df_.columns,
1026                index=self.output_dates_,
1027            )
1028
1029            res = DescribeResult(self.mean_, self.lower_, self.upper_)
1030
1031            if self.xreg_ is not None:
1032                if len(self.xreg_.shape) > 1:
1033                    res2 = mx.tuple_map(
1034                        res,
1035                        lambda x: mo.delete_last_columns(
1036                            x, num_columns=self.xreg_.shape[1]
1037                        ),
1038                    )
1039                else:
1040                    res2 = mx.tuple_map(
1041                        res, lambda x: mo.delete_last_columns(x, num_columns=1)
1042                    )
1043                return DescribeResult(res2[0], res2[1], res2[2])
1044
1045            return res

Forecast all the time series, h steps ahead

Parameters:

h: {integer} Forecasting horizon

level: {integer} Level of confidence (if obj has option 'return_std' and the posterior is gaussian)

new_xreg: {array-like}, shape = [n_samples = h, n_new_xreg] New values of additional (deterministic) regressors on horizon = h new_xreg must be in increasing order (most recent observations last)

**kwargs: additional parameters to be passed to self.cook_test_set

Returns:

model predictions for horizon = h: {array-like}, data frame or tuple. Standard deviation and prediction intervals are returned when obj.predict can return standard deviation

def score(self, X, training_index, testing_index, scoring=None, **kwargs):
1047    def score(self, X, training_index, testing_index, scoring=None, **kwargs):
1048        """Train on training_index, score on testing_index."""
1049
1050        assert (
1051            bool(set(training_index).intersection(set(testing_index))) == False
1052        ), "Non-overlapping 'training_index' and 'testing_index' required"
1053
1054        # Dimensions
1055        try:
1056            # multivariate time series
1057            n, p = X.shape
1058        except:
1059            # univariate time series
1060            n = X.shape[0]
1061            p = 1
1062
1063        # Training and testing sets
1064        if p > 1:
1065            X_train = X[training_index, :]
1066            X_test = X[testing_index, :]
1067        else:
1068            X_train = X[training_index]
1069            X_test = X[testing_index]
1070
1071        # Horizon
1072        h = len(testing_index)
1073        assert (
1074            len(training_index) + h
1075        ) <= n, "Please check lengths of training and testing windows"
1076
1077        # Fit and predict
1078        self.fit(X_train, **kwargs)
1079        preds = self.predict(h=h, **kwargs)
1080
1081        if scoring is None:
1082            scoring = "neg_root_mean_squared_error"
1083
1084        # check inputs
1085        assert scoring in (
1086            "explained_variance",
1087            "neg_mean_absolute_error",
1088            "neg_mean_squared_error",
1089            "neg_root_mean_squared_error",
1090            "neg_mean_squared_log_error",
1091            "neg_median_absolute_error",
1092            "r2",
1093        ), "'scoring' should be in ('explained_variance', 'neg_mean_absolute_error', \
1094                               'neg_mean_squared_error', 'neg_root_mean_squared_error', 'neg_mean_squared_log_error', \
1095                               'neg_median_absolute_error', 'r2')"
1096
1097        scoring_options = {
1098            "explained_variance": skm2.explained_variance_score,
1099            "neg_mean_absolute_error": skm2.mean_absolute_error,
1100            "neg_mean_squared_error": lambda x, y: np.mean((x - y) ** 2),
1101            "neg_root_mean_squared_error": lambda x, y: np.sqrt(
1102                np.mean((x - y) ** 2)
1103            ),
1104            "neg_mean_squared_log_error": skm2.mean_squared_log_error,
1105            "neg_median_absolute_error": skm2.median_absolute_error,
1106            "r2": skm2.r2_score,
1107        }
1108
1109        # if p > 1:
1110        #     return tuple(
1111        #         [
1112        #             scoring_options[scoring](
1113        #                 X_test[:, i], preds[:, i]#, **kwargs
1114        #             )
1115        #             for i in range(p)
1116        #         ]
1117        #     )
1118        # else:
1119        return scoring_options[scoring](X_test, preds)

Train on training_index, score on testing_index.

class MultitaskClassifier(nnetsauce.Base, sklearn.base.ClassifierMixin):
 16class MultitaskClassifier(Base, ClassifierMixin):
 17    """Multitask Classification model based on regression models, with shared covariates
 18
 19    Parameters:
 20
 21        obj: object
 22            any object (must be a regression model) containing a method fit (obj.fit())
 23            and a method predict (obj.predict())
 24
 25        n_hidden_features: int
 26            number of nodes in the hidden layer
 27
 28        activation_name: str
 29            activation function: 'relu', 'tanh', 'sigmoid', 'prelu' or 'elu'
 30
 31        a: float
 32            hyperparameter for 'prelu' or 'elu' activation function
 33
 34        nodes_sim: str
 35            type of simulation for the nodes: 'sobol', 'hammersley', 'halton',
 36            'uniform'
 37
 38        bias: boolean
 39            indicates if the hidden layer contains a bias term (True) or not
 40            (False)
 41
 42        dropout: float
 43            regularization parameter; (random) percentage of nodes dropped out
 44            of the training
 45
 46        direct_link: boolean
 47            indicates if the original predictors are included (True) in model's
 48            fitting or not (False)
 49
 50        n_clusters: int
 51            number of clusters for 'kmeans' or 'gmm' clustering (could be 0:
 52                no clustering)
 53
 54        cluster_encode: bool
 55            defines how the variable containing clusters is treated (default is one-hot)
 56            if `False`, then labels are used, without one-hot encoding
 57
 58        type_clust: str
 59            type of clustering method: currently k-means ('kmeans') or Gaussian
 60            Mixture Model ('gmm')
 61
 62        type_scaling: a tuple of 3 strings
 63            scaling methods for inputs, hidden layer, and clustering respectively
 64            (and when relevant).
 65            Currently available: standardization ('std') or MinMax scaling ('minmax')
 66
 67        col_sample: float
 68            percentage of covariates randomly chosen for training
 69
 70        row_sample: float
 71            percentage of rows chosen for training, by stratified bootstrapping
 72
 73        seed: int
 74            reproducibility seed for nodes_sim=='uniform'
 75
 76        backend: str
 77            "cpu" or "gpu" or "tpu"
 78
 79    Attributes:
 80
 81        fit_objs_: dict
 82            objects adjusted to each individual time series
 83
 84        n_classes_: int
 85            number of classes for the classifier
 86
 87    Examples:
 88
 89    See also [https://github.com/Techtonique/nnetsauce/blob/master/examples/mtask_classification.py](https://github.com/Techtonique/nnetsauce/blob/master/examples/mtask_classification.py)
 90
 91    ```python
 92    import nnetsauce as ns
 93    import numpy as np
 94    from sklearn.datasets import load_breast_cancer
 95    from sklearn.linear_model import LinearRegression
 96    from sklearn.model_selection import train_test_split
 97    from sklearn import metrics
 98    from time import time
 99
100    breast_cancer = load_breast_cancer()
101    Z = breast_cancer.data
102    t = breast_cancer.target
103
104    X_train, X_test, y_train, y_test = train_test_split(Z, t, test_size=0.2,
105                                                        random_state=123+2*10)
106
107    # Linear Regression is used
108    regr = LinearRegression()
109    fit_obj = ns.MultitaskClassifier(regr, n_hidden_features=5,
110                                n_clusters=2, type_clust="gmm")
111
112    start = time()
113    fit_obj.fit(X_train, y_train)
114    print(f"Elapsed {time() - start}")
115
116    print(fit_obj.score(X_test, y_test))
117    print(fit_obj.score(X_test, y_test, scoring="roc_auc"))
118
119    start = time()
120    preds = fit_obj.predict(X_test)
121    print(f"Elapsed {time() - start}")
122    print(metrics.classification_report(preds, y_test))
123    ```
124
125    """
126
127    # construct the object -----
128
129    def __init__(
130        self,
131        obj,
132        n_hidden_features=5,
133        activation_name="relu",
134        a=0.01,
135        nodes_sim="sobol",
136        bias=True,
137        dropout=0,
138        direct_link=True,
139        n_clusters=2,
140        cluster_encode=True,
141        type_clust="kmeans",
142        type_scaling=("std", "std", "std"),
143        col_sample=1,
144        row_sample=1,
145        seed=123,
146        backend="cpu",
147    ):
148        super().__init__(
149            n_hidden_features=n_hidden_features,
150            activation_name=activation_name,
151            a=a,
152            nodes_sim=nodes_sim,
153            bias=bias,
154            dropout=dropout,
155            direct_link=direct_link,
156            n_clusters=n_clusters,
157            cluster_encode=cluster_encode,
158            type_clust=type_clust,
159            type_scaling=type_scaling,
160            col_sample=col_sample,
161            row_sample=row_sample,
162            seed=seed,
163            backend=backend,
164        )
165
166        self.type_fit = "classification"
167        self.obj = obj
168        self.fit_objs_ = {}
169
170    def fit(self, X, y, sample_weight=None, **kwargs):
171        """Fit MultitaskClassifier to training data (X, y).
172
173        Args:
174
175            X: {array-like}, shape = [n_samples, n_features]
176                Training vectors, where n_samples is the number
177                of samples and n_features is the number of features.
178
179            y: array-like, shape = [n_samples]
180                Target values.
181
182            **kwargs: additional parameters to be passed to
183                    self.cook_training_set or self.obj.fit
184
185        Returns:
186
187            self: object
188
189        """
190
191        assert mx.is_factor(y), "y must contain only integers"
192
193        output_y, scaled_Z = self.cook_training_set(y=y, X=X, **kwargs)
194
195        self.classes_ = np.unique(y)  # for compatibility with sklearn
196        self.n_classes_ = len(self.classes_)  # for compatibility with sklearn
197
198        # multitask response
199        Y = mo.one_hot_encode2(output_y, self.n_classes_)
200
201        # if sample_weight is None:
202        for i in range(self.n_classes_):
203            self.fit_objs_[i] = deepcopy(
204                self.obj.fit(scaled_Z, Y[:, i], **kwargs)
205            )
206
207        self.classes_ = np.unique(y)
208        return self
209
210    def predict(self, X, **kwargs):
211        """Predict test data X.
212
213        Args:
214
215            X: {array-like}, shape = [n_samples, n_features]
216                Training vectors, where n_samples is the number
217                of samples and n_features is the number of features.
218
219            **kwargs: additional parameters to be passed to
220                    self.cook_test_set
221
222        Returns:
223
224            model predictions: {array-like}
225
226        """
227
228        return np.argmax(self.predict_proba(X, **kwargs), axis=1)
229
230    def predict_proba(self, X, **kwargs):
231        """Predict probabilities for test data X.
232
233        Args:
234
235            X: {array-like}, shape = [n_samples, n_features]
236                Training vectors, where n_samples is the number
237                of samples and n_features is the number of features.
238
239            **kwargs: additional parameters to be passed to
240                    self.cook_test_set
241
242        Returns:
243
244            probability estimates for test data: {array-like}
245
246        """
247
248        shape_X = X.shape
249
250        probs = np.zeros((shape_X[0], self.n_classes_))
251
252        if len(shape_X) == 1:
253            n_features = shape_X[0]
254
255            new_X = mo.rbind(
256                X.reshape(1, n_features),
257                np.ones(n_features).reshape(1, n_features),
258            )
259
260            Z = self.cook_test_set(new_X, **kwargs)
261
262            # loop on all the classes
263            for i in range(self.n_classes_):
264                probs[:, i] = self.fit_objs_[i].predict(Z, **kwargs)[0]
265
266        else:
267            Z = self.cook_test_set(X, **kwargs)
268
269            # loop on all the classes
270            for i in range(self.n_classes_):
271                probs[:, i] = self.fit_objs_[i].predict(Z, **kwargs)
272
273        expit_raw_probs = expit(probs)
274
275        return expit_raw_probs / expit_raw_probs.sum(axis=1)[:, None]

Multitask Classification model based on regression models, with shared covariates

Parameters:

obj: object
    any object (must be a regression model) containing a method fit (obj.fit())
    and a method predict (obj.predict())

n_hidden_features: int
    number of nodes in the hidden layer

activation_name: str
    activation function: 'relu', 'tanh', 'sigmoid', 'prelu' or 'elu'

a: float
    hyperparameter for 'prelu' or 'elu' activation function

nodes_sim: str
    type of simulation for the nodes: 'sobol', 'hammersley', 'halton',
    'uniform'

bias: boolean
    indicates if the hidden layer contains a bias term (True) or not
    (False)

dropout: float
    regularization parameter; (random) percentage of nodes dropped out
    of the training

direct_link: boolean
    indicates if the original predictors are included (True) in model's
    fitting or not (False)

n_clusters: int
    number of clusters for 'kmeans' or 'gmm' clustering (could be 0:
        no clustering)

cluster_encode: bool
    defines how the variable containing clusters is treated (default is one-hot)
    if `False`, then labels are used, without one-hot encoding

type_clust: str
    type of clustering method: currently k-means ('kmeans') or Gaussian
    Mixture Model ('gmm')

type_scaling: a tuple of 3 strings
    scaling methods for inputs, hidden layer, and clustering respectively
    (and when relevant).
    Currently available: standardization ('std') or MinMax scaling ('minmax')

col_sample: float
    percentage of covariates randomly chosen for training

row_sample: float
    percentage of rows chosen for training, by stratified bootstrapping

seed: int
    reproducibility seed for nodes_sim=='uniform'

backend: str
    "cpu" or "gpu" or "tpu"

Attributes:

fit_objs_: dict
    objects adjusted to each individual time series

n_classes_: int
    number of classes for the classifier

Examples:

See also https://github.com/Techtonique/nnetsauce/blob/master/examples/mtask_classification.py

import nnetsauce as ns
import numpy as np
from sklearn.datasets import load_breast_cancer
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split
from sklearn import metrics
from time import time

breast_cancer = load_breast_cancer()
Z = breast_cancer.data
t = breast_cancer.target

X_train, X_test, y_train, y_test = train_test_split(Z, t, test_size=0.2,
                                                    random_state=123+2*10)

# Linear Regression is used
regr = LinearRegression()
fit_obj = ns.MultitaskClassifier(regr, n_hidden_features=5,
                            n_clusters=2, type_clust="gmm")

start = time()
fit_obj.fit(X_train, y_train)
print(f"Elapsed {time() - start}")

print(fit_obj.score(X_test, y_test))
print(fit_obj.score(X_test, y_test, scoring="roc_auc"))

start = time()
preds = fit_obj.predict(X_test)
print(f"Elapsed {time() - start}")
print(metrics.classification_report(preds, y_test))
def fit(self, X, y, sample_weight=None, **kwargs):
170    def fit(self, X, y, sample_weight=None, **kwargs):
171        """Fit MultitaskClassifier to training data (X, y).
172
173        Args:
174
175            X: {array-like}, shape = [n_samples, n_features]
176                Training vectors, where n_samples is the number
177                of samples and n_features is the number of features.
178
179            y: array-like, shape = [n_samples]
180                Target values.
181
182            **kwargs: additional parameters to be passed to
183                    self.cook_training_set or self.obj.fit
184
185        Returns:
186
187            self: object
188
189        """
190
191        assert mx.is_factor(y), "y must contain only integers"
192
193        output_y, scaled_Z = self.cook_training_set(y=y, X=X, **kwargs)
194
195        self.classes_ = np.unique(y)  # for compatibility with sklearn
196        self.n_classes_ = len(self.classes_)  # for compatibility with sklearn
197
198        # multitask response
199        Y = mo.one_hot_encode2(output_y, self.n_classes_)
200
201        # if sample_weight is None:
202        for i in range(self.n_classes_):
203            self.fit_objs_[i] = deepcopy(
204                self.obj.fit(scaled_Z, Y[:, i], **kwargs)
205            )
206
207        self.classes_ = np.unique(y)
208        return self

Fit MultitaskClassifier to training data (X, y).

Args:

X: {array-like}, shape = [n_samples, n_features]
    Training vectors, where n_samples is the number
    of samples and n_features is the number of features.

y: array-like, shape = [n_samples]
    Target values.

**kwargs: additional parameters to be passed to
        self.cook_training_set or self.obj.fit

Returns:

self: object
def predict(self, X, **kwargs):
210    def predict(self, X, **kwargs):
211        """Predict test data X.
212
213        Args:
214
215            X: {array-like}, shape = [n_samples, n_features]
216                Training vectors, where n_samples is the number
217                of samples and n_features is the number of features.
218
219            **kwargs: additional parameters to be passed to
220                    self.cook_test_set
221
222        Returns:
223
224            model predictions: {array-like}
225
226        """
227
228        return np.argmax(self.predict_proba(X, **kwargs), axis=1)

Predict test data X.

Args:

X: {array-like}, shape = [n_samples, n_features]
    Training vectors, where n_samples is the number
    of samples and n_features is the number of features.

**kwargs: additional parameters to be passed to
        self.cook_test_set

Returns:

model predictions: {array-like}
def predict_proba(self, X, **kwargs):
230    def predict_proba(self, X, **kwargs):
231        """Predict probabilities for test data X.
232
233        Args:
234
235            X: {array-like}, shape = [n_samples, n_features]
236                Training vectors, where n_samples is the number
237                of samples and n_features is the number of features.
238
239            **kwargs: additional parameters to be passed to
240                    self.cook_test_set
241
242        Returns:
243
244            probability estimates for test data: {array-like}
245
246        """
247
248        shape_X = X.shape
249
250        probs = np.zeros((shape_X[0], self.n_classes_))
251
252        if len(shape_X) == 1:
253            n_features = shape_X[0]
254
255            new_X = mo.rbind(
256                X.reshape(1, n_features),
257                np.ones(n_features).reshape(1, n_features),
258            )
259
260            Z = self.cook_test_set(new_X, **kwargs)
261
262            # loop on all the classes
263            for i in range(self.n_classes_):
264                probs[:, i] = self.fit_objs_[i].predict(Z, **kwargs)[0]
265
266        else:
267            Z = self.cook_test_set(X, **kwargs)
268
269            # loop on all the classes
270            for i in range(self.n_classes_):
271                probs[:, i] = self.fit_objs_[i].predict(Z, **kwargs)
272
273        expit_raw_probs = expit(probs)
274
275        return expit_raw_probs / expit_raw_probs.sum(axis=1)[:, None]

Predict probabilities for test data X.

Args:

X: {array-like}, shape = [n_samples, n_features]
    Training vectors, where n_samples is the number
    of samples and n_features is the number of features.

**kwargs: additional parameters to be passed to
        self.cook_test_set

Returns:

probability estimates for test data: {array-like}
class PredictionInterval(sklearn.base.BaseEstimator, sklearn.base.RegressorMixin):
 19class PredictionInterval(BaseEstimator, RegressorMixin):
 20    """Class PredictionInterval: Obtain prediction intervals.
 21
 22    Attributes:
 23
 24        obj: an object;
 25            fitted object containing methods `fit` and `predict`
 26
 27        method: a string;
 28            method for constructing the prediction intervals.
 29            Currently "splitconformal" (default) and "localconformal"
 30
 31        level: a float;
 32            Confidence level for prediction intervals. Default is 95,
 33            equivalent to a miscoverage error of 5 (%)
 34
 35        replications: an integer;
 36            Number of replications for simulated conformal (default is `None`),
 37            for type_pi = "bootstrap" or "kde"
 38
 39        type_pi: a string;
 40            type of prediction interval: currently `None`
 41            (split conformal without simulation), "kde" or "bootstrap"
 42
 43        type_split: a string;
 44            "random" (random split of data) or "sequential" (sequential split of data)
 45
 46        seed: an integer;
 47            Reproducibility of fit (there's a random split between fitting and calibration data)
 48    """
 49
 50    def __init__(
 51        self,
 52        obj,
 53        method="splitconformal",
 54        level=95,
 55        type_pi=None,
 56        type_split="random",
 57        replications=None,
 58        kernel=None,
 59        agg="mean",
 60        seed=123,
 61    ):
 62
 63        self.obj = obj
 64        self.method = method
 65        self.level = level
 66        self.type_pi = type_pi
 67        self.type_split = type_split
 68        self.replications = replications
 69        self.kernel = kernel
 70        self.agg = agg
 71        self.seed = seed
 72        self.alpha_ = 1 - self.level / 100
 73        self.quantile_ = None
 74        self.icp_ = None
 75        self.calibrated_residuals_ = None
 76        self.scaled_calibrated_residuals_ = None
 77        self.calibrated_residuals_scaler_ = None
 78        self.kde_ = None
 79
 80    def fit(self, X, y, sample_weight=None, **kwargs):
 81        """Fit the `method` to training data (X, y).
 82
 83        Args:
 84
 85            X: array-like, shape = [n_samples, n_features];
 86                Training set vectors, where n_samples is the number
 87                of samples and n_features is the number of features.
 88
 89            y: array-like, shape = [n_samples, ]; Target values.
 90
 91            sample_weight: array-like, shape = [n_samples]
 92                Sample weights.
 93
 94        """
 95
 96        if self.type_split == "random":
 97
 98            X_train, X_calibration, y_train, y_calibration = train_test_split(
 99                X, y, test_size=0.5, random_state=self.seed
100            )
101
102        elif self.type_split == "sequential":
103
104            n_x = X.shape[0]
105            n_x_half = n_x // 2
106            first_half_idx = range(0, n_x_half)
107            second_half_idx = range(n_x_half, n_x)
108            X_train = X[first_half_idx, :]
109            X_calibration = X[second_half_idx, :]
110            y_train = y[first_half_idx]
111            y_calibration = y[second_half_idx]
112
113        if self.method == "splitconformal":
114
115            self.obj.fit(X_train, y_train)
116            preds_calibration = self.obj.predict(X_calibration)
117            self.calibrated_residuals_ = y_calibration - preds_calibration
118            absolute_residuals = np.abs(self.calibrated_residuals_)
119            self.calibrated_residuals_scaler_ = StandardScaler(
120                with_mean=True, with_std=True
121            )
122            self.scaled_calibrated_residuals_ = (
123                self.calibrated_residuals_scaler_.fit_transform(
124                    self.calibrated_residuals_.reshape(-1, 1)
125                ).ravel()
126            )
127            try:
128                # numpy version >= 1.22
129                self.quantile_ = np.quantile(
130                    a=absolute_residuals, q=self.level / 100, method="higher"
131                )
132            except:
133                # numpy version < 1.22
134                self.quantile_ = np.quantile(
135                    a=absolute_residuals,
136                    q=self.level / 100,
137                    interpolation="higher",
138                )
139
140        if self.method == "localconformal":
141
142            mad_estimator = ExtraTreesRegressor()
143            normalizer = RegressorNormalizer(
144                self.obj, mad_estimator, AbsErrorErrFunc()
145            )
146            nc = RegressorNc(self.obj, AbsErrorErrFunc(), normalizer)
147            self.icp_ = IcpRegressor(nc)
148            self.icp_.fit(X_train, y_train)
149            self.icp_.calibrate(X_calibration, y_calibration)
150
151        return self
152
153    def predict(self, X, return_pi=False):
154        """Obtain predictions and prediction intervals
155
156        Args:
157
158            X: array-like, shape = [n_samples, n_features];
159                Testing set vectors, where n_samples is the number
160                of samples and n_features is the number of features.
161
162            return_pi: boolean
163                Whether the prediction interval is returned or not.
164                Default is False, for compatibility with other _estimators_.
165                If True, a tuple containing the predictions + lower and upper
166                bounds is returned.
167
168        """
169
170        if self.method == "splitconformal":
171            pred = self.obj.predict(X)
172
173        if self.method == "localconformal":
174            pred = self.icp_.predict(X)
175
176        if self.method == "splitconformal":
177
178            if (
179                self.replications is None and self.type_pi is None
180            ):  # type_pi is not used here, no bootstrap or kde
181
182                if return_pi:
183
184                    DescribeResult = namedtuple(
185                        "DescribeResult", ("mean", "lower", "upper")
186                    )
187
188                    return DescribeResult(
189                        pred, pred - self.quantile_, pred + self.quantile_
190                    )
191
192                else:
193
194                    return pred
195
196            else:  # self.method == "splitconformal" and if self.replications is not None, type_pi must be used
197
198                if self.type_pi is None:
199                    self.type_pi = "kde"
200                    raise Warning("type_pi must be set, setting to 'kde'")
201
202                if self.replications is None:
203                    self.replications = 100
204                    raise Warning("replications must be set, setting to 100")
205
206                assert self.type_pi in (
207                    "bootstrap",
208                    "kde",
209                ), "`self.type_pi` must be in ('bootstrap', 'kde')"
210
211                if self.type_pi == "bootstrap":
212                    np.random.seed(self.seed)
213                    self.residuals_sims_ = np.asarray(
214                        [
215                            np.random.choice(
216                                a=self.scaled_calibrated_residuals_,
217                                size=X.shape[0],
218                            )
219                            for _ in range(self.replications)
220                        ]
221                    ).T
222                    self.sims_ = np.asarray(
223                        [
224                            pred
225                            + self.calibrated_residuals_scaler_.scale_[0]
226                            * self.residuals_sims_[:, i].ravel()
227                            for i in range(self.replications)
228                        ]
229                    ).T
230                elif self.type_pi == "kde":
231                    self.kde_ = gaussian_kde(
232                        dataset=self.scaled_calibrated_residuals_
233                    )
234                    self.sims_ = np.asarray(
235                        [
236                            pred
237                            + self.calibrated_residuals_scaler_.scale_[0]
238                            * self.kde_.resample(
239                                size=X.shape[0], seed=self.seed + i
240                            ).ravel()
241                            for i in range(self.replications)
242                        ]
243                    ).T
244
245                self.mean_ = np.mean(self.sims_, axis=1)
246                self.lower_ = np.quantile(
247                    self.sims_, q=self.alpha_ / 200, axis=1
248                )
249                self.upper_ = np.quantile(
250                    self.sims_, q=1 - self.alpha_ / 200, axis=1
251                )
252
253                DescribeResult = namedtuple(
254                    "DescribeResult", ("mean", "sims", "lower", "upper")
255                )
256
257                return DescribeResult(
258                    self.mean_, self.sims_, self.lower_, self.upper_
259                )
260
261        if self.method == "localconformal":
262
263            if self.replications is None:
264
265                if return_pi:
266
267                    predictions_bounds = self.icp_.predict(
268                        X, significance=1 - self.level
269                    )
270                    DescribeResult = namedtuple(
271                        "DescribeResult", ("mean", "lower", "upper")
272                    )
273                    return DescribeResult(
274                        pred, predictions_bounds[:, 0], predictions_bounds[:, 1]
275                    )
276
277                else:
278
279                    return pred
280
281            else:  # (self.method == "localconformal") and if self.replications is not None
282
283                raise NotImplementedError(
284                    "When self.method == 'localconformal', there are no simulations"
285                )

Class PredictionInterval: Obtain prediction intervals.

Attributes:

obj: an object;
    fitted object containing methods `fit` and `predict`

method: a string;
    method for constructing the prediction intervals.
    Currently "splitconformal" (default) and "localconformal"

level: a float;
    Confidence level for prediction intervals. Default is 95,
    equivalent to a miscoverage error of 5 (%)

replications: an integer;
    Number of replications for simulated conformal (default is `None`),
    for type_pi = "bootstrap" or "kde"

type_pi: a string;
    type of prediction interval: currently `None`
    (split conformal without simulation), "kde" or "bootstrap"

type_split: a string;
    "random" (random split of data) or "sequential" (sequential split of data)

seed: an integer;
    Reproducibility of fit (there's a random split between fitting and calibration data)
def fit(self, X, y, sample_weight=None, **kwargs):
 80    def fit(self, X, y, sample_weight=None, **kwargs):
 81        """Fit the `method` to training data (X, y).
 82
 83        Args:
 84
 85            X: array-like, shape = [n_samples, n_features];
 86                Training set vectors, where n_samples is the number
 87                of samples and n_features is the number of features.
 88
 89            y: array-like, shape = [n_samples, ]; Target values.
 90
 91            sample_weight: array-like, shape = [n_samples]
 92                Sample weights.
 93
 94        """
 95
 96        if self.type_split == "random":
 97
 98            X_train, X_calibration, y_train, y_calibration = train_test_split(
 99                X, y, test_size=0.5, random_state=self.seed
100            )
101
102        elif self.type_split == "sequential":
103
104            n_x = X.shape[0]
105            n_x_half = n_x // 2
106            first_half_idx = range(0, n_x_half)
107            second_half_idx = range(n_x_half, n_x)
108            X_train = X[first_half_idx, :]
109            X_calibration = X[second_half_idx, :]
110            y_train = y[first_half_idx]
111            y_calibration = y[second_half_idx]
112
113        if self.method == "splitconformal":
114
115            self.obj.fit(X_train, y_train)
116            preds_calibration = self.obj.predict(X_calibration)
117            self.calibrated_residuals_ = y_calibration - preds_calibration
118            absolute_residuals = np.abs(self.calibrated_residuals_)
119            self.calibrated_residuals_scaler_ = StandardScaler(
120                with_mean=True, with_std=True
121            )
122            self.scaled_calibrated_residuals_ = (
123                self.calibrated_residuals_scaler_.fit_transform(
124                    self.calibrated_residuals_.reshape(-1, 1)
125                ).ravel()
126            )
127            try:
128                # numpy version >= 1.22
129                self.quantile_ = np.quantile(
130                    a=absolute_residuals, q=self.level / 100, method="higher"
131                )
132            except:
133                # numpy version < 1.22
134                self.quantile_ = np.quantile(
135                    a=absolute_residuals,
136                    q=self.level / 100,
137                    interpolation="higher",
138                )
139
140        if self.method == "localconformal":
141
142            mad_estimator = ExtraTreesRegressor()
143            normalizer = RegressorNormalizer(
144                self.obj, mad_estimator, AbsErrorErrFunc()
145            )
146            nc = RegressorNc(self.obj, AbsErrorErrFunc(), normalizer)
147            self.icp_ = IcpRegressor(nc)
148            self.icp_.fit(X_train, y_train)
149            self.icp_.calibrate(X_calibration, y_calibration)
150
151        return self

Fit the method to training data (X, y).

Args:

X: array-like, shape = [n_samples, n_features];
    Training set vectors, where n_samples is the number
    of samples and n_features is the number of features.

y: array-like, shape = [n_samples, ]; Target values.

sample_weight: array-like, shape = [n_samples]
    Sample weights.
def predict(self, X, return_pi=False):
153    def predict(self, X, return_pi=False):
154        """Obtain predictions and prediction intervals
155
156        Args:
157
158            X: array-like, shape = [n_samples, n_features];
159                Testing set vectors, where n_samples is the number
160                of samples and n_features is the number of features.
161
162            return_pi: boolean
163                Whether the prediction interval is returned or not.
164                Default is False, for compatibility with other _estimators_.
165                If True, a tuple containing the predictions + lower and upper
166                bounds is returned.
167
168        """
169
170        if self.method == "splitconformal":
171            pred = self.obj.predict(X)
172
173        if self.method == "localconformal":
174            pred = self.icp_.predict(X)
175
176        if self.method == "splitconformal":
177
178            if (
179                self.replications is None and self.type_pi is None
180            ):  # type_pi is not used here, no bootstrap or kde
181
182                if return_pi:
183
184                    DescribeResult = namedtuple(
185                        "DescribeResult", ("mean", "lower", "upper")
186                    )
187
188                    return DescribeResult(
189                        pred, pred - self.quantile_, pred + self.quantile_
190                    )
191
192                else:
193
194                    return pred
195
196            else:  # self.method == "splitconformal" and if self.replications is not None, type_pi must be used
197
198                if self.type_pi is None:
199                    self.type_pi = "kde"
200                    raise Warning("type_pi must be set, setting to 'kde'")
201
202                if self.replications is None:
203                    self.replications = 100
204                    raise Warning("replications must be set, setting to 100")
205
206                assert self.type_pi in (
207                    "bootstrap",
208                    "kde",
209                ), "`self.type_pi` must be in ('bootstrap', 'kde')"
210
211                if self.type_pi == "bootstrap":
212                    np.random.seed(self.seed)
213                    self.residuals_sims_ = np.asarray(
214                        [
215                            np.random.choice(
216                                a=self.scaled_calibrated_residuals_,
217                                size=X.shape[0],
218                            )
219                            for _ in range(self.replications)
220                        ]
221                    ).T
222                    self.sims_ = np.asarray(
223                        [
224                            pred
225                            + self.calibrated_residuals_scaler_.scale_[0]
226                            * self.residuals_sims_[:, i].ravel()
227                            for i in range(self.replications)
228                        ]
229                    ).T
230                elif self.type_pi == "kde":
231                    self.kde_ = gaussian_kde(
232                        dataset=self.scaled_calibrated_residuals_
233                    )
234                    self.sims_ = np.asarray(
235                        [
236                            pred
237                            + self.calibrated_residuals_scaler_.scale_[0]
238                            * self.kde_.resample(
239                                size=X.shape[0], seed=self.seed + i
240                            ).ravel()
241                            for i in range(self.replications)
242                        ]
243                    ).T
244
245                self.mean_ = np.mean(self.sims_, axis=1)
246                self.lower_ = np.quantile(
247                    self.sims_, q=self.alpha_ / 200, axis=1
248                )
249                self.upper_ = np.quantile(
250                    self.sims_, q=1 - self.alpha_ / 200, axis=1
251                )
252
253                DescribeResult = namedtuple(
254                    "DescribeResult", ("mean", "sims", "lower", "upper")
255                )
256
257                return DescribeResult(
258                    self.mean_, self.sims_, self.lower_, self.upper_
259                )
260
261        if self.method == "localconformal":
262
263            if self.replications is None:
264
265                if return_pi:
266
267                    predictions_bounds = self.icp_.predict(
268                        X, significance=1 - self.level
269                    )
270                    DescribeResult = namedtuple(
271                        "DescribeResult", ("mean", "lower", "upper")
272                    )
273                    return DescribeResult(
274                        pred, predictions_bounds[:, 0], predictions_bounds[:, 1]
275                    )
276
277                else:
278
279                    return pred
280
281            else:  # (self.method == "localconformal") and if self.replications is not None
282
283                raise NotImplementedError(
284                    "When self.method == 'localconformal', there are no simulations"
285                )

Obtain predictions and prediction intervals

Args:

X: array-like, shape = [n_samples, n_features];
    Testing set vectors, where n_samples is the number
    of samples and n_features is the number of features.

return_pi: boolean
    Whether the prediction interval is returned or not.
    Default is False, for compatibility with other _estimators_.
    If True, a tuple containing the predictions + lower and upper
    bounds is returned.
class SimpleMultitaskClassifier(nnetsauce.Base, sklearn.base.ClassifierMixin):
 17class SimpleMultitaskClassifier(Base, ClassifierMixin):
 18    """Multitask Classification model based on regression models, with shared covariates
 19
 20    Parameters:
 21
 22        obj: object
 23            any object (must be a regression model) containing a method fit (obj.fit())
 24            and a method predict (obj.predict())
 25
 26        seed: int
 27            reproducibility seed
 28
 29    Attributes:
 30
 31        fit_objs_: dict
 32            objects adjusted to each individual time series
 33
 34        n_classes_: int
 35            number of classes for the classifier
 36
 37    Examples:
 38
 39    ```python
 40    import nnetsauce as ns
 41    import numpy as np
 42    from sklearn.datasets import load_breast_cancer
 43    from sklearn.linear_model import LinearRegression
 44    from sklearn.model_selection import train_test_split
 45    from sklearn import metrics
 46    from time import time
 47
 48    breast_cancer = load_breast_cancer()
 49    Z = breast_cancer.data
 50    t = breast_cancer.target
 51
 52    X_train, X_test, y_train, y_test = train_test_split(Z, t, test_size=0.2,
 53                                                        random_state=123+2*10)
 54
 55    # Linear Regression is used
 56    regr = LinearRegression()
 57    fit_obj = ns.SimpleMultitaskClassifier(regr)
 58
 59    start = time()
 60    fit_obj.fit(X_train, y_train)
 61    print(f"Elapsed {time() - start}")
 62
 63    print(fit_obj.score(X_test, y_test))
 64    print(fit_obj.score(X_test, y_test, scoring="roc_auc"))
 65
 66    start = time()
 67    preds = fit_obj.predict(X_test)
 68    print(f"Elapsed {time() - start}")
 69    print(metrics.classification_report(preds, y_test))
 70    ```
 71
 72    """
 73
 74    # construct the object -----
 75
 76    def __init__(
 77        self,
 78        obj,
 79    ):
 80        self.type_fit = "classification"
 81        self.obj = obj
 82        self.fit_objs_ = {}
 83        self.X_scaler_ = StandardScaler()
 84        self.scaled_X_ = None
 85
 86    def fit(self, X, y, sample_weight=None, **kwargs):
 87        """Fit SimpleMultitaskClassifier to training data (X, y).
 88
 89        Args:
 90
 91            X: {array-like}, shape = [n_samples, n_features]
 92                Training vectors, where n_samples is the number
 93                of samples and n_features is the number of features.
 94
 95            y: array-like, shape = [n_samples]
 96                Target values.
 97
 98            **kwargs: additional parameters to be passed to
 99                    self.cook_training_set or self.obj.fit
100
101        Returns:
102
103            self: object
104
105        """
106
107        assert mx.is_factor(y), "y must contain only integers"
108
109        self.classes_ = np.unique(y)  # for compatibility with sklearn
110        self.n_classes_ = len(self.classes_)  # for compatibility with sklearn
111
112        self.scaled_X_ = self.X_scaler_.fit_transform(X)
113
114        # multitask response
115        Y = mo.one_hot_encode2(y, self.n_classes_)
116
117        # if sample_weight is None:
118        for i in range(self.n_classes_):
119            self.fit_objs_[i] = deepcopy(
120                self.obj.fit(self.scaled_X_, Y[:, i], **kwargs)
121            )
122        self.classes_ = np.unique(y)
123        return self
124
125    def predict(self, X, **kwargs):
126        """Predict test data X.
127
128        Args:
129
130            X: {array-like}, shape = [n_samples, n_features]
131                Training vectors, where n_samples is the number
132                of samples and n_features is the number of features.
133
134            **kwargs: additional parameters
135
136        Returns:
137
138            model predictions: {array-like}
139
140        """
141
142        return np.argmax(self.predict_proba(X, **kwargs), axis=1)
143
144    def predict_proba(self, X, **kwargs):
145        """Predict probabilities for test data X.
146
147        Args:
148
149            X: {array-like}, shape = [n_samples, n_features]
150                Training vectors, where n_samples is the number
151                of samples and n_features is the number of features.
152
153            **kwargs: additional parameters
154
155        Returns:
156
157            probability estimates for test data: {array-like}
158
159        """
160
161        shape_X = X.shape
162
163        probs = np.zeros((shape_X[0], self.n_classes_))
164
165        if len(shape_X) == 1:
166            n_features = shape_X[0]
167
168            new_X = mo.rbind(
169                X.reshape(1, n_features),
170                np.ones(n_features).reshape(1, n_features),
171            )
172
173            Z = self.X_scaler_.transform(new_X, **kwargs)
174
175            # loop on all the classes
176            for i in range(self.n_classes_):
177                probs[:, i] = self.fit_objs_[i].predict(Z, **kwargs)[0]
178
179        else:
180            Z = self.X_scaler_.transform(X, **kwargs)
181
182            # loop on all the classes
183            for i in range(self.n_classes_):
184                probs[:, i] = self.fit_objs_[i].predict(Z, **kwargs)
185
186        expit_raw_probs = expit(probs)
187
188        return expit_raw_probs / expit_raw_probs.sum(axis=1)[:, None]

Multitask Classification model based on regression models, with shared covariates

Parameters:

obj: object
    any object (must be a regression model) containing a method fit (obj.fit())
    and a method predict (obj.predict())

seed: int
    reproducibility seed

Attributes:

fit_objs_: dict
    objects adjusted to each individual time series

n_classes_: int
    number of classes for the classifier

Examples:

import nnetsauce as ns
import numpy as np
from sklearn.datasets import load_breast_cancer
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split
from sklearn import metrics
from time import time

breast_cancer = load_breast_cancer()
Z = breast_cancer.data
t = breast_cancer.target

X_train, X_test, y_train, y_test = train_test_split(Z, t, test_size=0.2,
                                                    random_state=123+2*10)

# Linear Regression is used
regr = LinearRegression()
fit_obj = ns.SimpleMultitaskClassifier(regr)

start = time()
fit_obj.fit(X_train, y_train)
print(f"Elapsed {time() - start}")

print(fit_obj.score(X_test, y_test))
print(fit_obj.score(X_test, y_test, scoring="roc_auc"))

start = time()
preds = fit_obj.predict(X_test)
print(f"Elapsed {time() - start}")
print(metrics.classification_report(preds, y_test))
def fit(self, X, y, sample_weight=None, **kwargs):
 86    def fit(self, X, y, sample_weight=None, **kwargs):
 87        """Fit SimpleMultitaskClassifier to training data (X, y).
 88
 89        Args:
 90
 91            X: {array-like}, shape = [n_samples, n_features]
 92                Training vectors, where n_samples is the number
 93                of samples and n_features is the number of features.
 94
 95            y: array-like, shape = [n_samples]
 96                Target values.
 97
 98            **kwargs: additional parameters to be passed to
 99                    self.cook_training_set or self.obj.fit
100
101        Returns:
102
103            self: object
104
105        """
106
107        assert mx.is_factor(y), "y must contain only integers"
108
109        self.classes_ = np.unique(y)  # for compatibility with sklearn
110        self.n_classes_ = len(self.classes_)  # for compatibility with sklearn
111
112        self.scaled_X_ = self.X_scaler_.fit_transform(X)
113
114        # multitask response
115        Y = mo.one_hot_encode2(y, self.n_classes_)
116
117        # if sample_weight is None:
118        for i in range(self.n_classes_):
119            self.fit_objs_[i] = deepcopy(
120                self.obj.fit(self.scaled_X_, Y[:, i], **kwargs)
121            )
122        self.classes_ = np.unique(y)
123        return self

Fit SimpleMultitaskClassifier to training data (X, y).

Args:

X: {array-like}, shape = [n_samples, n_features]
    Training vectors, where n_samples is the number
    of samples and n_features is the number of features.

y: array-like, shape = [n_samples]
    Target values.

**kwargs: additional parameters to be passed to
        self.cook_training_set or self.obj.fit

Returns:

self: object
def predict(self, X, **kwargs):
125    def predict(self, X, **kwargs):
126        """Predict test data X.
127
128        Args:
129
130            X: {array-like}, shape = [n_samples, n_features]
131                Training vectors, where n_samples is the number
132                of samples and n_features is the number of features.
133
134            **kwargs: additional parameters
135
136        Returns:
137
138            model predictions: {array-like}
139
140        """
141
142        return np.argmax(self.predict_proba(X, **kwargs), axis=1)

Predict test data X.

Args:

X: {array-like}, shape = [n_samples, n_features]
    Training vectors, where n_samples is the number
    of samples and n_features is the number of features.

**kwargs: additional parameters

Returns:

model predictions: {array-like}
def predict_proba(self, X, **kwargs):
144    def predict_proba(self, X, **kwargs):
145        """Predict probabilities for test data X.
146
147        Args:
148
149            X: {array-like}, shape = [n_samples, n_features]
150                Training vectors, where n_samples is the number
151                of samples and n_features is the number of features.
152
153            **kwargs: additional parameters
154
155        Returns:
156
157            probability estimates for test data: {array-like}
158
159        """
160
161        shape_X = X.shape
162
163        probs = np.zeros((shape_X[0], self.n_classes_))
164
165        if len(shape_X) == 1:
166            n_features = shape_X[0]
167
168            new_X = mo.rbind(
169                X.reshape(1, n_features),
170                np.ones(n_features).reshape(1, n_features),
171            )
172
173            Z = self.X_scaler_.transform(new_X, **kwargs)
174
175            # loop on all the classes
176            for i in range(self.n_classes_):
177                probs[:, i] = self.fit_objs_[i].predict(Z, **kwargs)[0]
178
179        else:
180            Z = self.X_scaler_.transform(X, **kwargs)
181
182            # loop on all the classes
183            for i in range(self.n_classes_):
184                probs[:, i] = self.fit_objs_[i].predict(Z, **kwargs)
185
186        expit_raw_probs = expit(probs)
187
188        return expit_raw_probs / expit_raw_probs.sum(axis=1)[:, None]

Predict probabilities for test data X.

Args:

X: {array-like}, shape = [n_samples, n_features]
    Training vectors, where n_samples is the number
    of samples and n_features is the number of features.

**kwargs: additional parameters

Returns:

probability estimates for test data: {array-like}
class Optimizer:
  9class Optimizer:
 10    """Optimizer class
 11
 12    Attributes:
 13
 14        type_optim: str
 15            type of optimizer, (currently) either 'sgd' (stochastic minibatch gradient descent)
 16            or 'scd' (stochastic minibatch coordinate descent)
 17
 18        num_iters: int
 19            number of iterations of the optimizer
 20
 21        learning_rate: float
 22            step size
 23
 24        batch_prop: float
 25            proportion of the initial data used at each optimization step
 26
 27        learning_method: str
 28            "poly" - learning rate decreasing as a polynomial function
 29            of # of iterations (default)
 30            "exp" - learning rate decreasing as an exponential function
 31            of # of iterations
 32            "momentum" - gradient descent using momentum
 33
 34        randomization: str
 35            type of randomization applied at each step
 36            "strat" - stratified subsampling (default)
 37            "shuffle" - random subsampling
 38
 39        mass: float
 40            mass on velocity, for `method` == "momentum"
 41
 42        decay: float
 43            coefficient of decrease of the learning rate for
 44            `method` == "poly" and `method` == "exp"
 45
 46        tolerance: float
 47            early stopping parameter (convergence of loss function)
 48
 49        verbose: int
 50            controls verbosity of gradient descent
 51            0 - nothing is printed
 52            1 - a progress bar is printed
 53            2 - successive loss function values are printed
 54
 55    """
 56
 57    # construct the object -----
 58
 59    def __init__(
 60        self,
 61        type_optim="sgd",
 62        num_iters=100,
 63        learning_rate=0.01,
 64        batch_prop=1.0,
 65        learning_method="momentum",
 66        randomization="strat",
 67        mass=0.9,
 68        decay=0.1,
 69        tolerance=1e-3,
 70        verbose=1,
 71    ):
 72        self.type_optim = type_optim
 73        self.num_iters = num_iters
 74        self.learning_rate = learning_rate
 75        self.batch_prop = batch_prop
 76        self.learning_method = learning_method
 77        self.randomization = randomization
 78        self.mass = mass
 79        self.decay = decay
 80        self.tolerance = tolerance
 81        self.verbose = verbose
 82        self.opt = None
 83
 84    def fit(self, loss_func, response, x0, **kwargs):
 85        """Fit GLM model to training data (X, y).
 86
 87        Args:
 88
 89            loss_func: loss function
 90
 91            response: array-like, shape = [n_samples]
 92            target variable (used for subsampling)
 93
 94            x0: array-like, shape = [n_features]
 95                initial value provided to the optimizer
 96
 97            **kwargs: additional parameters to be passed to
 98                    loss function
 99
100        Returns:
101
102            self: object
103
104        """
105
106        if self.type_optim == "scd":
107            self.results = scd(
108                loss_func,
109                response=response,
110                x=x0,
111                num_iters=self.num_iters,
112                batch_prop=self.batch_prop,
113                learning_rate=self.learning_rate,
114                learning_method=self.learning_method,
115                mass=self.mass,
116                decay=self.decay,
117                randomization=self.randomization,
118                tolerance=self.tolerance,
119                verbose=self.verbose,
120                **kwargs
121            )
122
123        if self.type_optim == "sgd":
124            self.results = sgd(
125                loss_func,
126                response=response,
127                x=x0,
128                num_iters=self.num_iters,
129                batch_prop=self.batch_prop,
130                learning_rate=self.learning_rate,
131                learning_method=self.learning_method,
132                mass=self.mass,
133                decay=self.decay,
134                randomization=self.randomization,
135                tolerance=self.tolerance,
136                verbose=self.verbose,
137                **kwargs
138            )
139
140        return self
141
142    def one_hot_encode(self, y, n_classes):
143        return one_hot_encode(y, n_classes)

Optimizer class

Attributes:

type_optim: str
    type of optimizer, (currently) either 'sgd' (stochastic minibatch gradient descent)
    or 'scd' (stochastic minibatch coordinate descent)

num_iters: int
    number of iterations of the optimizer

learning_rate: float
    step size

batch_prop: float
    proportion of the initial data used at each optimization step

learning_method: str
    "poly" - learning rate decreasing as a polynomial function
    of # of iterations (default)
    "exp" - learning rate decreasing as an exponential function
    of # of iterations
    "momentum" - gradient descent using momentum

randomization: str
    type of randomization applied at each step
    "strat" - stratified subsampling (default)
    "shuffle" - random subsampling

mass: float
    mass on velocity, for `method` == "momentum"

decay: float
    coefficient of decrease of the learning rate for
    `method` == "poly" and `method` == "exp"

tolerance: float
    early stopping parameter (convergence of loss function)

verbose: int
    controls verbosity of gradient descent
    0 - nothing is printed
    1 - a progress bar is printed
    2 - successive loss function values are printed
def fit(self, loss_func, response, x0, **kwargs):
 84    def fit(self, loss_func, response, x0, **kwargs):
 85        """Fit GLM model to training data (X, y).
 86
 87        Args:
 88
 89            loss_func: loss function
 90
 91            response: array-like, shape = [n_samples]
 92            target variable (used for subsampling)
 93
 94            x0: array-like, shape = [n_features]
 95                initial value provided to the optimizer
 96
 97            **kwargs: additional parameters to be passed to
 98                    loss function
 99
100        Returns:
101
102            self: object
103
104        """
105
106        if self.type_optim == "scd":
107            self.results = scd(
108                loss_func,
109                response=response,
110                x=x0,
111                num_iters=self.num_iters,
112                batch_prop=self.batch_prop,
113                learning_rate=self.learning_rate,
114                learning_method=self.learning_method,
115                mass=self.mass,
116                decay=self.decay,
117                randomization=self.randomization,
118                tolerance=self.tolerance,
119                verbose=self.verbose,
120                **kwargs
121            )
122
123        if self.type_optim == "sgd":
124            self.results = sgd(
125                loss_func,
126                response=response,
127                x=x0,
128                num_iters=self.num_iters,
129                batch_prop=self.batch_prop,
130                learning_rate=self.learning_rate,
131                learning_method=self.learning_method,
132                mass=self.mass,
133                decay=self.decay,
134                randomization=self.randomization,
135                tolerance=self.tolerance,
136                verbose=self.verbose,
137                **kwargs
138            )
139
140        return self

Fit GLM model to training data (X, y).

Args:

loss_func: loss function

response: array-like, shape = [n_samples]
target variable (used for subsampling)

x0: array-like, shape = [n_features]
    initial value provided to the optimizer

**kwargs: additional parameters to be passed to
        loss function

Returns:

self: object
class RandomBagRegressor(nnetsauce.randombag.bag.RandomBag, sklearn.base.RegressorMixin):
 18class RandomBagRegressor(RandomBag, RegressorMixin):
 19    """Randomized 'Bagging' Regression model
 20
 21    Parameters:
 22
 23        obj: object
 24            any object containing a method fit (obj.fit()) and a method predict
 25            (obj.predict())
 26
 27        n_estimators: int
 28            number of boosting iterations
 29
 30        n_hidden_features: int
 31            number of nodes in the hidden layer
 32
 33        activation_name: str
 34            activation function: 'relu', 'tanh', 'sigmoid', 'prelu' or 'elu'
 35
 36        a: float
 37            hyperparameter for 'prelu' or 'elu' activation function
 38
 39        nodes_sim: str
 40            type of simulation for the nodes: 'sobol', 'hammersley', 'halton',
 41            'uniform'
 42
 43        bias: boolean
 44            indicates if the hidden layer contains a bias term (True) or not
 45            (False)
 46
 47        dropout: float
 48            regularization parameter; (random) percentage of nodes dropped out
 49            of the training
 50
 51        direct_link: boolean
 52            indicates if the original predictors are included (True) in model''s
 53            fitting or not (False)
 54
 55        n_clusters: int
 56            number of clusters for 'kmeans' or 'gmm' clustering (could be 0:
 57                no clustering)
 58
 59        cluster_encode: bool
 60            defines how the variable containing clusters is treated (default is one-hot)
 61            if `False`, then labels are used, without one-hot encoding
 62
 63        type_clust: str
 64            type of clustering method: currently k-means ('kmeans') or Gaussian
 65            Mixture Model ('gmm')
 66
 67        type_scaling: a tuple of 3 strings
 68            scaling methods for inputs, hidden layer, and clustering respectively
 69            (and when relevant).
 70            Currently available: standardization ('std') or MinMax scaling ('minmax')
 71
 72        col_sample: float
 73            percentage of covariates randomly chosen for training
 74
 75        row_sample: float
 76            percentage of rows chosen for training, by stratified bootstrapping
 77
 78        seed: int
 79            reproducibility seed for nodes_sim=='uniform'
 80
 81        backend: str
 82            "cpu" or "gpu" or "tpu"
 83
 84    Attributes:
 85
 86        voter_: dict
 87            dictionary containing all the fitted base-learners
 88
 89
 90    Examples:
 91
 92    ```python
 93    import numpy as np
 94    import nnetsauce as ns
 95    from sklearn.datasets import fetch_california_housing
 96    from sklearn.tree import DecisionTreeRegressor
 97    from sklearn.model_selection import train_test_split
 98
 99    X, y = fetch_california_housing(return_X_y=True, as_frame=False)
100
101    # split data into training test and test set
102    X_train, X_test, y_train, y_test = train_test_split(X, y,
103                                                        test_size=0.2, random_state=13)
104
105    # Requires further tuning
106    obj = DecisionTreeRegressor(max_depth=3, random_state=123)
107    obj2 = ns.RandomBagRegressor(obj=obj, direct_link=False,
108                                n_estimators=50,
109                                col_sample=0.9, row_sample=0.9,
110                                dropout=0, n_clusters=0, verbose=1)
111
112    obj2.fit(X_train, y_train)
113
114    print(np.sqrt(obj2.score(X_test, y_test))) # RMSE
115
116    ```
117
118    """
119
120    # construct the object -----
121
122    def __init__(
123        self,
124        obj,
125        n_estimators=10,
126        n_hidden_features=1,
127        activation_name="relu",
128        a=0.01,
129        nodes_sim="sobol",
130        bias=True,
131        dropout=0,
132        direct_link=False,
133        n_clusters=2,
134        cluster_encode=True,
135        type_clust="kmeans",
136        type_scaling=("std", "std", "std"),
137        col_sample=1,
138        row_sample=1,
139        n_jobs=None,
140        seed=123,
141        verbose=1,
142        backend="cpu",
143    ):
144        super().__init__(
145            obj=obj,
146            n_estimators=n_estimators,
147            n_hidden_features=n_hidden_features,
148            activation_name=activation_name,
149            a=a,
150            nodes_sim=nodes_sim,
151            bias=bias,
152            dropout=dropout,
153            direct_link=direct_link,
154            n_clusters=n_clusters,
155            cluster_encode=cluster_encode,
156            type_clust=type_clust,
157            type_scaling=type_scaling,
158            col_sample=col_sample,
159            row_sample=row_sample,
160            seed=seed,
161            backend=backend,
162        )
163
164        self.type_fit = "regression"
165        self.verbose = verbose
166        self.n_jobs = n_jobs
167        self.voter_ = {}
168
169    def fit(self, X, y, **kwargs):
170        """Fit Random 'Bagging' model to training data (X, y).
171
172        Args:
173
174            X: {array-like}, shape = [n_samples, n_features]
175                Training vectors, where n_samples is the number
176                of samples and n_features is the number of features.
177
178            y: array-like, shape = [n_samples]
179                Target values.
180
181            **kwargs: additional parameters to be passed to
182                    self.cook_training_set or self.obj.fit
183
184        Returns:
185
186            self: object
187
188        """
189
190        base_learner = CustomRegressor(
191            self.obj,
192            n_hidden_features=self.n_hidden_features,
193            activation_name=self.activation_name,
194            a=self.a,
195            nodes_sim=self.nodes_sim,
196            bias=self.bias,
197            dropout=self.dropout,
198            direct_link=self.direct_link,
199            n_clusters=self.n_clusters,
200            type_clust=self.type_clust,
201            type_scaling=self.type_scaling,
202            col_sample=self.col_sample,
203            row_sample=self.row_sample,
204            seed=self.seed,
205        )
206
207        # 1 - Sequential training -----
208
209        if self.n_jobs is None:
210            self.voter_ = rbagloop_regression(
211                base_learner, X, y, self.n_estimators, self.verbose, self.seed
212            )
213
214            self.n_estimators = len(self.voter_)
215
216            return self
217
218        # 2 - Parallel training -----
219        # buggy
220        # if self.n_jobs is not None:
221        def fit_estimators(m):
222            base_learner__ = deepcopy(base_learner)
223            base_learner__.set_params(seed=self.seed + m * 1000)
224            base_learner__.fit(X, y, **kwargs)
225            return base_learner__
226
227        if self.verbose == 1:
228            voters_list = Parallel(n_jobs=self.n_jobs, prefer="threads")(
229                delayed(fit_estimators)(m)
230                for m in tqdm(range(self.n_estimators))
231            )
232        else:
233            voters_list = Parallel(n_jobs=self.n_jobs, prefer="threads")(
234                delayed(fit_estimators)(m) for m in range(self.n_estimators)
235            )
236
237        self.voter_ = {i: elt for i, elt in enumerate(voters_list)}
238
239        self.n_estimators = len(self.voter_)
240
241        return self
242
243    def predict(self, X, weights=None, **kwargs):
244        """Predict for test data X.
245
246        Args:
247
248            X: {array-like}, shape = [n_samples, n_features]
249                Training vectors, where n_samples is the number
250                of samples and n_features is the number of features.
251
252            **kwargs: additional parameters to be passed to
253                    self.cook_test_set
254
255        Returns:
256
257            estimates for test data: {array-like}
258
259        """
260
261        def calculate_preds(voter, weights=None):
262            ensemble_preds = 0
263
264            n_iter = len(voter)
265
266            assert n_iter > 0, "no estimator found in `RandomBag` ensemble"
267
268            if weights is None:
269                for idx, elt in voter.items():
270                    ensemble_preds += elt.predict(X)
271
272                return ensemble_preds / n_iter
273
274            # if weights is not None:
275            for idx, elt in voter.items():
276                ensemble_preds += weights[idx] * elt.predict(X)
277
278            return ensemble_preds
279
280        # end calculate_preds ----
281
282        if weights is None:
283            return calculate_preds(self.voter_)
284
285        # if weights is not None:
286        self.weights = weights
287
288        return calculate_preds(self.voter_, weights)

Randomized 'Bagging' Regression model

Parameters:

obj: object
    any object containing a method fit (obj.fit()) and a method predict
    (obj.predict())

n_estimators: int
    number of boosting iterations

n_hidden_features: int
    number of nodes in the hidden layer

activation_name: str
    activation function: 'relu', 'tanh', 'sigmoid', 'prelu' or 'elu'

a: float
    hyperparameter for 'prelu' or 'elu' activation function

nodes_sim: str
    type of simulation for the nodes: 'sobol', 'hammersley', 'halton',
    'uniform'

bias: boolean
    indicates if the hidden layer contains a bias term (True) or not
    (False)

dropout: float
    regularization parameter; (random) percentage of nodes dropped out
    of the training

direct_link: boolean
    indicates if the original predictors are included (True) in model''s
    fitting or not (False)

n_clusters: int
    number of clusters for 'kmeans' or 'gmm' clustering (could be 0:
        no clustering)

cluster_encode: bool
    defines how the variable containing clusters is treated (default is one-hot)
    if `False`, then labels are used, without one-hot encoding

type_clust: str
    type of clustering method: currently k-means ('kmeans') or Gaussian
    Mixture Model ('gmm')

type_scaling: a tuple of 3 strings
    scaling methods for inputs, hidden layer, and clustering respectively
    (and when relevant).
    Currently available: standardization ('std') or MinMax scaling ('minmax')

col_sample: float
    percentage of covariates randomly chosen for training

row_sample: float
    percentage of rows chosen for training, by stratified bootstrapping

seed: int
    reproducibility seed for nodes_sim=='uniform'

backend: str
    "cpu" or "gpu" or "tpu"

Attributes:

voter_: dict
    dictionary containing all the fitted base-learners

Examples:

import numpy as np
import nnetsauce as ns
from sklearn.datasets import fetch_california_housing
from sklearn.tree import DecisionTreeRegressor
from sklearn.model_selection import train_test_split

X, y = fetch_california_housing(return_X_y=True, as_frame=False)

# split data into training test and test set
X_train, X_test, y_train, y_test = train_test_split(X, y,
                                                    test_size=0.2, random_state=13)

# Requires further tuning
obj = DecisionTreeRegressor(max_depth=3, random_state=123)
obj2 = ns.RandomBagRegressor(obj=obj, direct_link=False,
                            n_estimators=50,
                            col_sample=0.9, row_sample=0.9,
                            dropout=0, n_clusters=0, verbose=1)

obj2.fit(X_train, y_train)

print(np.sqrt(obj2.score(X_test, y_test))) # RMSE
def fit(self, X, y, **kwargs):
169    def fit(self, X, y, **kwargs):
170        """Fit Random 'Bagging' model to training data (X, y).
171
172        Args:
173
174            X: {array-like}, shape = [n_samples, n_features]
175                Training vectors, where n_samples is the number
176                of samples and n_features is the number of features.
177
178            y: array-like, shape = [n_samples]
179                Target values.
180
181            **kwargs: additional parameters to be passed to
182                    self.cook_training_set or self.obj.fit
183
184        Returns:
185
186            self: object
187
188        """
189
190        base_learner = CustomRegressor(
191            self.obj,
192            n_hidden_features=self.n_hidden_features,
193            activation_name=self.activation_name,
194            a=self.a,
195            nodes_sim=self.nodes_sim,
196            bias=self.bias,
197            dropout=self.dropout,
198            direct_link=self.direct_link,
199            n_clusters=self.n_clusters,
200            type_clust=self.type_clust,
201            type_scaling=self.type_scaling,
202            col_sample=self.col_sample,
203            row_sample=self.row_sample,
204            seed=self.seed,
205        )
206
207        # 1 - Sequential training -----
208
209        if self.n_jobs is None:
210            self.voter_ = rbagloop_regression(
211                base_learner, X, y, self.n_estimators, self.verbose, self.seed
212            )
213
214            self.n_estimators = len(self.voter_)
215
216            return self
217
218        # 2 - Parallel training -----
219        # buggy
220        # if self.n_jobs is not None:
221        def fit_estimators(m):
222            base_learner__ = deepcopy(base_learner)
223            base_learner__.set_params(seed=self.seed + m * 1000)
224            base_learner__.fit(X, y, **kwargs)
225            return base_learner__
226
227        if self.verbose == 1:
228            voters_list = Parallel(n_jobs=self.n_jobs, prefer="threads")(
229                delayed(fit_estimators)(m)
230                for m in tqdm(range(self.n_estimators))
231            )
232        else:
233            voters_list = Parallel(n_jobs=self.n_jobs, prefer="threads")(
234                delayed(fit_estimators)(m) for m in range(self.n_estimators)
235            )
236
237        self.voter_ = {i: elt for i, elt in enumerate(voters_list)}
238
239        self.n_estimators = len(self.voter_)
240
241        return self

Fit Random 'Bagging' model to training data (X, y).

Args:

X: {array-like}, shape = [n_samples, n_features]
    Training vectors, where n_samples is the number
    of samples and n_features is the number of features.

y: array-like, shape = [n_samples]
    Target values.

**kwargs: additional parameters to be passed to
        self.cook_training_set or self.obj.fit

Returns:

self: object
def predict(self, X, weights=None, **kwargs):
243    def predict(self, X, weights=None, **kwargs):
244        """Predict for test data X.
245
246        Args:
247
248            X: {array-like}, shape = [n_samples, n_features]
249                Training vectors, where n_samples is the number
250                of samples and n_features is the number of features.
251
252            **kwargs: additional parameters to be passed to
253                    self.cook_test_set
254
255        Returns:
256
257            estimates for test data: {array-like}
258
259        """
260
261        def calculate_preds(voter, weights=None):
262            ensemble_preds = 0
263
264            n_iter = len(voter)
265
266            assert n_iter > 0, "no estimator found in `RandomBag` ensemble"
267
268            if weights is None:
269                for idx, elt in voter.items():
270                    ensemble_preds += elt.predict(X)
271
272                return ensemble_preds / n_iter
273
274            # if weights is not None:
275            for idx, elt in voter.items():
276                ensemble_preds += weights[idx] * elt.predict(X)
277
278            return ensemble_preds
279
280        # end calculate_preds ----
281
282        if weights is None:
283            return calculate_preds(self.voter_)
284
285        # if weights is not None:
286        self.weights = weights
287
288        return calculate_preds(self.voter_, weights)

Predict for test data X.

Args:

X: {array-like}, shape = [n_samples, n_features]
    Training vectors, where n_samples is the number
    of samples and n_features is the number of features.

**kwargs: additional parameters to be passed to
        self.cook_test_set

Returns:

estimates for test data: {array-like}
class RandomBagClassifier(nnetsauce.randombag.bag.RandomBag, sklearn.base.ClassifierMixin):
 18class RandomBagClassifier(RandomBag, ClassifierMixin):
 19    """Randomized 'Bagging' Classification model
 20
 21    Parameters:
 22
 23        obj: object
 24            any object containing a method fit (obj.fit()) and a method predict
 25            (obj.predict())
 26
 27        n_estimators: int
 28            number of boosting iterations
 29
 30        n_hidden_features: int
 31            number of nodes in the hidden layer
 32
 33        activation_name: str
 34            activation function: 'relu', 'tanh', 'sigmoid', 'prelu' or 'elu'
 35
 36        a: float
 37            hyperparameter for 'prelu' or 'elu' activation function
 38
 39        nodes_sim: str
 40            type of simulation for the nodes: 'sobol', 'hammersley', 'halton',
 41            'uniform'
 42
 43        bias: boolean
 44            indicates if the hidden layer contains a bias term (True) or not
 45            (False)
 46
 47        dropout: float
 48            regularization parameter; (random) percentage of nodes dropped out
 49            of the training
 50
 51        direct_link: boolean
 52            indicates if the original predictors are included (True) in model's
 53            fitting or not (False)
 54
 55        n_clusters: int
 56            number of clusters for 'kmeans' or 'gmm' clustering (could be 0:
 57                no clustering)
 58
 59        cluster_encode: bool
 60            defines how the variable containing clusters is treated (default is one-hot)
 61            if `False`, then labels are used, without one-hot encoding
 62
 63        type_clust: str
 64            type of clustering method: currently k-means ('kmeans') or Gaussian
 65            Mixture Model ('gmm')
 66
 67        type_scaling: a tuple of 3 strings
 68            scaling methods for inputs, hidden layer, and clustering respectively
 69            (and when relevant).
 70            Currently available: standardization ('std') or MinMax scaling ('minmax')
 71
 72        col_sample: float
 73            percentage of covariates randomly chosen for training
 74
 75        row_sample: float
 76            percentage of rows chosen for training, by stratified bootstrapping
 77
 78        seed: int
 79            reproducibility seed for nodes_sim=='uniform'
 80
 81        backend: str
 82            "cpu" or "gpu" or "tpu"
 83
 84    Attributes:
 85
 86        voter_: dict
 87            dictionary containing all the fitted base-learners
 88
 89
 90    Examples:
 91
 92    See also [https://github.com/Techtonique/nnetsauce/blob/master/examples/randombag_classification.py](https://github.com/Techtonique/nnetsauce/blob/master/examples/randombag_classification.py)
 93
 94    ```python
 95    import nnetsauce as ns
 96    from sklearn.datasets import load_breast_cancer
 97    from sklearn.tree import DecisionTreeClassifier
 98    from sklearn.model_selection import train_test_split
 99    from sklearn import metrics
100    from time import time
101
102
103    breast_cancer = load_breast_cancer()
104    Z = breast_cancer.data
105    t = breast_cancer.target
106    np.random.seed(123)
107    X_train, X_test, y_train, y_test = train_test_split(Z, t, test_size=0.2)
108
109    # decision tree
110    clf = DecisionTreeClassifier(max_depth=2, random_state=123)
111    fit_obj = ns.RandomBagClassifier(clf, n_hidden_features=2,
112                                    direct_link=True,
113                                    n_estimators=100,
114                                    col_sample=0.9, row_sample=0.9,
115                                    dropout=0.3, n_clusters=0, verbose=1)
116
117    start = time()
118    fit_obj.fit(X_train, y_train)
119    print(f"Elapsed {time() - start}")
120
121    print(fit_obj.score(X_test, y_test))
122    print(fit_obj.score(X_test, y_test, scoring="roc_auc"))
123
124    start = time()
125    preds = fit_obj.predict(X_test)
126    print(f"Elapsed {time() - start}")
127    print(metrics.classification_report(preds, y_test))
128    ```
129
130    """
131
132    # construct the object -----
133
134    def __init__(
135        self,
136        obj,
137        n_estimators=10,
138        n_hidden_features=1,
139        activation_name="relu",
140        a=0.01,
141        nodes_sim="sobol",
142        bias=True,
143        dropout=0,
144        direct_link=False,
145        n_clusters=2,
146        cluster_encode=True,
147        type_clust="kmeans",
148        type_scaling=("std", "std", "std"),
149        col_sample=1,
150        row_sample=1,
151        n_jobs=None,
152        seed=123,
153        verbose=1,
154        backend="cpu",
155    ):
156        super().__init__(
157            obj=obj,
158            n_estimators=n_estimators,
159            n_hidden_features=n_hidden_features,
160            activation_name=activation_name,
161            a=a,
162            nodes_sim=nodes_sim,
163            bias=bias,
164            dropout=dropout,
165            direct_link=direct_link,
166            n_clusters=n_clusters,
167            cluster_encode=cluster_encode,
168            type_clust=type_clust,
169            type_scaling=type_scaling,
170            col_sample=col_sample,
171            row_sample=row_sample,
172            seed=seed,
173            backend=backend,
174        )
175
176        self.type_fit = "classification"
177        self.verbose = verbose
178        self.n_jobs = n_jobs
179        self.voter_ = {}
180
181    def fit(self, X, y, **kwargs):
182        """Fit Random 'Bagging' model to training data (X, y).
183
184        Args:
185
186            X: {array-like}, shape = [n_samples, n_features]
187                Training vectors, where n_samples is the number
188                of samples and n_features is the number of features.
189
190            y: array-like, shape = [n_samples]
191                Target values.
192
193            **kwargs: additional parameters to be passed to
194                    self.cook_training_set or self.obj.fit
195
196        Returns:
197
198            self: object
199
200        """
201
202        assert mx.is_factor(y), "y must contain only integers"
203
204        self.n_classes_ = len(np.unique(y))  # for compatibility with sklearn
205
206        # training
207        self.n_classes = len(np.unique(y))
208
209        base_learner = CustomClassifier(
210            self.obj,
211            n_hidden_features=self.n_hidden_features,
212            activation_name=self.activation_name,
213            a=self.a,
214            nodes_sim=self.nodes_sim,
215            bias=self.bias,
216            dropout=self.dropout,
217            direct_link=self.direct_link,
218            n_clusters=self.n_clusters,
219            type_clust=self.type_clust,
220            type_scaling=self.type_scaling,
221            col_sample=self.col_sample,
222            row_sample=self.row_sample,
223            seed=self.seed,
224        )
225
226        # 1 - Sequential training -----
227
228        if self.n_jobs is None:
229            self.voter_ = rbagloop_classification(
230                base_learner, X, y, self.n_estimators, self.verbose, self.seed
231            )
232
233            self.n_estimators = len(self.voter_)
234
235            return self
236
237        # 2 - Parallel training -----
238        # buggy
239        # if self.n_jobs is not None:
240        def fit_estimators(m):
241            base_learner__ = deepcopy(base_learner)
242            base_learner__.set_params(seed=self.seed + m * 1000)
243            base_learner__.fit(X, y, **kwargs)
244            return base_learner__
245
246        if self.verbose == 1:
247            voters_list = Parallel(n_jobs=self.n_jobs, prefer="threads")(
248                delayed(fit_estimators)(m)
249                for m in tqdm(range(self.n_estimators))
250            )
251        else:
252            voters_list = Parallel(n_jobs=self.n_jobs, prefer="threads")(
253                delayed(fit_estimators)(m) for m in range(self.n_estimators)
254            )
255
256        self.voter_ = {idx: elt for idx, elt in enumerate(voters_list)}
257
258        self.n_estimators = len(self.voter_)
259        self.classes_ = np.unique(y)
260        return self
261
262    def predict(self, X, weights=None, **kwargs):
263        """Predict test data X.
264
265        Args:
266
267            X: {array-like}, shape = [n_samples, n_features]
268                Training vectors, where n_samples is the number
269                of samples and n_features is the number of features.
270
271            **kwargs: additional parameters to be passed to
272                    self.cook_test_set
273
274        Returns:
275
276            model predictions: {array-like}
277
278        """
279        return self.predict_proba(X, weights, **kwargs).argmax(axis=1)
280
281    def predict_proba(self, X, weights=None, **kwargs):
282        """Predict probabilities for test data X.
283
284        Args:
285
286            X: {array-like}, shape = [n_samples, n_features]
287                Training vectors, where n_samples is the number
288                of samples and n_features is the number of features.
289
290            **kwargs: additional parameters to be passed to
291                    self.cook_test_set
292
293        Returns:
294
295            probability estimates for test data: {array-like}
296
297        """
298
299        def calculate_probas(voter, weights=None, verbose=None):
300            ensemble_proba = 0
301
302            n_iter = len(voter)
303
304            assert n_iter > 0, "no estimator found in `RandomBag` ensemble"
305
306            if weights is None:
307                for idx, elt in voter.items():
308                    try:
309                        ensemble_proba += elt.predict_proba(X)
310
311                        # if verbose == 1:
312                        #    pbar.update(idx)
313
314                    except:
315                        continue
316
317                # if verbose == 1:
318                #    pbar.update(n_iter)
319
320                return ensemble_proba / n_iter
321
322            # if weights is not None:
323            for idx, elt in voter.items():
324                ensemble_proba += weights[idx] * elt.predict_proba(X)
325
326                # if verbose == 1:
327                #    pbar.update(idx)
328
329            # if verbose == 1:
330            #    pbar.update(n_iter)
331
332            return ensemble_proba
333
334        # end calculate_probas ----
335
336        if self.n_jobs is None:
337            # if self.verbose == 1:
338            #    pbar = Progbar(self.n_estimators)
339
340            if weights is None:
341                return calculate_probas(self.voter_, verbose=self.verbose)
342
343            # if weights is not None:
344            self.weights = weights
345
346            return calculate_probas(self.voter_, weights, verbose=self.verbose)
347
348        # if self.n_jobs is not None:
349        def predict_estimator(m):
350            try:
351                return self.voter_[m].predict_proba(X)
352            except:
353                pass
354
355        if self.verbose == 1:
356            preds = Parallel(n_jobs=self.n_jobs, prefer="threads")(
357                delayed(predict_estimator)(m)
358                for m in tqdm(range(self.n_estimators))
359            )
360
361        else:
362            preds = Parallel(n_jobs=self.n_jobs, prefer="threads")(
363                delayed(predict_estimator)(m) for m in range(self.n_estimators)
364            )
365
366        ensemble_proba = 0
367
368        if weights is None:
369            for i in range(self.n_estimators):
370                ensemble_proba += preds[i]
371
372            return ensemble_proba / self.n_estimators
373
374        for i in range(self.n_estimators):
375            ensemble_proba += weights[i] * preds[i]
376
377        return ensemble_proba

Randomized 'Bagging' Classification model

Parameters:

obj: object
    any object containing a method fit (obj.fit()) and a method predict
    (obj.predict())

n_estimators: int
    number of boosting iterations

n_hidden_features: int
    number of nodes in the hidden layer

activation_name: str
    activation function: 'relu', 'tanh', 'sigmoid', 'prelu' or 'elu'

a: float
    hyperparameter for 'prelu' or 'elu' activation function

nodes_sim: str
    type of simulation for the nodes: 'sobol', 'hammersley', 'halton',
    'uniform'

bias: boolean
    indicates if the hidden layer contains a bias term (True) or not
    (False)

dropout: float
    regularization parameter; (random) percentage of nodes dropped out
    of the training

direct_link: boolean
    indicates if the original predictors are included (True) in model's
    fitting or not (False)

n_clusters: int
    number of clusters for 'kmeans' or 'gmm' clustering (could be 0:
        no clustering)

cluster_encode: bool
    defines how the variable containing clusters is treated (default is one-hot)
    if `False`, then labels are used, without one-hot encoding

type_clust: str
    type of clustering method: currently k-means ('kmeans') or Gaussian
    Mixture Model ('gmm')

type_scaling: a tuple of 3 strings
    scaling methods for inputs, hidden layer, and clustering respectively
    (and when relevant).
    Currently available: standardization ('std') or MinMax scaling ('minmax')

col_sample: float
    percentage of covariates randomly chosen for training

row_sample: float
    percentage of rows chosen for training, by stratified bootstrapping

seed: int
    reproducibility seed for nodes_sim=='uniform'

backend: str
    "cpu" or "gpu" or "tpu"

Attributes:

voter_: dict
    dictionary containing all the fitted base-learners

Examples:

See also https://github.com/Techtonique/nnetsauce/blob/master/examples/randombag_classification.py

import nnetsauce as ns
from sklearn.datasets import load_breast_cancer
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import train_test_split
from sklearn import metrics
from time import time


breast_cancer = load_breast_cancer()
Z = breast_cancer.data
t = breast_cancer.target
np.random.seed(123)
X_train, X_test, y_train, y_test = train_test_split(Z, t, test_size=0.2)

# decision tree
clf = DecisionTreeClassifier(max_depth=2, random_state=123)
fit_obj = ns.RandomBagClassifier(clf, n_hidden_features=2,
                                direct_link=True,
                                n_estimators=100,
                                col_sample=0.9, row_sample=0.9,
                                dropout=0.3, n_clusters=0, verbose=1)

start = time()
fit_obj.fit(X_train, y_train)
print(f"Elapsed {time() - start}")

print(fit_obj.score(X_test, y_test))
print(fit_obj.score(X_test, y_test, scoring="roc_auc"))

start = time()
preds = fit_obj.predict(X_test)
print(f"Elapsed {time() - start}")
print(metrics.classification_report(preds, y_test))
def fit(self, X, y, **kwargs):
181    def fit(self, X, y, **kwargs):
182        """Fit Random 'Bagging' model to training data (X, y).
183
184        Args:
185
186            X: {array-like}, shape = [n_samples, n_features]
187                Training vectors, where n_samples is the number
188                of samples and n_features is the number of features.
189
190            y: array-like, shape = [n_samples]
191                Target values.
192
193            **kwargs: additional parameters to be passed to
194                    self.cook_training_set or self.obj.fit
195
196        Returns:
197
198            self: object
199
200        """
201
202        assert mx.is_factor(y), "y must contain only integers"
203
204        self.n_classes_ = len(np.unique(y))  # for compatibility with sklearn
205
206        # training
207        self.n_classes = len(np.unique(y))
208
209        base_learner = CustomClassifier(
210            self.obj,
211            n_hidden_features=self.n_hidden_features,
212            activation_name=self.activation_name,
213            a=self.a,
214            nodes_sim=self.nodes_sim,
215            bias=self.bias,
216            dropout=self.dropout,
217            direct_link=self.direct_link,
218            n_clusters=self.n_clusters,
219            type_clust=self.type_clust,
220            type_scaling=self.type_scaling,
221            col_sample=self.col_sample,
222            row_sample=self.row_sample,
223            seed=self.seed,
224        )
225
226        # 1 - Sequential training -----
227
228        if self.n_jobs is None:
229            self.voter_ = rbagloop_classification(
230                base_learner, X, y, self.n_estimators, self.verbose, self.seed
231            )
232
233            self.n_estimators = len(self.voter_)
234
235            return self
236
237        # 2 - Parallel training -----
238        # buggy
239        # if self.n_jobs is not None:
240        def fit_estimators(m):
241            base_learner__ = deepcopy(base_learner)
242            base_learner__.set_params(seed=self.seed + m * 1000)
243            base_learner__.fit(X, y, **kwargs)
244            return base_learner__
245
246        if self.verbose == 1:
247            voters_list = Parallel(n_jobs=self.n_jobs, prefer="threads")(
248                delayed(fit_estimators)(m)
249                for m in tqdm(range(self.n_estimators))
250            )
251        else:
252            voters_list = Parallel(n_jobs=self.n_jobs, prefer="threads")(
253                delayed(fit_estimators)(m) for m in range(self.n_estimators)
254            )
255
256        self.voter_ = {idx: elt for idx, elt in enumerate(voters_list)}
257
258        self.n_estimators = len(self.voter_)
259        self.classes_ = np.unique(y)
260        return self

Fit Random 'Bagging' model to training data (X, y).

Args:

X: {array-like}, shape = [n_samples, n_features]
    Training vectors, where n_samples is the number
    of samples and n_features is the number of features.

y: array-like, shape = [n_samples]
    Target values.

**kwargs: additional parameters to be passed to
        self.cook_training_set or self.obj.fit

Returns:

self: object
def predict(self, X, weights=None, **kwargs):
262    def predict(self, X, weights=None, **kwargs):
263        """Predict test data X.
264
265        Args:
266
267            X: {array-like}, shape = [n_samples, n_features]
268                Training vectors, where n_samples is the number
269                of samples and n_features is the number of features.
270
271            **kwargs: additional parameters to be passed to
272                    self.cook_test_set
273
274        Returns:
275
276            model predictions: {array-like}
277
278        """
279        return self.predict_proba(X, weights, **kwargs).argmax(axis=1)

Predict test data X.

Args:

X: {array-like}, shape = [n_samples, n_features]
    Training vectors, where n_samples is the number
    of samples and n_features is the number of features.

**kwargs: additional parameters to be passed to
        self.cook_test_set

Returns:

model predictions: {array-like}
def predict_proba(self, X, weights=None, **kwargs):
281    def predict_proba(self, X, weights=None, **kwargs):
282        """Predict probabilities for test data X.
283
284        Args:
285
286            X: {array-like}, shape = [n_samples, n_features]
287                Training vectors, where n_samples is the number
288                of samples and n_features is the number of features.
289
290            **kwargs: additional parameters to be passed to
291                    self.cook_test_set
292
293        Returns:
294
295            probability estimates for test data: {array-like}
296
297        """
298
299        def calculate_probas(voter, weights=None, verbose=None):
300            ensemble_proba = 0
301
302            n_iter = len(voter)
303
304            assert n_iter > 0, "no estimator found in `RandomBag` ensemble"
305
306            if weights is None:
307                for idx, elt in voter.items():
308                    try:
309                        ensemble_proba += elt.predict_proba(X)
310
311                        # if verbose == 1:
312                        #    pbar.update(idx)
313
314                    except:
315                        continue
316
317                # if verbose == 1:
318                #    pbar.update(n_iter)
319
320                return ensemble_proba / n_iter
321
322            # if weights is not None:
323            for idx, elt in voter.items():
324                ensemble_proba += weights[idx] * elt.predict_proba(X)
325
326                # if verbose == 1:
327                #    pbar.update(idx)
328
329            # if verbose == 1:
330            #    pbar.update(n_iter)
331
332            return ensemble_proba
333
334        # end calculate_probas ----
335
336        if self.n_jobs is None:
337            # if self.verbose == 1:
338            #    pbar = Progbar(self.n_estimators)
339
340            if weights is None:
341                return calculate_probas(self.voter_, verbose=self.verbose)
342
343            # if weights is not None:
344            self.weights = weights
345
346            return calculate_probas(self.voter_, weights, verbose=self.verbose)
347
348        # if self.n_jobs is not None:
349        def predict_estimator(m):
350            try:
351                return self.voter_[m].predict_proba(X)
352            except:
353                pass
354
355        if self.verbose == 1:
356            preds = Parallel(n_jobs=self.n_jobs, prefer="threads")(
357                delayed(predict_estimator)(m)
358                for m in tqdm(range(self.n_estimators))
359            )
360
361        else:
362            preds = Parallel(n_jobs=self.n_jobs, prefer="threads")(
363                delayed(predict_estimator)(m) for m in range(self.n_estimators)
364            )
365
366        ensemble_proba = 0
367
368        if weights is None:
369            for i in range(self.n_estimators):
370                ensemble_proba += preds[i]
371
372            return ensemble_proba / self.n_estimators
373
374        for i in range(self.n_estimators):
375            ensemble_proba += weights[i] * preds[i]
376
377        return ensemble_proba

Predict probabilities for test data X.

Args:

X: {array-like}, shape = [n_samples, n_features]
    Training vectors, where n_samples is the number
    of samples and n_features is the number of features.

**kwargs: additional parameters to be passed to
        self.cook_test_set

Returns:

probability estimates for test data: {array-like}
class RegressorUpdater(sklearn.base.BaseEstimator, sklearn.base.RegressorMixin):
 16class RegressorUpdater(BaseEstimator, RegressorMixin):
 17    """
 18    Update a regression model with new observations
 19
 20    Parameters
 21    ----------
 22    regr: object
 23        A regression model with a coef_ attribute
 24    alpha: float
 25        Updating factor's exponent
 26
 27    Attributes
 28    ----------
 29    n_obs_: int
 30        Number of observations
 31    coef_: np.ndarray
 32        Coefficients of the model
 33    updating_factor_: float
 34        Updating factor
 35
 36    """
 37
 38    def __init__(self, regr, alpha=0.5):
 39        self.regr = regr
 40        self.alpha = alpha
 41        self.n_obs_ = None
 42        self.coef_ = None
 43        self.updating_factor_ = None
 44        try:
 45            self.coef_ = self.regr.coef_
 46            if isinstance(self.regr, Base):
 47                self.n_obs_ = self.regr.scaler_.n_samples_seen_
 48        except AttributeError:
 49            pass
 50
 51    def fit(self, X, y, **kwargs):
 52
 53        if isinstance(
 54            self.regr, CustomRegressor
 55        ):  # nnetsauce model not deep ---
 56            if check_is_fitted(self.regr) == False:
 57                self.regr.fit(X, y, **kwargs)
 58                self.n_obs_ = X.shape[0]
 59                if hasattr(self.regr, "coef_"):
 60                    self.coef_ = self.regr.coef_
 61                return self
 62            self.n_obs_ = self.regr.scaler_.n_samples_seen_
 63            if hasattr(self.regr, "coef_"):
 64                self.coef_ = self.regr.coef_
 65            return self
 66
 67        if (
 68            hasattr(self.regr, "coef_") == False
 69        ):  # sklearn model or CustomRegressor model ---
 70            self.regr.fit(X, y)
 71            self.n_obs_ = X.shape[0]
 72            self.regr.fit(X, y)
 73            if hasattr(self.regr, "stacked_obj"):
 74                self.coef_ = self.regr.stacked_obj.coef_
 75            else:
 76                self.coef_ = self.regr.coef_
 77            return self
 78        self.n_obs_ = X.shape[0]
 79        if hasattr(self.regr, "coef_"):
 80            self.coef_ = self.regr.coef_
 81        return self
 82
 83    def predict(self, X):
 84        # assert hasattr(self.regr, "coef_"), "model must have coef_ attribute"
 85        return self.regr.predict(X)
 86
 87    def partial_fit(self, X, y):
 88
 89        assert hasattr(
 90            self.regr, "coef_"
 91        ), "model must be fitted first (i.e have 'coef_' attribute)"
 92        assert (
 93            self.n_obs_ is not None
 94        ), "model must be fitted first (i.e have 'n_obs_' attribute)"
 95
 96        if len(X.shape) == 1:
 97            X = X.reshape(1, -1)
 98
 99        assert X.shape[0] == 1, "X must have one row"
100
101        self.updating_factor_ = self.n_obs_ ** (-self.alpha)
102
103        if isinstance(self.regr, Base):  # nnetsauce model ---
104
105            newX = deepcopy(X)
106
107            if isinstance(
108                self.regr, CustomRegressor
109            ):  # other nnetsauce model (CustomRegressor) ---
110                newX = self.regr.cook_test_set(X=X)
111                if isinstance(X, pd.DataFrame):
112                    newx = newX.values.ravel()
113                else:
114                    newx = newX.ravel()
115
116        else:  # an sklearn model ---
117
118            if isinstance(X, pd.DataFrame):
119                newx = X.values.ravel()
120            else:
121                newx = X.ravel()
122
123        new_coef = self.regr.coef_ + self.updating_factor_ * np.dot(
124            newx, y - np.dot(newx, self.regr.coef_)
125        )
126        self.regr.coef_ = _update_mean(self.regr.coef_, self.n_obs_, new_coef)
127        self.coef_ = deepcopy(self.regr.coef_)
128        self.n_obs_ += 1
129        return self

Update a regression model with new observations

Parameters

regr: object A regression model with a coef_ attribute alpha: float Updating factor's exponent

Attributes

n_obs_: int Number of observations coef_: np.ndarray Coefficients of the model updating_factor_: float Updating factor

def fit(self, X, y, **kwargs):
51    def fit(self, X, y, **kwargs):
52
53        if isinstance(
54            self.regr, CustomRegressor
55        ):  # nnetsauce model not deep ---
56            if check_is_fitted(self.regr) == False:
57                self.regr.fit(X, y, **kwargs)
58                self.n_obs_ = X.shape[0]
59                if hasattr(self.regr, "coef_"):
60                    self.coef_ = self.regr.coef_
61                return self
62            self.n_obs_ = self.regr.scaler_.n_samples_seen_
63            if hasattr(self.regr, "coef_"):
64                self.coef_ = self.regr.coef_
65            return self
66
67        if (
68            hasattr(self.regr, "coef_") == False
69        ):  # sklearn model or CustomRegressor model ---
70            self.regr.fit(X, y)
71            self.n_obs_ = X.shape[0]
72            self.regr.fit(X, y)
73            if hasattr(self.regr, "stacked_obj"):
74                self.coef_ = self.regr.stacked_obj.coef_
75            else:
76                self.coef_ = self.regr.coef_
77            return self
78        self.n_obs_ = X.shape[0]
79        if hasattr(self.regr, "coef_"):
80            self.coef_ = self.regr.coef_
81        return self
def predict(self, X):
83    def predict(self, X):
84        # assert hasattr(self.regr, "coef_"), "model must have coef_ attribute"
85        return self.regr.predict(X)
class ClassifierUpdater(sklearn.base.BaseEstimator, sklearn.base.ClassifierMixin):
 16class ClassifierUpdater(BaseEstimator, ClassifierMixin):
 17    """
 18    Update a regression model with new observations
 19
 20    Parameters
 21    ----------
 22    clf: object
 23        A regression model with a coef_ attribute
 24    alpha: float
 25        Updating factor's exponent
 26
 27    Attributes
 28    ----------
 29    n_obs_: int
 30        Number of observations
 31    coef_: np.ndarray
 32        Coefficients of the model
 33    updating_factor_: float
 34        Updating factor
 35
 36    """
 37
 38    def __init__(self, clf, alpha=0.5):
 39        self.clf = clf
 40        self.alpha = alpha
 41        self.n_obs_ = None
 42        self.coef_ = None
 43        self.updating_factor_ = None
 44        try:
 45            self.coef_ = self.clf.coef_
 46            if isinstance(self.clf, Base):
 47                self.n_obs_ = self.clf.scaler_.n_samples_seen_
 48        except AttributeError:
 49            pass
 50
 51    def fit(self, X, y, **kwargs):
 52
 53        raise NotImplementedError(
 54            "fit method is not implemented for ClassifierUpdater"
 55        )
 56
 57        if isinstance(
 58            self.clf, CustomClassifier
 59        ):  # nnetsauce model not deep ---
 60            if check_is_fitted(self.clf) == False:
 61                self.clf.fit(X, y, **kwargs)
 62                self.n_obs_ = X.shape[0]
 63                if hasattr(self.clf, "coef_"):
 64                    self.coef_ = self.clf.coef_
 65                return self
 66            self.n_obs_ = self.clf.scaler_.n_samples_seen_
 67            if hasattr(self.clf, "coef_"):
 68                self.coef_ = self.clf.coef_
 69            return self
 70
 71        if (
 72            hasattr(self.clf, "coef_") == False
 73        ):  # sklearn model or CustomClassifier model ---
 74            self.clf.fit(X, y)
 75            self.n_obs_ = X.shape[0]
 76            self.clf.fit(X, y)
 77            if hasattr(self.clf, "stacked_obj"):
 78                self.coef_ = self.clf.stacked_obj.coef_
 79            else:
 80                self.coef_ = self.clf.coef_
 81            return self
 82        self.n_obs_ = X.shape[0]
 83        if hasattr(self.clf, "coef_"):
 84            self.coef_ = self.clf.coef_
 85        return self
 86
 87    def predict(self, X):
 88
 89        raise NotImplementedError(
 90            "predict method is not implemented for ClassifierUpdater"
 91        )
 92        # assert hasattr(self.clf, "coef_"), "model must have coef_ attribute"
 93        return self.clf.predict(X)
 94
 95    def partial_fit(self, X, y):
 96
 97        raise NotImplementedError(
 98            "partial_fit method is not implemented for ClassifierUpdater"
 99        )
100
101        assert hasattr(
102            self.clf, "coef_"
103        ), "model must be fitted first (i.e have 'coef_' attribute)"
104        assert (
105            self.n_obs_ is not None
106        ), "model must be fitted first (i.e have 'n_obs_' attribute)"
107
108        if len(X.shape) == 1:
109            X = X.reshape(1, -1)
110
111        assert X.shape[0] == 1, "X must have one row"
112
113        self.updating_factor_ = self.n_obs_ ** (-self.alpha)
114
115        if isinstance(self.clf, Base):  # nnetsauce model ---
116
117            newX = deepcopy(X)
118
119            if isinstance(
120                self.clf, CustomClassifier
121            ):  # other nnetsauce model (CustomClassifier) ---
122                newX = self.clf.cook_test_set(X=X)
123                if isinstance(X, pd.DataFrame):
124                    newx = newX.values.ravel()
125                else:
126                    newx = newX.ravel()
127
128        else:  # an sklearn model ---
129
130            if isinstance(X, pd.DataFrame):
131                newx = X.values.ravel()
132            else:
133                newx = X.ravel()
134
135        new_coef = self.clf.coef_ + self.updating_factor_ * np.dot(
136            newx, y - np.dot(newx, self.clf.coef_)
137        )
138        self.clf.coef_ = _update_mean(self.clf.coef_, self.n_obs_, new_coef)
139        self.coef_ = deepcopy(self.clf.coef_)
140        self.n_obs_ += 1
141        return self

Update a regression model with new observations

Parameters

clf: object A regression model with a coef_ attribute alpha: float Updating factor's exponent

Attributes

n_obs_: int Number of observations coef_: np.ndarray Coefficients of the model updating_factor_: float Updating factor

def fit(self, X, y, **kwargs):
51    def fit(self, X, y, **kwargs):
52
53        raise NotImplementedError(
54            "fit method is not implemented for ClassifierUpdater"
55        )
56
57        if isinstance(
58            self.clf, CustomClassifier
59        ):  # nnetsauce model not deep ---
60            if check_is_fitted(self.clf) == False:
61                self.clf.fit(X, y, **kwargs)
62                self.n_obs_ = X.shape[0]
63                if hasattr(self.clf, "coef_"):
64                    self.coef_ = self.clf.coef_
65                return self
66            self.n_obs_ = self.clf.scaler_.n_samples_seen_
67            if hasattr(self.clf, "coef_"):
68                self.coef_ = self.clf.coef_
69            return self
70
71        if (
72            hasattr(self.clf, "coef_") == False
73        ):  # sklearn model or CustomClassifier model ---
74            self.clf.fit(X, y)
75            self.n_obs_ = X.shape[0]
76            self.clf.fit(X, y)
77            if hasattr(self.clf, "stacked_obj"):
78                self.coef_ = self.clf.stacked_obj.coef_
79            else:
80                self.coef_ = self.clf.coef_
81            return self
82        self.n_obs_ = X.shape[0]
83        if hasattr(self.clf, "coef_"):
84            self.coef_ = self.clf.coef_
85        return self
def predict(self, X):
87    def predict(self, X):
88
89        raise NotImplementedError(
90            "predict method is not implemented for ClassifierUpdater"
91        )
92        # assert hasattr(self.clf, "coef_"), "model must have coef_ attribute"
93        return self.clf.predict(X)
class Ridge2Regressor(nnetsauce.ridge2.ridge2.Ridge2, sklearn.base.RegressorMixin):
 23class Ridge2Regressor(Ridge2, RegressorMixin):
 24    """Ridge regression with 2 regularization parameters derived from class Ridge
 25
 26    Parameters:
 27
 28        n_hidden_features: int
 29            number of nodes in the hidden layer
 30
 31        activation_name: str
 32            activation function: 'relu', 'tanh', 'sigmoid', 'prelu' or 'elu'
 33
 34        a: float
 35            hyperparameter for 'prelu' or 'elu' activation function
 36
 37        nodes_sim: str
 38            type of simulation for the nodes: 'sobol', 'hammersley', 'halton',
 39            'uniform'
 40
 41        bias: boolean
 42            indicates if the hidden layer contains a bias term (True) or not
 43            (False)
 44
 45        dropout: float
 46            regularization parameter; (random) percentage of nodes dropped out
 47            of the training
 48
 49        n_clusters: int
 50            number of clusters for 'kmeans' or 'gmm' clustering (could be 0:
 51                no clustering)
 52
 53        cluster_encode: bool
 54            defines how the variable containing clusters is treated (default is one-hot)
 55            if `False`, then labels are used, without one-hot encoding
 56
 57        type_clust: str
 58            type of clustering method: currently k-means ('kmeans') or Gaussian
 59            Mixture Model ('gmm')
 60
 61        type_scaling: a tuple of 3 strings
 62            scaling methods for inputs, hidden layer, and clustering respectively
 63            (and when relevant).
 64            Currently available: standardization ('std') or MinMax scaling ('minmax')
 65
 66        lambda1: float
 67            regularization parameter on direct link
 68
 69        lambda2: float
 70            regularization parameter on hidden layer
 71
 72        seed: int
 73            reproducibility seed for nodes_sim=='uniform'
 74
 75        backend: str
 76            'cpu' or 'gpu' or 'tpu'
 77
 78    Attributes:
 79
 80        beta_: {array-like}
 81            regression coefficients
 82
 83        y_mean_: float
 84            average response
 85
 86    """
 87
 88    # construct the object -----
 89
 90    def __init__(
 91        self,
 92        n_hidden_features=5,
 93        activation_name="relu",
 94        a=0.01,
 95        nodes_sim="sobol",
 96        bias=True,
 97        dropout=0,
 98        n_clusters=2,
 99        cluster_encode=True,
100        type_clust="kmeans",
101        type_scaling=("std", "std", "std"),
102        lambda1=0.1,
103        lambda2=0.1,
104        seed=123,
105        backend="cpu",
106    ):
107        super().__init__(
108            n_hidden_features=n_hidden_features,
109            activation_name=activation_name,
110            a=a,
111            nodes_sim=nodes_sim,
112            bias=bias,
113            dropout=dropout,
114            n_clusters=n_clusters,
115            cluster_encode=cluster_encode,
116            type_clust=type_clust,
117            type_scaling=type_scaling,
118            lambda1=lambda1,
119            lambda2=lambda2,
120            seed=seed,
121            backend=backend,
122        )
123
124        self.type_fit = "regression"
125
126    def fit(self, X, y, **kwargs):
127        """Fit Ridge model to training data (X, y).
128
129        Args:
130
131            X: {array-like}, shape = [n_samples, n_features]
132                Training vectors, where n_samples is the number
133                of samples and n_features is the number of features.
134
135            y: array-like, shape = [n_samples]
136                Target values.
137
138            **kwargs: additional parameters to be passed to
139                    self.cook_training_set or self.obj.fit
140
141        Returns:
142
143            self: object
144
145        """
146
147        sys_platform = platform.system()
148
149        centered_y, scaled_Z = self.cook_training_set(y=y, X=X, **kwargs)
150
151        n_X, p_X = X.shape
152        n_Z, p_Z = scaled_Z.shape
153
154        if self.n_clusters > 0:
155            if self.encode_clusters == True:
156                n_features = p_X + self.n_clusters
157            else:
158                n_features = p_X + 1
159        else:
160            n_features = p_X
161
162        X_ = scaled_Z[:, 0:n_features]
163        Phi_X_ = scaled_Z[:, n_features:p_Z]
164
165        B = mo.crossprod(x=X_, backend=self.backend) + self.lambda1 * np.diag(
166            np.repeat(1, n_features)
167        )
168        C = mo.crossprod(x=Phi_X_, y=X_, backend=self.backend)
169        D = mo.crossprod(
170            x=Phi_X_, backend=self.backend
171        ) + self.lambda2 * np.diag(np.repeat(1, Phi_X_.shape[1]))
172
173        if sys_platform in ("Linux", "Darwin"):
174            B_inv = pinv(B) if self.backend == "cpu" else jpinv(B)
175        else:
176            B_inv = pinv(B)
177
178        W = mo.safe_sparse_dot(a=C, b=B_inv, backend=self.backend)
179        S_mat = D - mo.tcrossprod(x=W, y=C, backend=self.backend)
180
181        if sys_platform in ("Linux", "Darwin"):
182            S_inv = pinv(S_mat) if self.backend == "cpu" else jpinv(S_mat)
183        else:
184            S_inv = pinv(S_mat)
185
186        Y = mo.safe_sparse_dot(a=S_inv, b=W, backend=self.backend)
187        inv = mo.rbind(
188            mo.cbind(
189                x=B_inv + mo.crossprod(x=W, y=Y, backend=self.backend),
190                y=-np.transpose(Y),
191                backend=self.backend,
192            ),
193            mo.cbind(x=-Y, y=S_inv, backend=self.backend),
194            backend=self.backend,
195        )
196
197        self.beta_ = mo.safe_sparse_dot(
198            a=inv,
199            b=mo.crossprod(x=scaled_Z, y=centered_y, backend=self.backend),
200            backend=self.backend,
201        )
202
203        return self
204
205    def predict(self, X, **kwargs):
206        """Predict test data X.
207
208        Args:
209
210            X: {array-like}, shape = [n_samples, n_features]
211                Training vectors, where n_samples is the number
212                of samples and n_features is the number of features.
213
214            **kwargs: additional parameters to be passed to
215                    self.cook_test_set
216
217        Returns:
218
219            model predictions: {array-like}
220
221        """
222
223        if len(X.shape) == 1:
224            n_features = X.shape[0]
225            new_X = mo.rbind(
226                x=X.reshape(1, n_features),
227                y=np.ones(n_features).reshape(1, n_features),
228                backend=self.backend,
229            )
230
231            return (
232                self.y_mean_
233                + mo.safe_sparse_dot(
234                    a=self.cook_test_set(new_X, **kwargs),
235                    b=self.beta_,
236                    backend=self.backend,
237                )
238            )[0]
239
240        return self.y_mean_ + mo.safe_sparse_dot(
241            a=self.cook_test_set(X, **kwargs),
242            b=self.beta_,
243            backend=self.backend,
244        )

Ridge regression with 2 regularization parameters derived from class Ridge

Parameters:

n_hidden_features: int
    number of nodes in the hidden layer

activation_name: str
    activation function: 'relu', 'tanh', 'sigmoid', 'prelu' or 'elu'

a: float
    hyperparameter for 'prelu' or 'elu' activation function

nodes_sim: str
    type of simulation for the nodes: 'sobol', 'hammersley', 'halton',
    'uniform'

bias: boolean
    indicates if the hidden layer contains a bias term (True) or not
    (False)

dropout: float
    regularization parameter; (random) percentage of nodes dropped out
    of the training

n_clusters: int
    number of clusters for 'kmeans' or 'gmm' clustering (could be 0:
        no clustering)

cluster_encode: bool
    defines how the variable containing clusters is treated (default is one-hot)
    if `False`, then labels are used, without one-hot encoding

type_clust: str
    type of clustering method: currently k-means ('kmeans') or Gaussian
    Mixture Model ('gmm')

type_scaling: a tuple of 3 strings
    scaling methods for inputs, hidden layer, and clustering respectively
    (and when relevant).
    Currently available: standardization ('std') or MinMax scaling ('minmax')

lambda1: float
    regularization parameter on direct link

lambda2: float
    regularization parameter on hidden layer

seed: int
    reproducibility seed for nodes_sim=='uniform'

backend: str
    'cpu' or 'gpu' or 'tpu'

Attributes:

beta_: {array-like}
    regression coefficients

y_mean_: float
    average response
def fit(self, X, y, **kwargs):
126    def fit(self, X, y, **kwargs):
127        """Fit Ridge model to training data (X, y).
128
129        Args:
130
131            X: {array-like}, shape = [n_samples, n_features]
132                Training vectors, where n_samples is the number
133                of samples and n_features is the number of features.
134
135            y: array-like, shape = [n_samples]
136                Target values.
137
138            **kwargs: additional parameters to be passed to
139                    self.cook_training_set or self.obj.fit
140
141        Returns:
142
143            self: object
144
145        """
146
147        sys_platform = platform.system()
148
149        centered_y, scaled_Z = self.cook_training_set(y=y, X=X, **kwargs)
150
151        n_X, p_X = X.shape
152        n_Z, p_Z = scaled_Z.shape
153
154        if self.n_clusters > 0:
155            if self.encode_clusters == True:
156                n_features = p_X + self.n_clusters
157            else:
158                n_features = p_X + 1
159        else:
160            n_features = p_X
161
162        X_ = scaled_Z[:, 0:n_features]
163        Phi_X_ = scaled_Z[:, n_features:p_Z]
164
165        B = mo.crossprod(x=X_, backend=self.backend) + self.lambda1 * np.diag(
166            np.repeat(1, n_features)
167        )
168        C = mo.crossprod(x=Phi_X_, y=X_, backend=self.backend)
169        D = mo.crossprod(
170            x=Phi_X_, backend=self.backend
171        ) + self.lambda2 * np.diag(np.repeat(1, Phi_X_.shape[1]))
172
173        if sys_platform in ("Linux", "Darwin"):
174            B_inv = pinv(B) if self.backend == "cpu" else jpinv(B)
175        else:
176            B_inv = pinv(B)
177
178        W = mo.safe_sparse_dot(a=C, b=B_inv, backend=self.backend)
179        S_mat = D - mo.tcrossprod(x=W, y=C, backend=self.backend)
180
181        if sys_platform in ("Linux", "Darwin"):
182            S_inv = pinv(S_mat) if self.backend == "cpu" else jpinv(S_mat)
183        else:
184            S_inv = pinv(S_mat)
185
186        Y = mo.safe_sparse_dot(a=S_inv, b=W, backend=self.backend)
187        inv = mo.rbind(
188            mo.cbind(
189                x=B_inv + mo.crossprod(x=W, y=Y, backend=self.backend),
190                y=-np.transpose(Y),
191                backend=self.backend,
192            ),
193            mo.cbind(x=-Y, y=S_inv, backend=self.backend),
194            backend=self.backend,
195        )
196
197        self.beta_ = mo.safe_sparse_dot(
198            a=inv,
199            b=mo.crossprod(x=scaled_Z, y=centered_y, backend=self.backend),
200            backend=self.backend,
201        )
202
203        return self

Fit Ridge model to training data (X, y).

Args:

X: {array-like}, shape = [n_samples, n_features]
    Training vectors, where n_samples is the number
    of samples and n_features is the number of features.

y: array-like, shape = [n_samples]
    Target values.

**kwargs: additional parameters to be passed to
        self.cook_training_set or self.obj.fit

Returns:

self: object
def predict(self, X, **kwargs):
205    def predict(self, X, **kwargs):
206        """Predict test data X.
207
208        Args:
209
210            X: {array-like}, shape = [n_samples, n_features]
211                Training vectors, where n_samples is the number
212                of samples and n_features is the number of features.
213
214            **kwargs: additional parameters to be passed to
215                    self.cook_test_set
216
217        Returns:
218
219            model predictions: {array-like}
220
221        """
222
223        if len(X.shape) == 1:
224            n_features = X.shape[0]
225            new_X = mo.rbind(
226                x=X.reshape(1, n_features),
227                y=np.ones(n_features).reshape(1, n_features),
228                backend=self.backend,
229            )
230
231            return (
232                self.y_mean_
233                + mo.safe_sparse_dot(
234                    a=self.cook_test_set(new_X, **kwargs),
235                    b=self.beta_,
236                    backend=self.backend,
237                )
238            )[0]
239
240        return self.y_mean_ + mo.safe_sparse_dot(
241            a=self.cook_test_set(X, **kwargs),
242            b=self.beta_,
243            backend=self.backend,
244        )

Predict test data X.

Args:

X: {array-like}, shape = [n_samples, n_features]
    Training vectors, where n_samples is the number
    of samples and n_features is the number of features.

**kwargs: additional parameters to be passed to
        self.cook_test_set

Returns:

model predictions: {array-like}
class Ridge2Classifier(nnetsauce.ridge2.ridge2.Ridge2, sklearn.base.ClassifierMixin):
 18class Ridge2Classifier(Ridge2, ClassifierMixin):
 19    """Multinomial logit classification with 2 regularization parameters
 20
 21    Parameters:
 22
 23        n_hidden_features: int
 24            number of nodes in the hidden layer
 25
 26        activation_name: str
 27            activation function: 'relu', 'tanh', 'sigmoid', 'prelu' or 'elu'
 28
 29        a: float
 30            hyperparameter for 'prelu' or 'elu' activation function
 31
 32        nodes_sim: str
 33            type of simulation for the nodes: 'sobol', 'hammersley', 'halton',
 34            'uniform'
 35
 36        bias: boolean
 37            indicates if the hidden layer contains a bias term (True) or not
 38            (False)
 39
 40        dropout: float
 41            regularization parameter; (random) percentage of nodes dropped out
 42            of the training
 43
 44        direct_link: boolean
 45            indicates if the original predictors are included (True) in model's
 46            fitting or not (False)
 47
 48        n_clusters: int
 49            number of clusters for 'kmeans' or 'gmm' clustering (could be 0:
 50                no clustering)
 51
 52        cluster_encode: bool
 53            defines how the variable containing clusters is treated (default is one-hot)
 54            if `False`, then labels are used, without one-hot encoding
 55
 56        type_clust: str
 57            type of clustering method: currently k-means ('kmeans') or Gaussian
 58            Mixture Model ('gmm')
 59
 60        type_scaling: a tuple of 3 strings
 61            scaling methods for inputs, hidden layer, and clustering respectively
 62            (and when relevant).
 63            Currently available: standardization ('std') or MinMax scaling ('minmax')
 64
 65        lambda1: float
 66            regularization parameter on direct link
 67
 68        lambda2: float
 69            regularization parameter on hidden layer
 70
 71        solver: str
 72            optimization function "L-BFGS-B",  "Newton-CG",
 73            "trust-ncg", "L-BFGS-B-lstsq", "Newton-CG-lstsq",
 74            "trust-ncg-lstsq" (see scipy.optimize.minimize)
 75            When using "L-BFGS-B-lstsq", "Newton-CG-lstsq", or "trust-ncg-lstsq",
 76            the initial value for the optimization is set to the least squares solution
 77
 78        seed: int
 79            reproducibility seed for nodes_sim=='uniform'
 80
 81        backend: str
 82            "cpu" or "gpu" or "tpu"
 83
 84    Attributes:
 85
 86        beta_: {array-like}
 87            regression coefficients
 88
 89        classes_: {array-like}
 90            unique classes in the target variable
 91
 92        minloglik_: float
 93            minimum value of the negative log-likelihood
 94
 95    Examples:
 96
 97    See also [https://github.com/Techtonique/nnetsauce/blob/master/examples/ridge_classification.py](https://github.com/Techtonique/nnetsauce/blob/master/examples/ridge_classification.py)
 98
 99    ```python
100    import nnetsauce as ns
101    import numpy as np
102    from sklearn.datasets import load_breast_cancer
103    from sklearn.model_selection import train_test_split
104    from time import time
105
106
107    breast_cancer = load_breast_cancer()
108    X = breast_cancer.data
109    y = breast_cancer.target
110
111    # split data into training test and test set
112    np.random.seed(123)
113    X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)
114
115    # create the model with nnetsauce
116    fit_obj = ns.Ridge2Classifier(lambda1 = 6.90185578e+04,
117                                lambda2 = 3.17392781e+02,
118                                n_hidden_features=95,
119                                n_clusters=2,
120                                dropout = 3.62817383e-01,
121                                type_clust = "gmm")
122
123    # fit the model on training set
124    start = time()
125    fit_obj.fit(X_train, y_train)
126    print(f"Elapsed {time() - start}")
127
128    # get the accuracy on test set
129    start = time()
130    print(fit_obj.score(X_test, y_test))
131    print(f"Elapsed {time() - start}")
132
133    # get area under the curve on test set (auc)
134    print(fit_obj.score(X_test, y_test, scoring="roc_auc"))
135    ```
136
137
138    """
139
140    # construct the object -----
141
142    def __init__(
143        self,
144        n_hidden_features=5,
145        activation_name="relu",
146        a=0.01,
147        nodes_sim="sobol",
148        bias=True,
149        dropout=0,
150        direct_link=True,
151        n_clusters=2,
152        cluster_encode=True,
153        type_clust="kmeans",
154        type_scaling=("std", "std", "std"),
155        lambda1=0.1,
156        lambda2=0.1,
157        solver="L-BFGS-B",
158        seed=123,
159        backend="cpu",
160    ):
161        super().__init__(
162            n_hidden_features=n_hidden_features,
163            activation_name=activation_name,
164            a=a,
165            nodes_sim=nodes_sim,
166            bias=bias,
167            dropout=dropout,
168            direct_link=direct_link,
169            n_clusters=n_clusters,
170            cluster_encode=cluster_encode,
171            type_clust=type_clust,
172            type_scaling=type_scaling,
173            lambda1=lambda1,
174            lambda2=lambda2,
175            seed=seed,
176            backend=backend,
177        )
178
179        self.type_fit = "classification"
180        self.solver = solver
181        self.beta_ = None
182        self.classes_ = None
183        self.minloglik_ = None
184
185    def loglik(self, X, Y, **kwargs):
186        """Log-likelihood for training data (X, Y).
187
188        Args:
189
190            X: {array-like}, shape = [n_samples, n_features]
191                Training vectors, where n_samples is the number
192                of samples and n_features is the number of features.
193
194            Y: array-like, shape = [n_samples]
195                One-hot encode target values.
196
197            **kwargs: additional parameters to be passed to
198                    self.cook_training_set or self.obj.fit
199
200        Returns:
201
202        """
203
204        def loglik_grad_hess(Y, X, B, XB, hessian=True, **kwargs):
205            # nobs, n_classes
206            n, K = Y.shape
207
208            # total number of covariates
209            p = X.shape[1]
210
211            # initial number of covariates
212            init_p = p - self.n_hidden_features
213
214            max_double = 709.0
215            XB[XB > max_double] = max_double
216            exp_XB = np.exp(XB)
217            probs = exp_XB / exp_XB.sum(axis=1)[:, None]
218
219            # gradient -----
220            # (Y - p) -> (n, K)
221            # X -> (n, p)
222            # (K, n) %*% (n, p) -> (K, p)
223            if hessian is False:
224                grad = (
225                    -mo.safe_sparse_dot(
226                        a=(Y - probs).T, b=X, backend=self.backend
227                    )
228                    / n
229                )
230                grad += self.lambda1 * B[0:init_p, :].sum(axis=0)[:, None]
231                grad += self.lambda2 * B[init_p:p, :].sum(axis=0)[:, None]
232
233                return grad.flatten()
234
235            # hessian -----
236            if hessian is True:
237                Kp = K * p
238                hess = np.zeros((Kp, Kp), float)
239                for k1 in range(K):
240                    x_index = range(k1 * p, (k1 + 1) * p)
241                    for k2 in range(k1, K):
242                        y_index = range(k2 * p, (k2 + 1) * p)
243                        H_sub = (
244                            -mo.safe_sparse_dot(
245                                a=X.T,
246                                b=(probs[:, k1] * probs[:, k2])[:, None] * X,
247                                backend=self.backend,
248                            )
249                            / n
250                        )  # do not store
251                        hess[np.ix_(x_index, y_index)] = hess[
252                            np.ix_(y_index, x_index)
253                        ] = H_sub
254
255                return hess + (self.lambda1 + self.lambda2) * np.identity(Kp)
256
257        # total number of covariates
258        p = X.shape[1]
259
260        # initial number of covariates
261        init_p = p - self.n_hidden_features
262
263        # log-likelihood (1st return)
264        def loglik_func(x):
265            # (p, K)
266            B = x.reshape(Y.shape[1], p).T
267
268            # (n, K)
269            XB = mo.safe_sparse_dot(X, B, backend=self.backend)
270
271            res = -(np.sum(Y * XB, axis=1) - logsumexp(XB)).mean()
272
273            res += (
274                0.5
275                * self.lambda1
276                * mo.squared_norm(B[0:init_p, :], backend=self.backend)
277            )
278            res += (
279                0.5
280                * self.lambda2
281                * mo.squared_norm(B[init_p:p, :], backend=self.backend)
282            )
283
284            return res
285
286        # gradient of log-likelihood
287        def grad_func(x):
288            # (p, K)
289            B = x.reshape(Y.shape[1], p).T
290
291            return loglik_grad_hess(
292                Y=Y,
293                X=X,
294                B=B,
295                XB=mo.safe_sparse_dot(X, B, backend=self.backend),
296                hessian=False,
297                **kwargs
298            )
299
300        # hessian of log-likelihood
301        def hessian_func(x):
302            # (p, K)
303            B = x.reshape(Y.shape[1], p).T
304
305            return loglik_grad_hess(
306                Y=Y,
307                X=X,
308                B=B,
309                XB=mo.safe_sparse_dot(X, B, backend=self.backend),
310                hessian=True,
311                **kwargs
312            )
313
314        return loglik_func, grad_func, hessian_func
315
316    # newton-cg
317    # L-BFGS-B
318    def fit(self, X, y, **kwargs):
319        """Fit Ridge model to training data (X, y).
320
321        for beta: regression coeffs (beta11, ..., beta1p, ..., betaK1, ..., betaKp)
322        for K classes and p covariates.
323
324        Args:
325
326            X: {array-like}, shape = [n_samples, n_features]
327                Training vectors, where n_samples is the number
328                of samples and n_features is the number of features.
329
330            y: array-like, shape = [n_samples]
331                Target values.
332
333            **kwargs: additional parameters to be passed to
334                    self.cook_training_set or self.obj.fit
335
336        Returns:
337
338            self: object
339
340        """
341
342        assert mx.is_factor(y), "y must contain only integers"
343
344        output_y, scaled_Z = self.cook_training_set(y=y, X=X, **kwargs)
345
346        self.n_classes = len(np.unique(y))
347        self.classes_ = np.unique(y)  # for compatibility with sklearn
348        self.n_classes_ = len(self.classes_)  # for compatibility with sklearn
349
350        Y = mo.one_hot_encode2(output_y, self.n_classes)
351
352        # optimize for beta, minimize self.loglik (maximize loglik) -----
353        loglik_func, grad_func, hessian_func = self.loglik(X=scaled_Z, Y=Y)
354
355        if self.solver == "L-BFGS-B":
356            opt = minimize(
357                fun=loglik_func,
358                x0=np.zeros(scaled_Z.shape[1] * self.n_classes),
359                jac=grad_func,
360                method=self.solver,
361            )
362            self.beta_ = opt.x
363            self.minloglik_ = opt.fun
364
365        if self.solver in ("Newton-CG", "trust-ncg"):
366            opt = minimize(
367                fun=loglik_func,
368                x0=np.zeros(scaled_Z.shape[1] * self.n_classes),
369                jac=grad_func,
370                hess=hessian_func,
371                method=self.solver,
372            )
373            self.beta_ = opt.x
374            self.minloglik_ = opt.fun
375
376        if self.solver == "L-BFGS-B-lstsq":
377            opt = minimize(
378                fun=loglik_func,
379                x0=np.linalg.lstsq(scaled_Z, Y, rcond=None)[0].flatten(
380                    order="F"
381                ),
382                jac=grad_func,
383                method="L-BFGS-B",
384            )
385            self.beta_ = opt.x
386            self.minloglik_ = opt.fun
387
388        if self.solver in "Newton-CG-lstsq":
389            opt = minimize(
390                fun=loglik_func,
391                x0=np.linalg.lstsq(scaled_Z, Y, rcond=None)[0].flatten(
392                    order="F"
393                ),
394                jac=grad_func,
395                hess=hessian_func,
396                method="Newton-CG",
397            )
398            self.beta_ = opt.x
399            self.minloglik_ = opt.fun
400
401        if self.solver in "trust-ncg-lstsq":
402            opt = minimize(
403                fun=loglik_func,
404                x0=np.linalg.lstsq(scaled_Z, Y, rcond=None)[0].flatten(
405                    order="F"
406                ),
407                jac=grad_func,
408                hess=hessian_func,
409                method="trust-ncg",
410            )
411            self.beta_ = opt.x
412            self.minloglik_ = opt.fun
413
414        self.classes_ = np.unique(y)
415
416        return self
417
418    def predict(self, X, **kwargs):
419        """Predict test data X.
420
421        Args:
422
423            X: {array-like}, shape = [n_samples, n_features]
424                Training vectors, where n_samples is the number
425                of samples and n_features is the number of features.
426
427            **kwargs: additional parameters to be passed to
428                    self.cook_test_set
429
430        Returns:
431
432            model predictions: {array-like}
433        """
434
435        return np.argmax(self.predict_proba(X, **kwargs), axis=1)
436
437    def predict_proba(self, X, **kwargs):
438        """Predict probabilities for test data X.
439
440        Args:
441
442            X: {array-like}, shape = [n_samples, n_features]
443                Training vectors, where n_samples is the number
444                of samples and n_features is the number of features.
445
446            **kwargs: additional parameters to be passed to
447                    self.cook_test_set
448
449        Returns:
450
451            probability estimates for test data: {array-like}
452
453        """
454        if len(X.shape) == 1:
455            n_features = X.shape[0]
456            new_X = mo.rbind(
457                X.reshape(1, n_features),
458                np.ones(n_features).reshape(1, n_features),
459            )
460
461            Z = self.cook_test_set(new_X, **kwargs)
462
463        else:
464            Z = self.cook_test_set(X, **kwargs)
465
466        ZB = mo.safe_sparse_dot(
467            a=Z,
468            b=self.beta_.reshape(
469                self.n_classes,
470                X.shape[1] + self.n_hidden_features + self.n_clusters,
471            ).T,
472            backend=self.backend,
473        )
474
475        exp_ZB = np.exp(ZB)
476
477        return exp_ZB / exp_ZB.sum(axis=1)[:, None]

Multinomial logit classification with 2 regularization parameters

Parameters:

n_hidden_features: int
    number of nodes in the hidden layer

activation_name: str
    activation function: 'relu', 'tanh', 'sigmoid', 'prelu' or 'elu'

a: float
    hyperparameter for 'prelu' or 'elu' activation function

nodes_sim: str
    type of simulation for the nodes: 'sobol', 'hammersley', 'halton',
    'uniform'

bias: boolean
    indicates if the hidden layer contains a bias term (True) or not
    (False)

dropout: float
    regularization parameter; (random) percentage of nodes dropped out
    of the training

direct_link: boolean
    indicates if the original predictors are included (True) in model's
    fitting or not (False)

n_clusters: int
    number of clusters for 'kmeans' or 'gmm' clustering (could be 0:
        no clustering)

cluster_encode: bool
    defines how the variable containing clusters is treated (default is one-hot)
    if `False`, then labels are used, without one-hot encoding

type_clust: str
    type of clustering method: currently k-means ('kmeans') or Gaussian
    Mixture Model ('gmm')

type_scaling: a tuple of 3 strings
    scaling methods for inputs, hidden layer, and clustering respectively
    (and when relevant).
    Currently available: standardization ('std') or MinMax scaling ('minmax')

lambda1: float
    regularization parameter on direct link

lambda2: float
    regularization parameter on hidden layer

solver: str
    optimization function "L-BFGS-B",  "Newton-CG",
    "trust-ncg", "L-BFGS-B-lstsq", "Newton-CG-lstsq",
    "trust-ncg-lstsq" (see scipy.optimize.minimize)
    When using "L-BFGS-B-lstsq", "Newton-CG-lstsq", or "trust-ncg-lstsq",
    the initial value for the optimization is set to the least squares solution

seed: int
    reproducibility seed for nodes_sim=='uniform'

backend: str
    "cpu" or "gpu" or "tpu"

Attributes:

beta_: {array-like}
    regression coefficients

classes_: {array-like}
    unique classes in the target variable

minloglik_: float
    minimum value of the negative log-likelihood

Examples:

See also https://github.com/Techtonique/nnetsauce/blob/master/examples/ridge_classification.py

import nnetsauce as ns
import numpy as np
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
from time import time


breast_cancer = load_breast_cancer()
X = breast_cancer.data
y = breast_cancer.target

# split data into training test and test set
np.random.seed(123)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)

# create the model with nnetsauce
fit_obj = ns.Ridge2Classifier(lambda1 = 6.90185578e+04,
                            lambda2 = 3.17392781e+02,
                            n_hidden_features=95,
                            n_clusters=2,
                            dropout = 3.62817383e-01,
                            type_clust = "gmm")

# fit the model on training set
start = time()
fit_obj.fit(X_train, y_train)
print(f"Elapsed {time() - start}")

# get the accuracy on test set
start = time()
print(fit_obj.score(X_test, y_test))
print(f"Elapsed {time() - start}")

# get area under the curve on test set (auc)
print(fit_obj.score(X_test, y_test, scoring="roc_auc"))
def fit(self, X, y, **kwargs):
318    def fit(self, X, y, **kwargs):
319        """Fit Ridge model to training data (X, y).
320
321        for beta: regression coeffs (beta11, ..., beta1p, ..., betaK1, ..., betaKp)
322        for K classes and p covariates.
323
324        Args:
325
326            X: {array-like}, shape = [n_samples, n_features]
327                Training vectors, where n_samples is the number
328                of samples and n_features is the number of features.
329
330            y: array-like, shape = [n_samples]
331                Target values.
332
333            **kwargs: additional parameters to be passed to
334                    self.cook_training_set or self.obj.fit
335
336        Returns:
337
338            self: object
339
340        """
341
342        assert mx.is_factor(y), "y must contain only integers"
343
344        output_y, scaled_Z = self.cook_training_set(y=y, X=X, **kwargs)
345
346        self.n_classes = len(np.unique(y))
347        self.classes_ = np.unique(y)  # for compatibility with sklearn
348        self.n_classes_ = len(self.classes_)  # for compatibility with sklearn
349
350        Y = mo.one_hot_encode2(output_y, self.n_classes)
351
352        # optimize for beta, minimize self.loglik (maximize loglik) -----
353        loglik_func, grad_func, hessian_func = self.loglik(X=scaled_Z, Y=Y)
354
355        if self.solver == "L-BFGS-B":
356            opt = minimize(
357                fun=loglik_func,
358                x0=np.zeros(scaled_Z.shape[1] * self.n_classes),
359                jac=grad_func,
360                method=self.solver,
361            )
362            self.beta_ = opt.x
363            self.minloglik_ = opt.fun
364
365        if self.solver in ("Newton-CG", "trust-ncg"):
366            opt = minimize(
367                fun=loglik_func,
368                x0=np.zeros(scaled_Z.shape[1] * self.n_classes),
369                jac=grad_func,
370                hess=hessian_func,
371                method=self.solver,
372            )
373            self.beta_ = opt.x
374            self.minloglik_ = opt.fun
375
376        if self.solver == "L-BFGS-B-lstsq":
377            opt = minimize(
378                fun=loglik_func,
379                x0=np.linalg.lstsq(scaled_Z, Y, rcond=None)[0].flatten(
380                    order="F"
381                ),
382                jac=grad_func,
383                method="L-BFGS-B",
384            )
385            self.beta_ = opt.x
386            self.minloglik_ = opt.fun
387
388        if self.solver in "Newton-CG-lstsq":
389            opt = minimize(
390                fun=loglik_func,
391                x0=np.linalg.lstsq(scaled_Z, Y, rcond=None)[0].flatten(
392                    order="F"
393                ),
394                jac=grad_func,
395                hess=hessian_func,
396                method="Newton-CG",
397            )
398            self.beta_ = opt.x
399            self.minloglik_ = opt.fun
400
401        if self.solver in "trust-ncg-lstsq":
402            opt = minimize(
403                fun=loglik_func,
404                x0=np.linalg.lstsq(scaled_Z, Y, rcond=None)[0].flatten(
405                    order="F"
406                ),
407                jac=grad_func,
408                hess=hessian_func,
409                method="trust-ncg",
410            )
411            self.beta_ = opt.x
412            self.minloglik_ = opt.fun
413
414        self.classes_ = np.unique(y)
415
416        return self

Fit Ridge model to training data (X, y).

for beta: regression coeffs (beta11, ..., beta1p, ..., betaK1, ..., betaKp) for K classes and p covariates.

Args:

X: {array-like}, shape = [n_samples, n_features]
    Training vectors, where n_samples is the number
    of samples and n_features is the number of features.

y: array-like, shape = [n_samples]
    Target values.

**kwargs: additional parameters to be passed to
        self.cook_training_set or self.obj.fit

Returns:

self: object
def predict(self, X, **kwargs):
418    def predict(self, X, **kwargs):
419        """Predict test data X.
420
421        Args:
422
423            X: {array-like}, shape = [n_samples, n_features]
424                Training vectors, where n_samples is the number
425                of samples and n_features is the number of features.
426
427            **kwargs: additional parameters to be passed to
428                    self.cook_test_set
429
430        Returns:
431
432            model predictions: {array-like}
433        """
434
435        return np.argmax(self.predict_proba(X, **kwargs), axis=1)

Predict test data X.

Args:

X: {array-like}, shape = [n_samples, n_features]
    Training vectors, where n_samples is the number
    of samples and n_features is the number of features.

**kwargs: additional parameters to be passed to
        self.cook_test_set

Returns:

model predictions: {array-like}
def predict_proba(self, X, **kwargs):
437    def predict_proba(self, X, **kwargs):
438        """Predict probabilities for test data X.
439
440        Args:
441
442            X: {array-like}, shape = [n_samples, n_features]
443                Training vectors, where n_samples is the number
444                of samples and n_features is the number of features.
445
446            **kwargs: additional parameters to be passed to
447                    self.cook_test_set
448
449        Returns:
450
451            probability estimates for test data: {array-like}
452
453        """
454        if len(X.shape) == 1:
455            n_features = X.shape[0]
456            new_X = mo.rbind(
457                X.reshape(1, n_features),
458                np.ones(n_features).reshape(1, n_features),
459            )
460
461            Z = self.cook_test_set(new_X, **kwargs)
462
463        else:
464            Z = self.cook_test_set(X, **kwargs)
465
466        ZB = mo.safe_sparse_dot(
467            a=Z,
468            b=self.beta_.reshape(
469                self.n_classes,
470                X.shape[1] + self.n_hidden_features + self.n_clusters,
471            ).T,
472            backend=self.backend,
473        )
474
475        exp_ZB = np.exp(ZB)
476
477        return exp_ZB / exp_ZB.sum(axis=1)[:, None]

Predict probabilities for test data X.

Args:

X: {array-like}, shape = [n_samples, n_features]
    Training vectors, where n_samples is the number
    of samples and n_features is the number of features.

**kwargs: additional parameters to be passed to
        self.cook_test_set

Returns:

probability estimates for test data: {array-like}
class Ridge2MultitaskClassifier(nnetsauce.ridge2.ridge2.Ridge2, sklearn.base.ClassifierMixin):
 23class Ridge2MultitaskClassifier(Ridge2, ClassifierMixin):
 24    """Multitask Ridge classification with 2 regularization parameters
 25
 26    Parameters:
 27
 28        n_hidden_features: int
 29            number of nodes in the hidden layer
 30
 31        activation_name: str
 32            activation function: 'relu', 'tanh', 'sigmoid', 'prelu' or 'elu'
 33
 34        a: float
 35            hyperparameter for 'prelu' or 'elu' activation function
 36
 37        nodes_sim: str
 38            type of simulation for the nodes: 'sobol', 'hammersley', 'halton',
 39            'uniform'
 40
 41        bias: boolean
 42            indicates if the hidden layer contains a bias term (True) or not
 43            (False)
 44
 45        dropout: float
 46            regularization parameter; (random) percentage of nodes dropped out
 47            of the training
 48
 49        n_clusters: int
 50            number of clusters for 'kmeans' or 'gmm' clustering (could be 0:
 51                no clustering)
 52
 53        cluster_encode: bool
 54            defines how the variable containing clusters is treated (default is one-hot)
 55            if `False`, then labels are used, without one-hot encoding
 56
 57        type_clust: str
 58            type of clustering method: currently k-means ('kmeans') or Gaussian
 59            Mixture Model ('gmm')
 60
 61        type_scaling: a tuple of 3 strings
 62            scaling methods for inputs, hidden layer, and clustering respectively
 63            (and when relevant).
 64            Currently available: standardization ('std') or MinMax scaling ('minmax')
 65
 66        lambda1: float
 67            regularization parameter on direct link
 68
 69        lambda2: float
 70            regularization parameter on hidden layer
 71
 72        seed: int
 73            reproducibility seed for nodes_sim=='uniform'
 74
 75        backend: str
 76            "cpu" or "gpu" or "tpu"
 77
 78    Attributes:
 79
 80        beta_: {array-like}
 81            regression coefficients
 82
 83    Examples:
 84
 85    See also [https://github.com/Techtonique/nnetsauce/blob/master/examples/ridgemtask_classification.py](https://github.com/Techtonique/nnetsauce/blob/master/examples/ridgemtask_classification.py)
 86
 87    ```python
 88    import nnetsauce as ns
 89    import numpy as np
 90    from sklearn.datasets import load_breast_cancer
 91    from sklearn.model_selection import train_test_split
 92    from sklearn import metrics
 93    from time import time
 94
 95    breast_cancer = load_breast_cancer()
 96    Z = breast_cancer.data
 97    t = breast_cancer.target
 98    np.random.seed(123)
 99    X_train, X_test, y_train, y_test = train_test_split(Z, t, test_size=0.2)
100
101    fit_obj = ns.Ridge2MultitaskClassifier(n_hidden_features=int(9.83730469e+01),
102                                    dropout=4.31054687e-01,
103                                    n_clusters=int(1.71484375e+00),
104                                    lambda1=1.24023438e+01, lambda2=7.30263672e+03)
105
106    start = time()
107    fit_obj.fit(X_train, y_train)
108    print(f"Elapsed {time() - start}")
109
110    print(fit_obj.score(X_test, y_test))
111    print(fit_obj.score(X_test, y_test, scoring="roc_auc"))
112
113    start = time()
114    preds = fit_obj.predict(X_test)
115    print(f"Elapsed {time() - start}")
116    print(metrics.classification_report(preds, y_test))
117    ```
118
119    """
120
121    # construct the object -----
122
123    def __init__(
124        self,
125        n_hidden_features=5,
126        activation_name="relu",
127        a=0.01,
128        nodes_sim="sobol",
129        bias=True,
130        dropout=0,
131        n_clusters=2,
132        cluster_encode=True,
133        type_clust="kmeans",
134        type_scaling=("std", "std", "std"),
135        lambda1=0.1,
136        lambda2=0.1,
137        seed=123,
138        backend="cpu",
139    ):
140        super().__init__(
141            n_hidden_features=n_hidden_features,
142            activation_name=activation_name,
143            a=a,
144            nodes_sim=nodes_sim,
145            bias=bias,
146            dropout=dropout,
147            n_clusters=n_clusters,
148            cluster_encode=cluster_encode,
149            type_clust=type_clust,
150            type_scaling=type_scaling,
151            lambda1=lambda1,
152            lambda2=lambda2,
153            seed=seed,
154            backend=backend,
155        )
156
157        self.type_fit = "classification"
158
159    def fit(self, X, y, **kwargs):
160        """Fit Ridge model to training data (X, y).
161
162        Args:
163
164            X: {array-like}, shape = [n_samples, n_features]
165                Training vectors, where n_samples is the number
166                of samples and n_features is the number of features.
167
168            y: array-like, shape = [n_samples]
169                Target values.
170
171            **kwargs: additional parameters to be passed to
172                    self.cook_training_set or self.obj.fit
173
174        Returns:
175
176            self: object
177
178        """
179
180        sys_platform = platform.system()
181
182        assert mx.is_factor(y), "y must contain only integers"
183
184        self.classes_ = np.unique(y)  # for compatibility with sklearn
185        self.n_classes_ = len(self.classes_)  # for compatibility with sklearn
186
187        output_y, scaled_Z = self.cook_training_set(y=y, X=X, **kwargs)
188
189        n_X, p_X = X.shape
190        n_Z, p_Z = scaled_Z.shape
191
192        self.n_classes = len(np.unique(y))
193
194        # multitask response
195        Y = mo.one_hot_encode2(output_y, self.n_classes)
196
197        if self.n_clusters > 0:
198            if self.encode_clusters == True:
199                n_features = p_X + self.n_clusters
200            else:
201                n_features = p_X + 1
202        else:
203            n_features = p_X
204
205        X_ = scaled_Z[:, 0:n_features]
206        Phi_X_ = scaled_Z[:, n_features:p_Z]
207
208        B = mo.crossprod(x=X_, backend=self.backend) + self.lambda1 * np.diag(
209            np.repeat(1, X_.shape[1])
210        )
211        C = mo.crossprod(x=Phi_X_, y=X_, backend=self.backend)
212        D = mo.crossprod(
213            x=Phi_X_, backend=self.backend
214        ) + self.lambda2 * np.diag(np.repeat(1, Phi_X_.shape[1]))
215
216        if sys_platform in ("Linux", "Darwin"):
217            B_inv = pinv(B) if self.backend == "cpu" else jpinv(B)
218        else:
219            B_inv = pinv(B)
220
221        W = mo.safe_sparse_dot(a=C, b=B_inv, backend=self.backend)
222        S_mat = D - mo.tcrossprod(x=W, y=C, backend=self.backend)
223
224        if sys_platform in ("Linux", "Darwin"):
225            S_inv = pinv(S_mat) if self.backend == "cpu" else jpinv(S_mat)
226        else:
227            S_inv = pinv(S_mat)
228
229        Y2 = mo.safe_sparse_dot(a=S_inv, b=W, backend=self.backend)
230        inv = mo.rbind(
231            mo.cbind(
232                x=B_inv + mo.crossprod(x=W, y=Y2, backend=self.backend),
233                y=-np.transpose(Y2),
234                backend=self.backend,
235            ),
236            mo.cbind(x=-Y2, y=S_inv, backend=self.backend),
237            backend=self.backend,
238        )
239
240        self.beta_ = mo.safe_sparse_dot(
241            a=inv,
242            b=mo.crossprod(x=scaled_Z, y=Y, backend=self.backend),
243            backend=self.backend,
244        )
245        self.classes_ = np.unique(y)
246        return self
247
248    def predict(self, X, **kwargs):
249        """Predict test data X.
250
251        Args:
252
253            X: {array-like}, shape = [n_samples, n_features]
254                Training vectors, where n_samples is the number
255                of samples and n_features is the number of features.
256
257            **kwargs: additional parameters to be passed to
258                    self.cook_test_set
259
260        Returns:
261
262            model predictions: {array-like}
263
264        """
265
266        return np.argmax(self.predict_proba(X, **kwargs), axis=1)
267
268    def predict_proba(self, X, **kwargs):
269        """Predict probabilities for test data X.
270
271        Args:
272
273            X: {array-like}, shape = [n_samples, n_features]
274                Training vectors, where n_samples is the number
275                of samples and n_features is the number of features.
276
277            **kwargs: additional parameters to be passed to
278                    self.cook_test_set
279
280        Returns:
281
282            probability estimates for test data: {array-like}
283
284        """
285
286        if len(X.shape) == 1:
287            n_features = X.shape[0]
288            new_X = mo.rbind(
289                x=X.reshape(1, n_features),
290                y=np.ones(n_features).reshape(1, n_features),
291                backend=self.backend,
292            )
293
294            Z = self.cook_test_set(new_X, **kwargs)
295
296        else:
297            Z = self.cook_test_set(X, **kwargs)
298
299        ZB = mo.safe_sparse_dot(a=Z, b=self.beta_, backend=self.backend)
300
301        exp_ZB = np.exp(ZB)
302
303        return exp_ZB / exp_ZB.sum(axis=1)[:, None]
304
305    def score(self, X, y, scoring=None):
306        """Scoring function for classification.
307
308        Args:
309
310            X: {array-like}, shape = [n_samples, n_features]
311                Training vectors, where n_samples is the number
312                of samples and n_features is the number of features.
313
314            y: array-like, shape = [n_samples]
315                Target values.
316
317            scoring: str
318                scoring method (default is accuracy)
319
320        Returns:
321
322            score: float
323        """
324
325        if scoring is None:
326            scoring = "accuracy"
327
328        if scoring == "accuracy":
329            return skm2.accuracy_score(y, self.predict(X))
330
331        if scoring == "f1":
332            return skm2.f1_score(y, self.predict(X))
333
334        if scoring == "precision":
335            return skm2.precision_score(y, self.predict(X))
336
337        if scoring == "recall":
338            return skm2.recall_score(y, self.predict(X))
339
340        if scoring == "roc_auc":
341            return skm2.roc_auc_score(y, self.predict(X))
342
343        if scoring == "log_loss":
344            return skm2.log_loss(y, self.predict_proba(X))
345
346        if scoring == "balanced_accuracy":
347            return skm2.balanced_accuracy_score(y, self.predict(X))
348
349        if scoring == "average_precision":
350            return skm2.average_precision_score(y, self.predict(X))
351
352        if scoring == "neg_brier_score":
353            return -skm2.brier_score_loss(y, self.predict_proba(X))
354
355        if scoring == "neg_log_loss":
356            return -skm2.log_loss(y, self.predict_proba(X))

Multitask Ridge classification with 2 regularization parameters

Parameters:

n_hidden_features: int
    number of nodes in the hidden layer

activation_name: str
    activation function: 'relu', 'tanh', 'sigmoid', 'prelu' or 'elu'

a: float
    hyperparameter for 'prelu' or 'elu' activation function

nodes_sim: str
    type of simulation for the nodes: 'sobol', 'hammersley', 'halton',
    'uniform'

bias: boolean
    indicates if the hidden layer contains a bias term (True) or not
    (False)

dropout: float
    regularization parameter; (random) percentage of nodes dropped out
    of the training

n_clusters: int
    number of clusters for 'kmeans' or 'gmm' clustering (could be 0:
        no clustering)

cluster_encode: bool
    defines how the variable containing clusters is treated (default is one-hot)
    if `False`, then labels are used, without one-hot encoding

type_clust: str
    type of clustering method: currently k-means ('kmeans') or Gaussian
    Mixture Model ('gmm')

type_scaling: a tuple of 3 strings
    scaling methods for inputs, hidden layer, and clustering respectively
    (and when relevant).
    Currently available: standardization ('std') or MinMax scaling ('minmax')

lambda1: float
    regularization parameter on direct link

lambda2: float
    regularization parameter on hidden layer

seed: int
    reproducibility seed for nodes_sim=='uniform'

backend: str
    "cpu" or "gpu" or "tpu"

Attributes:

beta_: {array-like}
    regression coefficients

Examples:

See also https://github.com/Techtonique/nnetsauce/blob/master/examples/ridgemtask_classification.py

import nnetsauce as ns
import numpy as np
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
from sklearn import metrics
from time import time

breast_cancer = load_breast_cancer()
Z = breast_cancer.data
t = breast_cancer.target
np.random.seed(123)
X_train, X_test, y_train, y_test = train_test_split(Z, t, test_size=0.2)

fit_obj = ns.Ridge2MultitaskClassifier(n_hidden_features=int(9.83730469e+01),
                                dropout=4.31054687e-01,
                                n_clusters=int(1.71484375e+00),
                                lambda1=1.24023438e+01, lambda2=7.30263672e+03)

start = time()
fit_obj.fit(X_train, y_train)
print(f"Elapsed {time() - start}")

print(fit_obj.score(X_test, y_test))
print(fit_obj.score(X_test, y_test, scoring="roc_auc"))

start = time()
preds = fit_obj.predict(X_test)
print(f"Elapsed {time() - start}")
print(metrics.classification_report(preds, y_test))
def fit(self, X, y, **kwargs):
159    def fit(self, X, y, **kwargs):
160        """Fit Ridge model to training data (X, y).
161
162        Args:
163
164            X: {array-like}, shape = [n_samples, n_features]
165                Training vectors, where n_samples is the number
166                of samples and n_features is the number of features.
167
168            y: array-like, shape = [n_samples]
169                Target values.
170
171            **kwargs: additional parameters to be passed to
172                    self.cook_training_set or self.obj.fit
173
174        Returns:
175
176            self: object
177
178        """
179
180        sys_platform = platform.system()
181
182        assert mx.is_factor(y), "y must contain only integers"
183
184        self.classes_ = np.unique(y)  # for compatibility with sklearn
185        self.n_classes_ = len(self.classes_)  # for compatibility with sklearn
186
187        output_y, scaled_Z = self.cook_training_set(y=y, X=X, **kwargs)
188
189        n_X, p_X = X.shape
190        n_Z, p_Z = scaled_Z.shape
191
192        self.n_classes = len(np.unique(y))
193
194        # multitask response
195        Y = mo.one_hot_encode2(output_y, self.n_classes)
196
197        if self.n_clusters > 0:
198            if self.encode_clusters == True:
199                n_features = p_X + self.n_clusters
200            else:
201                n_features = p_X + 1
202        else:
203            n_features = p_X
204
205        X_ = scaled_Z[:, 0:n_features]
206        Phi_X_ = scaled_Z[:, n_features:p_Z]
207
208        B = mo.crossprod(x=X_, backend=self.backend) + self.lambda1 * np.diag(
209            np.repeat(1, X_.shape[1])
210        )
211        C = mo.crossprod(x=Phi_X_, y=X_, backend=self.backend)
212        D = mo.crossprod(
213            x=Phi_X_, backend=self.backend
214        ) + self.lambda2 * np.diag(np.repeat(1, Phi_X_.shape[1]))
215
216        if sys_platform in ("Linux", "Darwin"):
217            B_inv = pinv(B) if self.backend == "cpu" else jpinv(B)
218        else:
219            B_inv = pinv(B)
220
221        W = mo.safe_sparse_dot(a=C, b=B_inv, backend=self.backend)
222        S_mat = D - mo.tcrossprod(x=W, y=C, backend=self.backend)
223
224        if sys_platform in ("Linux", "Darwin"):
225            S_inv = pinv(S_mat) if self.backend == "cpu" else jpinv(S_mat)
226        else:
227            S_inv = pinv(S_mat)
228
229        Y2 = mo.safe_sparse_dot(a=S_inv, b=W, backend=self.backend)
230        inv = mo.rbind(
231            mo.cbind(
232                x=B_inv + mo.crossprod(x=W, y=Y2, backend=self.backend),
233                y=-np.transpose(Y2),
234                backend=self.backend,
235            ),
236            mo.cbind(x=-Y2, y=S_inv, backend=self.backend),
237            backend=self.backend,
238        )
239
240        self.beta_ = mo.safe_sparse_dot(
241            a=inv,
242            b=mo.crossprod(x=scaled_Z, y=Y, backend=self.backend),
243            backend=self.backend,
244        )
245        self.classes_ = np.unique(y)
246        return self

Fit Ridge model to training data (X, y).

Args:

X: {array-like}, shape = [n_samples, n_features]
    Training vectors, where n_samples is the number
    of samples and n_features is the number of features.

y: array-like, shape = [n_samples]
    Target values.

**kwargs: additional parameters to be passed to
        self.cook_training_set or self.obj.fit

Returns:

self: object
def predict(self, X, **kwargs):
248    def predict(self, X, **kwargs):
249        """Predict test data X.
250
251        Args:
252
253            X: {array-like}, shape = [n_samples, n_features]
254                Training vectors, where n_samples is the number
255                of samples and n_features is the number of features.
256
257            **kwargs: additional parameters to be passed to
258                    self.cook_test_set
259
260        Returns:
261
262            model predictions: {array-like}
263
264        """
265
266        return np.argmax(self.predict_proba(X, **kwargs), axis=1)

Predict test data X.

Args:

X: {array-like}, shape = [n_samples, n_features]
    Training vectors, where n_samples is the number
    of samples and n_features is the number of features.

**kwargs: additional parameters to be passed to
        self.cook_test_set

Returns:

model predictions: {array-like}
def predict_proba(self, X, **kwargs):
268    def predict_proba(self, X, **kwargs):
269        """Predict probabilities for test data X.
270
271        Args:
272
273            X: {array-like}, shape = [n_samples, n_features]
274                Training vectors, where n_samples is the number
275                of samples and n_features is the number of features.
276
277            **kwargs: additional parameters to be passed to
278                    self.cook_test_set
279
280        Returns:
281
282            probability estimates for test data: {array-like}
283
284        """
285
286        if len(X.shape) == 1:
287            n_features = X.shape[0]
288            new_X = mo.rbind(
289                x=X.reshape(1, n_features),
290                y=np.ones(n_features).reshape(1, n_features),
291                backend=self.backend,
292            )
293
294            Z = self.cook_test_set(new_X, **kwargs)
295
296        else:
297            Z = self.cook_test_set(X, **kwargs)
298
299        ZB = mo.safe_sparse_dot(a=Z, b=self.beta_, backend=self.backend)
300
301        exp_ZB = np.exp(ZB)
302
303        return exp_ZB / exp_ZB.sum(axis=1)[:, None]

Predict probabilities for test data X.

Args:

X: {array-like}, shape = [n_samples, n_features]
    Training vectors, where n_samples is the number
    of samples and n_features is the number of features.

**kwargs: additional parameters to be passed to
        self.cook_test_set

Returns:

probability estimates for test data: {array-like}
def score(self, X, y, scoring=None):
305    def score(self, X, y, scoring=None):
306        """Scoring function for classification.
307
308        Args:
309
310            X: {array-like}, shape = [n_samples, n_features]
311                Training vectors, where n_samples is the number
312                of samples and n_features is the number of features.
313
314            y: array-like, shape = [n_samples]
315                Target values.
316
317            scoring: str
318                scoring method (default is accuracy)
319
320        Returns:
321
322            score: float
323        """
324
325        if scoring is None:
326            scoring = "accuracy"
327
328        if scoring == "accuracy":
329            return skm2.accuracy_score(y, self.predict(X))
330
331        if scoring == "f1":
332            return skm2.f1_score(y, self.predict(X))
333
334        if scoring == "precision":
335            return skm2.precision_score(y, self.predict(X))
336
337        if scoring == "recall":
338            return skm2.recall_score(y, self.predict(X))
339
340        if scoring == "roc_auc":
341            return skm2.roc_auc_score(y, self.predict(X))
342
343        if scoring == "log_loss":
344            return skm2.log_loss(y, self.predict_proba(X))
345
346        if scoring == "balanced_accuracy":
347            return skm2.balanced_accuracy_score(y, self.predict(X))
348
349        if scoring == "average_precision":
350            return skm2.average_precision_score(y, self.predict(X))
351
352        if scoring == "neg_brier_score":
353            return -skm2.brier_score_loss(y, self.predict_proba(X))
354
355        if scoring == "neg_log_loss":
356            return -skm2.log_loss(y, self.predict_proba(X))

Scoring function for classification.

Args:

X: {array-like}, shape = [n_samples, n_features]
    Training vectors, where n_samples is the number
    of samples and n_features is the number of features.

y: array-like, shape = [n_samples]
    Target values.

scoring: str
    scoring method (default is accuracy)

Returns:

score: float
class SubSampler:
 6class SubSampler:
 7    """Subsampling class.
 8
 9    Attributes:
10
11       y: array-like, shape = [n_samples]
12           Target values.
13
14       row_sample: double
15           subsampling fraction
16
17       n_samples: int
18            subsampling by using the number of rows (supersedes row_sample)
19
20       seed: int
21           reproductibility seed
22
23       n_jobs: int
24            number of jobs to run in parallel
25
26       verbose: bool
27            print progress messages and bars
28    """
29
30    def __init__(
31        self,
32        y,
33        row_sample=0.8,
34        n_samples=None,
35        seed=123,
36        n_jobs=None,
37        verbose=False,
38    ):
39        self.y = y
40        self.n_samples = n_samples
41        if self.n_samples is None:
42            assert (
43                row_sample < 1 and row_sample >= 0
44            ), "'row_sample' must be provided, plus < 1 and >= 0"
45            self.row_sample = row_sample
46        else:
47            assert self.n_samples < len(y), "'n_samples' must be < len(y)"
48            self.row_sample = self.n_samples / len(y)
49        self.seed = seed
50        self.indices = None
51        self.n_jobs = n_jobs
52        self.verbose = verbose
53
54    def subsample(self):
55        """Returns indices of subsampled input data.
56
57        Examples:
58
59        <ul>
60            <li> <a href="https://github.com/Techtonique/nnetsauce/blob/master/nnetsauce/demo/thierrymoudiki_20240105_subsampling.ipynb">20240105_subsampling.ipynb</a> </li>
61            <li> <a href="https://github.com/Techtonique/nnetsauce/blob/master/nnetsauce/demo/thierrymoudiki_20240131_subsampling_nsamples.ipynb">20240131_subsampling_nsamples.ipynb</a> </li>
62        </ul>
63
64        """
65        self.indices = dosubsample(
66            y=self.y,
67            row_sample=self.row_sample,
68            seed=self.seed,
69            n_jobs=self.n_jobs,
70            verbose=self.verbose,
71        )
72        return self.indices

Subsampling class.

Attributes:

y: array-like, shape = [n_samples] Target values.

row_sample: double subsampling fraction

n_samples: int subsampling by using the number of rows (supersedes row_sample)

seed: int reproductibility seed

n_jobs: int number of jobs to run in parallel

verbose: bool print progress messages and bars

def subsample(self):
54    def subsample(self):
55        """Returns indices of subsampled input data.
56
57        Examples:
58
59        <ul>
60            <li> <a href="https://github.com/Techtonique/nnetsauce/blob/master/nnetsauce/demo/thierrymoudiki_20240105_subsampling.ipynb">20240105_subsampling.ipynb</a> </li>
61            <li> <a href="https://github.com/Techtonique/nnetsauce/blob/master/nnetsauce/demo/thierrymoudiki_20240131_subsampling_nsamples.ipynb">20240131_subsampling_nsamples.ipynb</a> </li>
62        </ul>
63
64        """
65        self.indices = dosubsample(
66            y=self.y,
67            row_sample=self.row_sample,
68            seed=self.seed,
69            n_jobs=self.n_jobs,
70            verbose=self.verbose,
71        )
72        return self.indices

Returns indices of subsampled input data.

Examples: