From 9535bbf67b019e761971117cf14b978558202935 Mon Sep 17 00:00:00 2001 From: Will LeVine Date: Thu, 10 Sep 2020 14:21:16 -0400 Subject: [PATCH 01/20] Purged LifelongClassificationNetwork, added docstring header to network.py --- proglearn/network.py | 78 +++----------------------------------------- 1 file changed, 5 insertions(+), 73 deletions(-) diff --git a/proglearn/network.py b/proglearn/network.py index 3c5242b86f..4a34bc8543 100644 --- a/proglearn/network.py +++ b/proglearn/network.py @@ -1,3 +1,7 @@ +''' +Main Author: Will LeVine +Corresponding Email: levinewill@icloud.com +''' import numpy as np from .progressive_learner import ProgressiveLearner @@ -9,78 +13,6 @@ from keras.optimizers import Adam from keras.callbacks import EarlyStopping - -class LifelongRegressionNetwork: - def __init__( - self, network, decider="linear", loss="mse", epochs=100, optimizer=Adam(1e-3), verbose=False - ): - self.network = network - self.decider = decider - self.loss = loss - self.epochs = epochs - self.optimizer = optimizer - self.verbose = verbose - self.is_first_task = True - - def setup(self): - - # Set transformer network hyperparameters. - default_transformer_kwargs = { - "network": self.network, - "euclidean_layer_idx": -2, - "loss": self.loss, - "optimizer": self.optimizer, - "compile_kwargs": {}, - "fit_kwargs": { - "epochs": self.epochs, - "verbose": self.verbose, - "callbacks": [EarlyStopping(patience=10, monitor="val_loss")], - "validation_split": 0.25, - }, - } - - # Set voter network hyperparameters. - default_voter_kwargs = { - "validation_split": 0.25, - "loss": self.loss, - "lr": self.lr, - "epochs": self.epochs, - "verbose": self.verbose, - } - - # Choose decider. - if self.decider == "linear": - default_decider_class = LinearRegressionDecider - elif self.decider == "knn": - default_decider_class = KNNRegressionDecider - else: - raise ValueError("Decider must be 'linear' or 'knn'.") - - self.pl = ProgressiveLearner( - default_transformer_class=NeuralRegressionTransformer, - default_transformer_kwargs=default_transformer_kwargs, - default_voter_class=NeuralRegressionVoter, - default_voter_kwargs=default_voter_kwargs, - default_decider_class=default_decider_class, - default_decider_kwargs={}, - ) - - def add_task(self, X, y, task_id=None): - - if self.is_first_task: - self.setup() - self.is_first_task = False - - self.pl.add_task( - X, y, task_id=task_id, transformer_voter_decider_split=[0.6, 0.3, 0.1] - ) - - return self - - def predict(self, X, task_id): - return self.pl.predict(X, task_id) - - class LifelongClassificationNetwork: def __init__( self, @@ -151,4 +83,4 @@ def predict(self, X, task_id): return self.pl.predict(X, task_id) def predict_proba(self, X, task_id): - return self.pl.predict_proba(X, task_id) \ No newline at end of file + return self.pl.predict_proba(X, task_id) From 0d50531fbe2a5905bf20d327434a8218a23cab6f Mon Sep 17 00:00:00 2001 From: Will LeVine Date: Thu, 10 Sep 2020 14:23:02 -0400 Subject: [PATCH 02/20] Modified LifelongClassificationNetwork to accept optimizer instead of learning rate --- proglearn/network.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/proglearn/network.py b/proglearn/network.py index 4a34bc8543..d346ad838e 100644 --- a/proglearn/network.py +++ b/proglearn/network.py @@ -18,15 +18,15 @@ def __init__( self, network, loss="categorical_crossentropy", + optimizer=Adam(3e-4), epochs=100, - lr=3e-4, batch_size=32, verbose=False, ): self.network = network self.loss = loss self.epochs = epochs - self.optimizer = Adam(lr) + self.optimizer = optimizer self.verbose = verbose self.batch_size = batch_size self.is_first_task = True From 535ecf750c4fe7dba5982a6830ea7607952a1dbd Mon Sep 17 00:00:00 2001 From: Will LeVine Date: Thu, 10 Sep 2020 14:24:10 -0400 Subject: [PATCH 03/20] Purged TransferForest --- proglearn/forest.py | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/proglearn/forest.py b/proglearn/forest.py index e4fc353180..5bea94d697 100644 --- a/proglearn/forest.py +++ b/proglearn/forest.py @@ -53,29 +53,3 @@ def predict(self, X): def predict_proba(self, X): return self.lf.predict_proba(X, 0) - - -class TransferForest: - def __init__(self, n_estimators=100): - self.lf = LifelongClassificationForest(n_estimators=n_estimators) - self.source_ids = [] - - def add_source_task(self, X, y, task_id=None): - self.lf.add_task( - X, y, task_id=task_id, transformer_voter_decider_split=[0.9, 0.1, 0] - ) - self.source_ids.append(task_id) - return self - - def add_target_task(self, X, y, task_id=None): - self.lf.add_task( - X, y, task_id=task_id, transformer_voter_decider_split=[0.1, 0.9, 0] - ) - self.target_id = task_id - return self - - def predict(self, X): - return self.lf.predict(X, self.target_id, transformer_ids=self.source_ids) - - def predict_proba(self, X): - return self.lf.predict_proba(X, self.target_id, transformer_ids=self.source_ids) \ No newline at end of file From 5c91c1b19a7d7509a6309eab360e52082f8a0ed3 Mon Sep 17 00:00:00 2001 From: Will LeVine Date: Thu, 10 Sep 2020 14:24:24 -0400 Subject: [PATCH 04/20] Added docstring header --- proglearn/forest.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/proglearn/forest.py b/proglearn/forest.py index 5bea94d697..3704df4ddb 100644 --- a/proglearn/forest.py +++ b/proglearn/forest.py @@ -1,9 +1,12 @@ +''' +Main Author: Will LeVine +Corresponding Email: levinewill@icloud.com +''' from .progressive_learner import ProgressiveLearner from .transformers import TreeClassificationTransformer from .voters import TreeClassificationVoter from .deciders import SimpleAverage - class LifelongClassificationForest: def __init__(self, n_estimators=100, finite_sample_correction=False): self.n_estimators = n_estimators From b42424beff180287f6e16bf16f9b5614059fd696 Mon Sep 17 00:00:00 2001 From: Will LeVine Date: Thu, 10 Sep 2020 14:28:37 -0400 Subject: [PATCH 05/20] Modify KNNClassificationVoter to default k=None and internally calculate k To address issue #112 --- proglearn/voters.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/proglearn/voters.py b/proglearn/voters.py index 1c3ed736dc..cf7f86ce92 100755 --- a/proglearn/voters.py +++ b/proglearn/voters.py @@ -97,7 +97,7 @@ def _finite_sample_correction(posteriors, num_points_in_partition, num_classes): class KNNClassificationVoter(BaseVoter): - def __init__(self, k, kwargs={}): + def __init__(self, k=None, kwargs={}): """ Doc strings here. """ @@ -110,7 +110,8 @@ def fit(self, X, y): Doc strings here. """ X, y = check_X_y(X, y) - self.knn = KNeighborsClassifier(self.k, **self.kwargs) + k = int(np.log2(len(X))) if self.k == None else self.k + self.knn = KNeighborsClassifier(k, **self.kwargs) self.knn.fit(X, y) self._is_fitted = True From c17bd678c4b4d74a711790c4d37386302139a053 Mon Sep 17 00:00:00 2001 From: Will LeVine Date: Thu, 10 Sep 2020 14:39:26 -0400 Subject: [PATCH 06/20] Matched LifelongClassificationNetwork and LifelongClassificationForest hyperparams and purged setup function in LifelongClassificationNetwork --- proglearn/network.py | 39 ++++++++++++--------------------------- 1 file changed, 12 insertions(+), 27 deletions(-) diff --git a/proglearn/network.py b/proglearn/network.py index d346ad838e..bb4d6f9141 100644 --- a/proglearn/network.py +++ b/proglearn/network.py @@ -5,9 +5,9 @@ import numpy as np from .progressive_learner import ProgressiveLearner -from .transformers import NeuralClassificationTransformer, NeuralRegressionTransformer -from .voters import KNNClassificationVoter, NeuralRegressionVoter -from .deciders import SimpleAverage, LinearRegressionDecider, KNNRegressionDecider +from .transformers import NeuralClassificationTransformer +from .voters import KNNClassificationVoter +from .deciders import SimpleAverage from sklearn.utils import check_X_y, check_array from keras.optimizers import Adam @@ -29,58 +29,43 @@ def __init__( self.optimizer = optimizer self.verbose = verbose self.batch_size = batch_size - self.is_first_task = True - - def setup(self, num_points_per_task): - + # Set transformer network hyperparameters. default_transformer_kwargs = { "network": self.network, "euclidean_layer_idx": -2, "loss": self.loss, "optimizer": self.optimizer, - "num_classes": 10, - "compile_kwargs": {}, "fit_kwargs": { "epochs": self.epochs, - # "callbacks": [EarlyStopping(patience=5, monitor="val_loss")], + "callbacks": [EarlyStopping(patience=5, monitor="val_loss")], "verbose": self.verbose, "validation_split": 0.33, "batch_size": self.batch_size }, } - # Hyperparameter for KNN voter. - default_voter_kwargs = {"k": int(np.log2(num_points_per_task))} - self.pl = ProgressiveLearner( default_transformer_class=NeuralClassificationTransformer, default_transformer_kwargs=default_transformer_kwargs, default_voter_class=KNNClassificationVoter, - default_voter_kwargs=default_voter_kwargs, + default_voter_kwargs={}, default_decider_class=SimpleAverage, default_decider_kwargs={}, ) - def add_task(self, X, y, task_id=None, decider_kwargs={}): - - if self.is_first_task: - num_points_per_task = len(X) - self.setup(num_points_per_task) - self.is_first_task = False - + def add_task(self, X, y, task_id=None, transformer_voter_decider_split=[0.67, 0.33, 0]): self.pl.add_task( X, y, task_id=task_id, - transformer_voter_decider_split=[0.67, 0.33, 0.0], - decider_kwargs=decider_kwargs, + transformer_voter_decider_split=transformer_voter_decider_split ) return self - def predict(self, X, task_id): - return self.pl.predict(X, task_id) + def predict(self, X, task_id, transformer_ids=None): + return self.pl.predict(X, task_id, transformer_ids=transformer_ids) - def predict_proba(self, X, task_id): - return self.pl.predict_proba(X, task_id) + def predict_proba(self, X, task_id, transformer_ids=None): + return self.pl.predict_proba(X, task_id, transformer_ids=transformer_ids) From b5a9ad18f35d2505fd33b14337e93f5996837b33 Mon Sep 17 00:00:00 2001 From: Will LeVine Date: Thu, 10 Sep 2020 14:42:03 -0400 Subject: [PATCH 07/20] Added decider_kwargs to forest.py --- proglearn/forest.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/proglearn/forest.py b/proglearn/forest.py index 3704df4ddb..3e107fec5f 100644 --- a/proglearn/forest.py +++ b/proglearn/forest.py @@ -28,6 +28,7 @@ def add_task( task_id=task_id, transformer_voter_decider_split=transformer_voter_decider_split, num_transformers=self.n_estimators, + decider_kwargs = {"classes" : np.unique(y)} ) return self @@ -48,7 +49,7 @@ def fit(self, X, y): n_estimators=self.n_estimators, finite_sample_correction=self.finite_sample_correction, ) - self.lf.add_task(X, y, task_id=0) + self.lf.add_task(X, y, task_id=0, decider_kwargs = {"classes" : np.unique(y)}) return self def predict(self, X): From 9759c67fa4a13e4c8a76ad388dcd132b4ee42999 Mon Sep 17 00:00:00 2001 From: Will LeVine Date: Thu, 10 Sep 2020 14:42:27 -0400 Subject: [PATCH 08/20] Added decider_kwargs to network.py --- proglearn/network.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/proglearn/network.py b/proglearn/network.py index bb4d6f9141..cea65d10da 100644 --- a/proglearn/network.py +++ b/proglearn/network.py @@ -59,7 +59,8 @@ def add_task(self, X, y, task_id=None, transformer_voter_decider_split=[0.67, 0. X, y, task_id=task_id, - transformer_voter_decider_split=transformer_voter_decider_split + transformer_voter_decider_split=transformer_voter_decider_split, + decider_kwargs = {"classes" : np.unique(y)} ) return self From 6ca813d34c0ae2450dfd6c33cf4681bed06d62f4 Mon Sep 17 00:00:00 2001 From: Will LeVine Date: Thu, 10 Sep 2020 14:47:41 -0400 Subject: [PATCH 09/20] Added add_transformer to network.py --- proglearn/network.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/proglearn/network.py b/proglearn/network.py index cea65d10da..0b48e669c7 100644 --- a/proglearn/network.py +++ b/proglearn/network.py @@ -64,6 +64,15 @@ def add_task(self, X, y, task_id=None, transformer_voter_decider_split=[0.67, 0. ) return self + + def add_transformer(self, X, y, transformer_id=None): + self.pl.add_transformer( + X, + y, + transformer_id=transformer_id + ) + + return self def predict(self, X, task_id, transformer_ids=None): return self.pl.predict(X, task_id, transformer_ids=transformer_ids) From 97935840ec5f34b6c133db37228caa5e7a8f108c Mon Sep 17 00:00:00 2001 From: Will LeVine Date: Thu, 10 Sep 2020 14:48:12 -0400 Subject: [PATCH 10/20] Added 'add_transformer' to forest.py --- proglearn/forest.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/proglearn/forest.py b/proglearn/forest.py index 3e107fec5f..9846a16df8 100644 --- a/proglearn/forest.py +++ b/proglearn/forest.py @@ -31,6 +31,15 @@ def add_task( decider_kwargs = {"classes" : np.unique(y)} ) return self + + def add_transformer(self, X, y, transformer_id=None): + self.pl.add_transformer( + X, + y, + transformer_id=transformer_id + ) + + return self def predict(self, X, task_id, transformer_ids=None): return self.pl.predict(X, task_id, transformer_ids=transformer_ids) From 27e97afb68739ff042f2adff669b2a18607eee62 Mon Sep 17 00:00:00 2001 From: Will LeVine Date: Thu, 10 Sep 2020 15:05:38 -0400 Subject: [PATCH 11/20] Updated progressive_learner add_task docstring --- proglearn/progressive_learner.py | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/proglearn/progressive_learner.py b/proglearn/progressive_learner.py index 89d1e22449..737ae74ee3 100755 --- a/proglearn/progressive_learner.py +++ b/proglearn/progressive_learner.py @@ -466,15 +466,19 @@ def add_task( task_id : obj, default=None The id corresponding to the task being added. transformer_voter_decider_split : ndarray, default=[0.67, 0.33, 0] - A 1d array of length 3. The 2nd index indicates the proportion of the data - set aside to train the decider - these indices are saved internally and - will be used to train all further deciders corresponding to this task for - all function calls. The 1st index indicates the proportion of the data - set aside to train the voter from the (optional) newly added transformer(s) - to the new task. For all other tasks, the aggregate transformer and voter - data is used to train the voters corresponding to those tasks. The 0th index - indicates the proportions of the input data used to train the (optional) newly - added transformer(s). + A 1d array of length 3. The 0th index indicates the proportions of the input + data used to train the (optional) newly added transformer(s) corresponding to + the task_id provided in this function call. The 1st index indicates the proportion of + the data set aside to train the voter(s) from these (optional) newly added + transformer(s) to the task_id provided in this function call. For all other tasks, + the aggregate transformer and voter data pairs from those tasks are used to train + the voter(s) from these (optional) newly added transformer(s) to those tasks; + for all other transformers, the aggregate transformer and voter data provided in + this function call is used to train the voter(s) from those transformers to + the task_id provided in this function call. The 2nd index indicates the + proportion of the data set aside to train the decider - these indices are saved + internally and will be used to train all further deciders corresponding to this + task for all function calls. num_transformers : int, default=1 The number of transformers to add corresponding to the given inputs. transformer_class : BaseTransformer, default=None @@ -573,4 +577,4 @@ def predict_proba(self, X, task_id, transformer_ids=None): else: raise AttributeError( "Cannot call `predict_proba` on non-classification decider." - ) \ No newline at end of file + ) From 02eba324e5c66bd24e8efad6a1e34136821c7d0f Mon Sep 17 00:00:00 2001 From: Will LeVine Date: Thu, 10 Sep 2020 15:14:21 -0400 Subject: [PATCH 12/20] Hotfix to forest.py to add forest transformers (rather than just trees) --- proglearn/forest.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/proglearn/forest.py b/proglearn/forest.py index 9846a16df8..cf04308528 100644 --- a/proglearn/forest.py +++ b/proglearn/forest.py @@ -8,8 +8,9 @@ from .deciders import SimpleAverage class LifelongClassificationForest: - def __init__(self, n_estimators=100, finite_sample_correction=False): + def __init__(self, n_estimators=100, tree_construction_proportion=0.67, finite_sample_correction=False): self.n_estimators = n_estimators + self.tree_construction_proportion=tree_construction_proportion self.pl = ProgressiveLearner( default_transformer_class=TreeClassificationTransformer, default_transformer_kwargs={}, @@ -20,13 +21,12 @@ def __init__(self, n_estimators=100, finite_sample_correction=False): ) def add_task( - self, X, y, task_id=None, transformer_voter_decider_split=[0.67, 0.33, 0] - ): + self, X, y, task_id=None): self.pl.add_task( X, y, task_id=task_id, - transformer_voter_decider_split=transformer_voter_decider_split, + transformer_voter_decider_split=[self.tree_construction_proportion, 1-tree_construction_proportion, 0], num_transformers=self.n_estimators, decider_kwargs = {"classes" : np.unique(y)} ) @@ -36,7 +36,9 @@ def add_transformer(self, X, y, transformer_id=None): self.pl.add_transformer( X, y, - transformer_id=transformer_id + transformer_id=transformer_id, + num_transformers=self.n_estimators, + transformer_data_proportion=self.tree_construction_proportion ) return self From 89e1b3de7b6234f893e0ce5e5c4c248d346059ca Mon Sep 17 00:00:00 2001 From: Will LeVine Date: Thu, 10 Sep 2020 15:23:58 -0400 Subject: [PATCH 13/20] Got rid of transformer_ids argument to predict/predict_proba in forest --- proglearn/forest.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/proglearn/forest.py b/proglearn/forest.py index cf04308528..e802653cba 100644 --- a/proglearn/forest.py +++ b/proglearn/forest.py @@ -43,11 +43,11 @@ def add_transformer(self, X, y, transformer_id=None): return self - def predict(self, X, task_id, transformer_ids=None): - return self.pl.predict(X, task_id, transformer_ids=transformer_ids) + def predict(self, X, task_id): + return self.pl.predict(X, task_id) - def predict_proba(self, X, task_id, transformer_ids=None): - return self.pl.predict_proba(X, task_id, transformer_ids=transformer_ids) + def predict_proba(self, X, task_id): + return self.pl.predict_proba(X, task_id) class UncertaintyForest: From 1ee4e0e270ba32e28fe128ab214883abfc161b86 Mon Sep 17 00:00:00 2001 From: Will LeVine Date: Thu, 10 Sep 2020 15:24:37 -0400 Subject: [PATCH 14/20] Got rid of transformer_ids argument to predict/predict_proba in forest --- proglearn/network.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/proglearn/network.py b/proglearn/network.py index 0b48e669c7..df0839f03f 100644 --- a/proglearn/network.py +++ b/proglearn/network.py @@ -74,8 +74,8 @@ def add_transformer(self, X, y, transformer_id=None): return self - def predict(self, X, task_id, transformer_ids=None): - return self.pl.predict(X, task_id, transformer_ids=transformer_ids) + def predict(self, X, task_id): + return self.pl.predict(X, task_id) - def predict_proba(self, X, task_id, transformer_ids=None): - return self.pl.predict_proba(X, task_id, transformer_ids=transformer_ids) + def predict_proba(self, X, task_id): + return self.pl.predict_proba(X, task_id) From e229d70cd27c04757f686e683d4784adced82b50 Mon Sep 17 00:00:00 2001 From: Will LeVine Date: Thu, 10 Sep 2020 15:25:48 -0400 Subject: [PATCH 15/20] Renamed LifelongClassificationForest to L2F --- proglearn/forest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proglearn/forest.py b/proglearn/forest.py index e802653cba..addf269470 100644 --- a/proglearn/forest.py +++ b/proglearn/forest.py @@ -7,7 +7,7 @@ from .voters import TreeClassificationVoter from .deciders import SimpleAverage -class LifelongClassificationForest: +class L2F: def __init__(self, n_estimators=100, tree_construction_proportion=0.67, finite_sample_correction=False): self.n_estimators = n_estimators self.tree_construction_proportion=tree_construction_proportion From 3f4e631958501eb6dcb2522caa587bbfa2f0e9bd Mon Sep 17 00:00:00 2001 From: Will LeVine Date: Thu, 10 Sep 2020 15:26:11 -0400 Subject: [PATCH 16/20] Renamed LifelongClassificationNetwork to L2N --- proglearn/network.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proglearn/network.py b/proglearn/network.py index df0839f03f..d58cf93e06 100644 --- a/proglearn/network.py +++ b/proglearn/network.py @@ -13,7 +13,7 @@ from keras.optimizers import Adam from keras.callbacks import EarlyStopping -class LifelongClassificationNetwork: +class L2N: def __init__( self, network, From 35a2a81fc7657ebdd50dc89cb5a6b19ac3f1ffef Mon Sep 17 00:00:00 2001 From: Will LeVine Date: Thu, 10 Sep 2020 15:29:30 -0400 Subject: [PATCH 17/20] Delete test_neuralregression.py --- tests/test_neuralregression.py | 62 ---------------------------------- 1 file changed, 62 deletions(-) delete mode 100644 tests/test_neuralregression.py diff --git a/tests/test_neuralregression.py b/tests/test_neuralregression.py deleted file mode 100644 index b386e2d0ae..0000000000 --- a/tests/test_neuralregression.py +++ /dev/null @@ -1,62 +0,0 @@ -import pytest -import numpy as np -from numpy.testing import assert_allclose -from sklearn.exceptions import NotFittedError - -from proglearn.transformers import NeuralRegressionTransformer -from proglearn.voters import NeuralRegressionVoter - -from tensorflow import keras -from tensorflow.random import set_seed - - -def initialize_transformer(): - network = keras.Sequential() - network.add(keras.layers.Dense(2, activation="relu", input_shape=(3,))) - network.add(keras.layers.Dense(1, activation="relu")) - - return NeuralRegressionTransformer(network=network) - - -def test_predict_without_fit(): - # Generate random data - X = np.random.normal(0, 1, size=(100, 3)) - - with pytest.raises(NotFittedError): - nrt = initialize_transformer() - nrt.transform(X) - - with pytest.raises(NotFittedError): - nrv = NeuralRegressionVoter() - nrv.vote(X) - - -def test_correct_transformation(): - np.random.seed(1) - set_seed(2) # tensorflow - - nrt = initialize_transformer() - nrt._is_fitted = True - - x = np.ones((1, 3)) - u1 = np.array([[0, 0.69286364]]) - - u2 = nrt.transform(x) - - assert_allclose(u1, u2) - - -def test_correct_vote(): - np.random.seed(3) - set_seed(4) # tensorflow - - X = np.random.randn(1000, 3) - Y = np.sum(X, axis=1).reshape((1000, 1)) - - nrv = NeuralRegressionVoter(epochs=30, lr=1) - nrv.fit(X, Y) - - X_test = np.ones((5, 3)) - Y_test = 3 * np.ones((5, 1)) - - assert_allclose(Y_test, nrv.vote(X_test), atol=1e-4) From 9df6cecc136550fb81a75273c66645768794fa13 Mon Sep 17 00:00:00 2001 From: Will LeVine Date: Thu, 10 Sep 2020 15:29:37 -0400 Subject: [PATCH 18/20] Delete test_treeregression.py --- tests/test_treeregression.py | 54 ------------------------------------ 1 file changed, 54 deletions(-) delete mode 100755 tests/test_treeregression.py diff --git a/tests/test_treeregression.py b/tests/test_treeregression.py deleted file mode 100755 index 604511c1ff..0000000000 --- a/tests/test_treeregression.py +++ /dev/null @@ -1,54 +0,0 @@ -import pytest -import numpy as np -from numpy.testing import assert_allclose -from sklearn.exceptions import NotFittedError - -from proglearn.transformers import TreeRegressionTransformer -from proglearn.voters import TreeRegressionVoter - - -def initialize_transformer(): - return TreeRegressionTransformer() - - -def test_predict_without_fit(): - # Generate random data - X = np.random.normal(0, 1, size=(100, 3)) - - with pytest.raises(NotFittedError): - trt = initialize_transformer() - trt.transform(X) - - with pytest.raises(NotFittedError): - trv = TreeRegressionVoter() - trv.vote(X) - - -def test_correct_transformation(): - np.random.seed(1) - - trt = initialize_transformer() - - X = np.concatenate((np.zeros(100), np.ones(100))).reshape(-1, 1) - y = np.concatenate((np.zeros(100), np.ones(100))) - - trt.fit(X, y) - u1 = trt.transform(np.array([0]).reshape(1, -1)) - u2 = trt.transform(np.array([1]).reshape(1, -1)) - - assert u1 != u2 - - -def test_correct_vote(): - np.random.seed(3) - - X = np.concatenate((np.zeros(100), np.ones(100))) - y = np.concatenate((np.zeros(100), np.ones(100))) - - trv = TreeRegressionVoter() - trv.fit(X, y) - - X_test = np.ones(6) - y_test = np.ones(6) - - assert_allclose(y_test, trv.vote(X_test), atol=1e-4) \ No newline at end of file From 97e2cdbbc727ddc58439b0b6cde69d24d40d0385 Mon Sep 17 00:00:00 2001 From: Will LeVine Date: Thu, 10 Sep 2020 15:30:46 -0400 Subject: [PATCH 19/20] Delete test_deciders.py --- tests/test_deciders.py | 80 ------------------------------------------ 1 file changed, 80 deletions(-) delete mode 100644 tests/test_deciders.py diff --git a/tests/test_deciders.py b/tests/test_deciders.py deleted file mode 100644 index 6eac9b921a..0000000000 --- a/tests/test_deciders.py +++ /dev/null @@ -1,80 +0,0 @@ -import pytest -import numpy as np -from numpy.testing import assert_allclose -from sklearn.exceptions import NotFittedError - -from proglearn.deciders import KNNRegressionDecider, LinearRegressionDecider -from proglearn.base import BaseTransformer, BaseVoter - - -def test_predict_without_fit(): - # Generate random data - X = np.random.normal(0, 1, size=(100, 3)) - - with pytest.raises(NotFittedError): - krd = KNNRegressionDecider() - krd.predict(X) - - with pytest.raises(NotFittedError): - lrd = LinearRegressionDecider() - lrd.predict(X) - - -class IdentityTransformer(BaseTransformer): - def __init__(self): - self._is_fitted = False - - def fit(self): - self._is_fitted = True - - def transform(self, X): - return X - - def is_fitted(self): - return self._is_fitted - - -class IdentityVoter(BaseVoter): - def __init__(self, index): - self._is_fitted = False - self.index = index - - def fit(self): - self._is_fitted = True - - def vote(self, X): - n = len(X) - return X[:, self.index].reshape(n) - - def is_fitted(self): - return self._is_fitted - - -def test_correct_decision(): - np.random.seed(3) - - X = 0.1 * np.random.randn(2000, 3) + 1 - Y = np.sum(X, axis=1).reshape((2000, 1)) - - lrd = LinearRegressionDecider() - krd = KNNRegressionDecider() - - transformer_id_to_transformers = { - "0": [IdentityTransformer()], - "1": [IdentityTransformer()], - "2": [IdentityTransformer()], - } - transformer_id_to_voters = { - "0": [IdentityVoter(0)], - "1": [IdentityVoter(1)], - "2": [IdentityVoter(2)], - } - - lrd.fit(X, Y, transformer_id_to_transformers, transformer_id_to_voters) - krd.fit(X, Y, transformer_id_to_transformers, transformer_id_to_voters) - - X_test = np.ones((5, 3)) - Y_test = 3 * np.ones(5) - - assert_allclose(Y_test, lrd.predict(X_test), atol=1e-4) - assert_allclose(Y_test, krd.predict(X_test), atol=1e-2) From 7ceb314d6ab24070241b5f7e767a2076ab78b3cb Mon Sep 17 00:00:00 2001 From: Will LeVine Date: Thu, 10 Sep 2020 15:38:48 -0400 Subject: [PATCH 20/20] Added ValueError check to SimpleAverage Decider --- proglearn/deciders.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/proglearn/deciders.py b/proglearn/deciders.py index e5264aa2a1..f854f1a912 100755 --- a/proglearn/deciders.py +++ b/proglearn/deciders.py @@ -34,7 +34,9 @@ def fit( transformer_id_to_voters, classes=None, ): - self.classes = self.classes if len(self.classes) > 0 else np.unique(y) + if self.classes == None and len(y) == 0: + raise ValueError("Classification Decider classes undefined with no class labels fed to 'fit') + self.classes = self.classes if self.classes != None else np.unique(y) self.transformer_id_to_transformers = transformer_id_to_transformers self.transformer_id_to_voters = transformer_id_to_voters