From 101130d51962776902cd63514cccf6f469b4c245 Mon Sep 17 00:00:00 2001 From: Timo Kaufmann Date: Fri, 18 Sep 2020 16:52:06 +0200 Subject: [PATCH 01/10] Handle the case of one-object rankings in list_net Merge can only be called on multiple layers, and in the case of length-one rankings there will only be one layer. --- csrank/objectranking/list_net.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csrank/objectranking/list_net.py b/csrank/objectranking/list_net.py index c5fc19cd..50aac4d4 100644 --- a/csrank/objectranking/list_net.py +++ b/csrank/objectranking/list_net.py @@ -215,7 +215,7 @@ def construct_model(self): for hidden_layer in self.hidden_layers: hid = [hidden_layer(x) for x in hid] outputs = [self.output_node(x) for x in hid] - merged = concatenate(outputs) + merged = concatenate(outputs) if len(outputs) > 1 else outputs[0] model = Model(inputs=self.input_layer, outputs=merged) model.compile( loss=self.loss_function, From 454073ec5f1bd46df9b411c35b25228f8455c8d4 Mon Sep 17 00:00:00 2001 From: Timo Kaufmann Date: Fri, 18 Sep 2020 16:53:12 +0200 Subject: [PATCH 02/10] Fix random state handling in the baseline --- csrank/objectranking/baseline.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csrank/objectranking/baseline.py b/csrank/objectranking/baseline.py index acb5a6b1..4eff9290 100644 --- a/csrank/objectranking/baseline.py +++ b/csrank/objectranking/baseline.py @@ -16,7 +16,7 @@ def __init__(self, random_state=None, **kwargs): :param kwargs: Keyword arguments for the algorithms """ - self.random_state = (random_state,) + self.random_state = random_state def _pre_fit(self): super()._pre_fit() From 9a42f8b663f42af66b3d29f3032d70f016a7f608 Mon Sep 17 00:00:00 2001 From: Timo Kaufmann Date: Tue, 22 Sep 2020 13:59:56 +0200 Subject: [PATCH 03/10] Always return self from fit Required by the scikit-learn estimator API for easier fit-predict chaining. --- csrank/choicefunction/baseline.py | 1 + csrank/choicefunction/cmpnet_choice.py | 1 + csrank/choicefunction/fate_choice.py | 1 + csrank/choicefunction/fatelinear_choice.py | 1 + csrank/choicefunction/feta_choice.py | 1 + csrank/choicefunction/fetalinear_choice.py | 1 + csrank/choicefunction/generalized_linear_model.py | 1 + csrank/choicefunction/pairwise_choice.py | 1 + csrank/choicefunction/ranknet_choice.py | 1 + csrank/core/cmpnet_core.py | 1 + csrank/core/fate_linear.py | 1 + csrank/core/fate_network.py | 1 + csrank/core/feta_linear.py | 1 + csrank/core/feta_network.py | 1 + csrank/core/pairwise_svm.py | 1 + csrank/core/ranknet_core.py | 1 + csrank/discretechoice/baseline.py | 1 + csrank/discretechoice/generalized_nested_logit.py | 1 + csrank/discretechoice/mixed_logit_model.py | 1 + csrank/discretechoice/model_selector.py | 1 + csrank/discretechoice/multinomial_logit_model.py | 1 + csrank/discretechoice/nested_logit_model.py | 1 + csrank/discretechoice/paired_combinatorial_logit.py | 1 + csrank/discretechoice/pairwise_discrete_choice.py | 2 +- csrank/dyadranking/fate_dyad_ranker.py | 1 + csrank/objectranking/baseline.py | 1 + csrank/objectranking/expected_rank_regression.py | 1 + csrank/objectranking/list_net.py | 1 + csrank/objectranking/rank_svm.py | 2 +- csrank/tests/test_fate.py | 2 +- 30 files changed, 30 insertions(+), 3 deletions(-) diff --git a/csrank/choicefunction/baseline.py b/csrank/choicefunction/baseline.py index a3c69439..165e4395 100644 --- a/csrank/choicefunction/baseline.py +++ b/csrank/choicefunction/baseline.py @@ -19,6 +19,7 @@ def __init__(self, **kwargs): def fit(self, X, Y, **kwd): self._pre_fit() + return self def _predict_scores_fixed(self, X, Y, **kwargs): return np.zeros_like(Y) + Y.mean() diff --git a/csrank/choicefunction/cmpnet_choice.py b/csrank/choicefunction/cmpnet_choice.py index 4bde0cd7..8c1d1562 100644 --- a/csrank/choicefunction/cmpnet_choice.py +++ b/csrank/choicefunction/cmpnet_choice.py @@ -179,3 +179,4 @@ def fit( else: super().fit(X, Y, epochs, callbacks, validation_split, verbose, **kwd) self.threshold_ = 0.5 + return self diff --git a/csrank/choicefunction/fate_choice.py b/csrank/choicefunction/fate_choice.py index 2154468d..8f033606 100644 --- a/csrank/choicefunction/fate_choice.py +++ b/csrank/choicefunction/fate_choice.py @@ -180,3 +180,4 @@ def fit( else: super().fit(X, Y, **kwargs) self.threshold_ = 0.5 + return self diff --git a/csrank/choicefunction/fatelinear_choice.py b/csrank/choicefunction/fatelinear_choice.py index a36666aa..b6473071 100644 --- a/csrank/choicefunction/fatelinear_choice.py +++ b/csrank/choicefunction/fatelinear_choice.py @@ -98,3 +98,4 @@ def fit( else: super().fit(X, Y, epochs, callbacks, validation_split, verbose, **kwd) self.threshold_ = 0.5 + return self diff --git a/csrank/choicefunction/feta_choice.py b/csrank/choicefunction/feta_choice.py index e5a2a738..dc5f689c 100644 --- a/csrank/choicefunction/feta_choice.py +++ b/csrank/choicefunction/feta_choice.py @@ -311,6 +311,7 @@ def fit( else: super().fit(X, Y, epochs, callbacks, validation_split, verbose, **kwd) self.threshold_ = 0.5 + return self def sub_sampling(self, X, Y): if self.n_objects_fit_ <= self.max_number_of_objects: diff --git a/csrank/choicefunction/fetalinear_choice.py b/csrank/choicefunction/fetalinear_choice.py index ec24015b..d07b5191 100644 --- a/csrank/choicefunction/fetalinear_choice.py +++ b/csrank/choicefunction/fetalinear_choice.py @@ -96,3 +96,4 @@ def fit( else: super().fit(X, Y, epochs, callbacks, validation_split, verbose, **kwd) self.threshold_ = 0.5 + return self diff --git a/csrank/choicefunction/generalized_linear_model.py b/csrank/choicefunction/generalized_linear_model.py index 10ba751e..3ddb3df5 100644 --- a/csrank/choicefunction/generalized_linear_model.py +++ b/csrank/choicefunction/generalized_linear_model.py @@ -256,6 +256,7 @@ def fit( **kwargs, ) self.threshold_ = 0.5 + return self def _fit( self, diff --git a/csrank/choicefunction/pairwise_choice.py b/csrank/choicefunction/pairwise_choice.py index 36450e32..6aebf7b0 100644 --- a/csrank/choicefunction/pairwise_choice.py +++ b/csrank/choicefunction/pairwise_choice.py @@ -114,3 +114,4 @@ def fit(self, X, Y, tune_size=0.1, thin_thresholds=1, verbose=0, **kwd): else: super().fit(X, Y, **kwd) self.threshold_ = 0.5 + return self diff --git a/csrank/choicefunction/ranknet_choice.py b/csrank/choicefunction/ranknet_choice.py index c687fb87..1aa8bb88 100644 --- a/csrank/choicefunction/ranknet_choice.py +++ b/csrank/choicefunction/ranknet_choice.py @@ -166,3 +166,4 @@ def fit( else: super().fit(X, Y, epochs, callbacks, validation_split, verbose, **kwd) self.threshold_ = 0.5 + return self diff --git a/csrank/core/cmpnet_core.py b/csrank/core/cmpnet_core.py index 40c8e74c..b7e97eda 100644 --- a/csrank/core/cmpnet_core.py +++ b/csrank/core/cmpnet_core.py @@ -175,6 +175,7 @@ def fit( **kwd, ) logger.debug("Fitting Complete") + return self def predict_pair(self, a, b, **kwargs): return self.model_.predict([a, b], **kwargs) diff --git a/csrank/core/fate_linear.py b/csrank/core/fate_linear.py index 6b2f83dc..8c60debf 100644 --- a/csrank/core/fate_linear.py +++ b/csrank/core/fate_linear.py @@ -112,6 +112,7 @@ def fit( self.bias1_ = tf_session.run(self.b1) self.weight2_ = tf_session.run(self.W2) self.bias2_ = tf_session.run(self.b2) + return self def _fit_(self, X, Y, epochs, n_instances, tf_session, verbose): try: diff --git a/csrank/core/fate_network.py b/csrank/core/fate_network.py index 1de78df1..ec4c9e92 100644 --- a/csrank/core/fate_network.py +++ b/csrank/core/fate_network.py @@ -518,6 +518,7 @@ def fit( refit=refit, **kwargs, ) + return self def fit_generator( self, diff --git a/csrank/core/feta_linear.py b/csrank/core/feta_linear.py index 1e5f38a8..7b19a520 100644 --- a/csrank/core/feta_linear.py +++ b/csrank/core/feta_linear.py @@ -179,6 +179,7 @@ def fit( self.weight2_ = tf_session.run(self.W2) self.bias2_ = tf_session.run(self.b2) self.W_last_ = tf_session.run(self.W_out_) + return self def _fit_(self, X, Y, epochs, n_instances, tf_session, verbose): try: diff --git a/csrank/core/feta_network.py b/csrank/core/feta_network.py index 6c66eaf2..87a50980 100644 --- a/csrank/core/feta_network.py +++ b/csrank/core/feta_network.py @@ -316,6 +316,7 @@ def fit( verbose=verbose, **kwd, ) + return self def sub_sampling(self, X, Y): if self.n_objects_fit_ > self.max_number_of_objects: diff --git a/csrank/core/pairwise_svm.py b/csrank/core/pairwise_svm.py index 4e6eac94..becd9696 100644 --- a/csrank/core/pairwise_svm.py +++ b/csrank/core/pairwise_svm.py @@ -103,6 +103,7 @@ def fit(self, X, Y, **kwargs): if self.fit_intercept: self.weights_ = np.append(self.weights_, self.model_.intercept_) logger.debug("Fitting Complete") + return self def _predict_scores_fixed(self, X, **kwargs): assert X.shape[-1] == self.n_object_features_fit_ diff --git a/csrank/core/ranknet_core.py b/csrank/core/ranknet_core.py index 0d0908fe..9dd97ba4 100644 --- a/csrank/core/ranknet_core.py +++ b/csrank/core/ranknet_core.py @@ -170,6 +170,7 @@ def fit( ) logger.debug("Fitting Complete") + return self @property def scoring_model(self): diff --git a/csrank/discretechoice/baseline.py b/csrank/discretechoice/baseline.py index 6f8585b6..5b098f21 100644 --- a/csrank/discretechoice/baseline.py +++ b/csrank/discretechoice/baseline.py @@ -24,6 +24,7 @@ def _pre_fit(self): def fit(self, X, Y, **kwd): self._pre_fit() + return self def _predict_scores_fixed(self, X, **kwargs): n_instances, n_objects, n_features = X.shape diff --git a/csrank/discretechoice/generalized_nested_logit.py b/csrank/discretechoice/generalized_nested_logit.py index 7ba6cdb4..6830976b 100644 --- a/csrank/discretechoice/generalized_nested_logit.py +++ b/csrank/discretechoice/generalized_nested_logit.py @@ -337,6 +337,7 @@ def fit( self.n_nests = self.n_objects_fit_ + int(self.n_objects_fit_ / 2) self.construct_model(X, Y) fit_pymc3_model(self, sampler, draws, tune, vi_params, **kwargs) + return self def _predict_scores_fixed(self, X, **kwargs): mean_trace = dict(pm.summary(self.trace_)["mean"]) diff --git a/csrank/discretechoice/mixed_logit_model.py b/csrank/discretechoice/mixed_logit_model.py index a1dc687a..08259f7c 100644 --- a/csrank/discretechoice/mixed_logit_model.py +++ b/csrank/discretechoice/mixed_logit_model.py @@ -218,6 +218,7 @@ def fit( _n_instances, self.n_objects_fit_, self.n_object_features_fit_ = X.shape self.construct_model(X, Y) fit_pymc3_model(self, sampler, draws, tune, vi_params, **kwargs) + return self def _predict_scores_fixed(self, X, **kwargs): summary = dict(pm.summary(self.trace_)["mean"]) diff --git a/csrank/discretechoice/model_selector.py b/csrank/discretechoice/model_selector.py index 078d9719..4c6f137e 100644 --- a/csrank/discretechoice/model_selector.py +++ b/csrank/discretechoice/model_selector.py @@ -105,6 +105,7 @@ def fit(self, X, Y): self.parameter_ind[j][1], ) self.fit_learner(X, Y, key) + return self def fit_learner(self, X, Y, key): learner = self.learner_cls(**self.model_params) diff --git a/csrank/discretechoice/multinomial_logit_model.py b/csrank/discretechoice/multinomial_logit_model.py index 7db65b46..0415e3c1 100644 --- a/csrank/discretechoice/multinomial_logit_model.py +++ b/csrank/discretechoice/multinomial_logit_model.py @@ -217,6 +217,7 @@ def fit( _n_instances, self.n_objects_fit_, self.n_object_features_fit_ = X.shape self.construct_model(X, Y) fit_pymc3_model(self, sampler, draws, tune, vi_params, **kwargs) + return self def _predict_scores_fixed(self, X, **kwargs): d = dict(pm.summary(self.trace_)["mean"]) diff --git a/csrank/discretechoice/nested_logit_model.py b/csrank/discretechoice/nested_logit_model.py index 5b4e1d46..be9c4862 100644 --- a/csrank/discretechoice/nested_logit_model.py +++ b/csrank/discretechoice/nested_logit_model.py @@ -392,6 +392,7 @@ def fit( self.random_state_ = check_random_state(self.random_state) self.construct_model(X, Y) fit_pymc3_model(self, sampler, draws, tune, vi_params, **kwargs) + return self def _predict_scores_fixed(self, X, **kwargs): y_nests = self.create_nests(X) diff --git a/csrank/discretechoice/paired_combinatorial_logit.py b/csrank/discretechoice/paired_combinatorial_logit.py index 54d90269..f6a13d7f 100644 --- a/csrank/discretechoice/paired_combinatorial_logit.py +++ b/csrank/discretechoice/paired_combinatorial_logit.py @@ -332,6 +332,7 @@ def fit( self.n_nests = len(self.nests_indices) self.construct_model(X, Y) fit_pymc3_model(self, sampler, draws, tune, vi_params, **kwargs) + return self def _predict_scores_fixed(self, X, **kwargs): mean_trace = dict(pm.summary(self.trace_)["mean"]) diff --git a/csrank/discretechoice/pairwise_discrete_choice.py b/csrank/discretechoice/pairwise_discrete_choice.py index b50d678f..28211704 100644 --- a/csrank/discretechoice/pairwise_discrete_choice.py +++ b/csrank/discretechoice/pairwise_discrete_choice.py @@ -76,4 +76,4 @@ def _convert_instances_(self, X, Y): def fit(self, X, Y, **kwd): self._pre_fit() _n_instances, self.n_objects_fit_, self.n_object_features_fit_ = X.shape - super().fit(X, Y, **kwd) + return super().fit(X, Y, **kwd) diff --git a/csrank/dyadranking/fate_dyad_ranker.py b/csrank/dyadranking/fate_dyad_ranker.py index 37c10fcd..59d00244 100644 --- a/csrank/dyadranking/fate_dyad_ranker.py +++ b/csrank/dyadranking/fate_dyad_ranker.py @@ -6,6 +6,7 @@ class FATEDyadRanker(FATENetwork, DyadRanker): def fit(self, Xo, Xc, Y, **kwargs): self._pre_fit() + return self def predict_scores(self, Xo, Xc, **kwargs): return self.model_.predict([Xo, Xc], **kwargs) diff --git a/csrank/objectranking/baseline.py b/csrank/objectranking/baseline.py index 4eff9290..4593966a 100644 --- a/csrank/objectranking/baseline.py +++ b/csrank/objectranking/baseline.py @@ -24,6 +24,7 @@ def _pre_fit(self): def fit(self, X, Y, **kwd): self._pre_fit() + return self def _predict_scores_fixed(self, X, **kwargs): n_instances, n_objects, n_features = X.shape diff --git a/csrank/objectranking/expected_rank_regression.py b/csrank/objectranking/expected_rank_regression.py index 71dfde37..cb83f293 100644 --- a/csrank/objectranking/expected_rank_regression.py +++ b/csrank/objectranking/expected_rank_regression.py @@ -127,6 +127,7 @@ def fit(self, X, Y, **kwargs): if self.fit_intercept: self.weights_ = np.append(self.weights_, self.model_.intercept_) logger.debug("Fitting Complete") + return self def _predict_scores_fixed(self, X, **kwargs): n_instances, n_objects, n_features = X.shape diff --git a/csrank/objectranking/list_net.py b/csrank/objectranking/list_net.py index 50aac4d4..8f5bac6a 100644 --- a/csrank/objectranking/list_net.py +++ b/csrank/objectranking/list_net.py @@ -199,6 +199,7 @@ def fit( **kwd, ) logger.debug("Fitting Complete") + return self def construct_model(self): """ diff --git a/csrank/objectranking/rank_svm.py b/csrank/objectranking/rank_svm.py index 89a56339..8be3c68f 100644 --- a/csrank/objectranking/rank_svm.py +++ b/csrank/objectranking/rank_svm.py @@ -60,7 +60,7 @@ def __init__( def fit(self, X, Y, **kwargs): self._pre_fit() _n_instances, self.n_objects_fit_, self.n_object_features_fit_ = X.shape - super().fit(X, Y, **kwargs) + return super().fit(X, Y, **kwargs) def _convert_instances_(self, X, Y): logger.debug("Creating the Dataset") diff --git a/csrank/tests/test_fate.py b/csrank/tests/test_fate.py index 7ce2cc69..96023824 100644 --- a/csrank/tests/test_fate.py +++ b/csrank/tests/test_fate.py @@ -27,7 +27,7 @@ def predict(self, *args, **kwargs): pass def fit(self, *args, **kwargs): - pass + return self grc = MockClass() grc._initialize_optimizer() From f89e64d2087884535ddb044011606d5e2a0fb86f Mon Sep 17 00:00:00 2001 From: Timo Kaufmann Date: Tue, 22 Sep 2020 15:07:23 +0200 Subject: [PATCH 04/10] Fix ranking normalization for 0-based rankings This would previously fail due to a division by 0 if the ranking is 0-based and consists of only one object. Concretely, this would fail the "check_fit2d_1sample" check from the scikit-learn estimator test suite if we generate 0-based rankings. --- csrank/dataset_reader/objectranking/util.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/csrank/dataset_reader/objectranking/util.py b/csrank/dataset_reader/objectranking/util.py index c7e5f7a1..b1306840 100644 --- a/csrank/dataset_reader/objectranking/util.py +++ b/csrank/dataset_reader/objectranking/util.py @@ -109,7 +109,9 @@ def complete_linear_regression_dataset(X, rankings): Y_single = [] for features, rank in zip(X, rankings): X1.extend(features) - norm_ranks = rank / np.max(rank, axis=0) + min_rank = np.min(rank, axis=0) + max_rank = np.max(rank, axis=0) + norm_ranks = (rank - min_rank + 1) / (max_rank - min_rank + 1) Y_single.extend(norm_ranks) X1 = np.array(X1) Y_single = np.array(Y_single) From 6be12b7c85c1ebec23caa5593795dee144e6be9a Mon Sep 17 00:00:00 2001 From: Timo Kaufmann Date: Wed, 23 Sep 2020 14:22:22 +0200 Subject: [PATCH 05/10] Gracefully handle the single-object case in cmpnet --- csrank/core/cmpnet_core.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/csrank/core/cmpnet_core.py b/csrank/core/cmpnet_core.py index b7e97eda..932a2ee3 100644 --- a/csrank/core/cmpnet_core.py +++ b/csrank/core/cmpnet_core.py @@ -157,12 +157,15 @@ def fit( """ self._pre_fit() _n_instances, self.n_objects_fit_, self.n_object_features_fit_ = X.shape - x1, x2, y_double = self._convert_instances_(X, Y) - logger.debug("Instances created {}".format(x1.shape[0])) self._construct_layers() self.model_ = self.construct_model() + if self.n_objects_fit_ < 2: + # Nothing to learn here, no pairwise comparisons can be generated. + return self + x1, x2, y_double = self._convert_instances_(X, Y) + logger.debug("Instances created {}".format(x1.shape[0])) logger.debug("Finished Creating the model, now fitting started") self.model_.fit( [x1, x2], From fcc70c85f44f56844dcdc31946e3bd37f8ee347d Mon Sep 17 00:00:00 2001 From: Timo Kaufmann Date: Wed, 23 Sep 2020 14:39:13 +0200 Subject: [PATCH 06/10] Gracefully handle the single-object case in FETA --- csrank/core/feta_network.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/csrank/core/feta_network.py b/csrank/core/feta_network.py index 87a50980..7c441a97 100644 --- a/csrank/core/feta_network.py +++ b/csrank/core/feta_network.py @@ -303,6 +303,9 @@ def fit( logger.debug("Enter fit function...") X, Y = self.sub_sampling(X, Y) + if self.n_objects_fit_ < 2: + # Nothing to learn, can't construct a model. + return self self.model_ = self.construct_model() logger.debug("Starting gradient descent...") From 32375fe6d612130c2781a4074716e6541bf53e2f Mon Sep 17 00:00:00 2001 From: Timo Kaufmann Date: Wed, 23 Sep 2020 14:48:52 +0200 Subject: [PATCH 07/10] Gracefully handle the single-object case in FATE --- csrank/core/fate_network.py | 4 +++- csrank/layers.py | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/csrank/core/fate_network.py b/csrank/core/fate_network.py index ec4c9e92..2948762d 100644 --- a/csrank/core/fate_network.py +++ b/csrank/core/fate_network.py @@ -140,7 +140,9 @@ def join_input_layers(self, input_layer, *layers, n_layers, n_objects): for j in range(self.n_hidden_joint_layers): joint = self.joint_layers[j](joint) scores.append(self.scorer(joint)) - scores = concatenate(scores, name="final_scores") + scores = ( + concatenate(scores, name="final_scores") if len(scores) > 1 else scores[0] + ) logger.debug("Done") return scores diff --git a/csrank/layers.py b/csrank/layers.py index e92b9625..a5e971c9 100644 --- a/csrank/layers.py +++ b/csrank/layers.py @@ -134,7 +134,8 @@ def _create_model(self, shape): set_mappings.append((i, curr)) # TODO: is feature_repr used outside? - feature_repr = average([x for (j, x) in set_mappings]) + x_values = [x for (j, x) in set_mappings] + feature_repr = average(x_values) if len(x_values) > 1 else x_values[0] self.cached_models[n_objects] = Model(inputs=input_layer, outputs=feature_repr) From 56fcca8492e212aad98892135a6d33464767d94c Mon Sep 17 00:00:00 2001 From: Timo Kaufmann Date: Wed, 23 Sep 2020 14:55:48 +0200 Subject: [PATCH 08/10] Gracefully handle the single-object case in ranknet --- csrank/core/ranknet_core.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/csrank/core/ranknet_core.py b/csrank/core/ranknet_core.py index 9dd97ba4..88344fff 100644 --- a/csrank/core/ranknet_core.py +++ b/csrank/core/ranknet_core.py @@ -147,15 +147,19 @@ def fit( """ self._pre_fit() _n_instances, self.n_objects_fit_, self.n_object_features_fit_ = X.shape - X1, X2, Y_single = self._convert_instances_(X, Y) - - logger.debug("Instances created {}".format(X1.shape[0])) logger.debug("Creating the model") self._construct_layers() # Model with input as two objects and output as probability of x1>x2 self.model_ = self.construct_model() + + if self.n_objects_fit_ < 2: + # Nothing to learn, cannot create pairwise comparisons. + return self + X1, X2, Y_single = self._convert_instances_(X, Y) + + logger.debug("Instances created {}".format(X1.shape[0])) logger.debug("Finished Creating the model, now fitting started") self.model_.fit( From 74438677aa20249eddc3149f8f8ee408f60cd5dc Mon Sep 17 00:00:00 2001 From: Timo Kaufmann Date: Wed, 23 Sep 2020 14:57:00 +0200 Subject: [PATCH 09/10] Gracefully handle the single-object case in svm --- csrank/core/pairwise_svm.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/csrank/core/pairwise_svm.py b/csrank/core/pairwise_svm.py index becd9696..c3f68acd 100644 --- a/csrank/core/pairwise_svm.py +++ b/csrank/core/pairwise_svm.py @@ -75,7 +75,6 @@ def fit(self, X, Y, **kwargs): """ self._pre_fit() _n_instances, self.n_objects_fit_, self.n_object_features_fit_ = X.shape - x_train, y_single = self._convert_instances_(X, Y) if self.use_logistic_regression: self.model_ = LogisticRegression( C=self.C, @@ -93,6 +92,10 @@ def fit(self, X, Y, **kwargs): ) logger.info("Linear SVC model ") + if self.n_objects_fit_ < 2: + # Nothing to learn, cannot create pairwise instances. + return self + x_train, y_single = self._convert_instances_(X, Y) if self.normalize: std_scalar = StandardScaler() x_train = std_scalar.fit_transform(x_train) From 47d8f6a933a790be07ce9e7a539388b414617200 Mon Sep 17 00:00:00 2001 From: Timo Kaufmann Date: Wed, 23 Sep 2020 15:09:22 +0200 Subject: [PATCH 10/10] Gracefully handle the single-object case in feta_linear --- csrank/core/feta_linear.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/csrank/core/feta_linear.py b/csrank/core/feta_linear.py index 7b19a520..789709cd 100644 --- a/csrank/core/feta_linear.py +++ b/csrank/core/feta_linear.py @@ -162,6 +162,10 @@ def fit( self._pre_fit() # Global Variables Initializer n_instances, self.n_objects_fit_, self.n_object_features_fit_ = X.shape + if self.n_objects_fit_ < 2: + # Nothing to learn here, model cannot be constructed without any + # instance pairs. + return self self._construct_model_(self.n_objects_fit_) init = tf.global_variables_initializer()