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]
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))
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
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}
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}
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"
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}
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}
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}
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}
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
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
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}
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
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
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}
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
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
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}
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
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
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}
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.
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}")
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
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}
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}
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
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
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
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`
()
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
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))
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
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}
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}
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
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))
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
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`
()
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
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))
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)
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")
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
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
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}
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}
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
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
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
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}
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
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)
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)
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)
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.
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.
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)
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.
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.
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
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
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.
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.
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
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.
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))
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
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
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.
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))
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
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}
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}
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)
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.
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.
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))
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
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}
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}
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
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
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
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
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}
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))
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
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}
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}
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
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
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
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
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
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
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}
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"))
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
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}
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}
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))
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
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}
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}
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
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
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: