From e2f319aefc9ae6c094035841d1929639fe12c57c Mon Sep 17 00:00:00 2001 From: William de Vazelhes Date: Tue, 21 May 2019 15:37:16 +0200 Subject: [PATCH 1/4] FIX: fix covariance algo --- metric_learn/covariance.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/metric_learn/covariance.py b/metric_learn/covariance.py index 7a04923d..ed716251 100644 --- a/metric_learn/covariance.py +++ b/metric_learn/covariance.py @@ -35,11 +35,11 @@ def fit(self, X, y=None): y : unused """ X = self._prepare_inputs(X, ensure_min_samples=2) - M = np.cov(X, rowvar = False) - if M.ndim == 0: + M = np.atleast2d(np.cov(X, rowvar = False)) + if len(M) == 1: M = 1./M else: - M = np.linalg.inv(M) + M = np.linalg.pinvh(M) self.transformer_ = transformer_from_metric(np.atleast_2d(M)) return self From f57187f28ab47e1073652b03f2139a046fe3de53 Mon Sep 17 00:00:00 2001 From: William de Vazelhes Date: Tue, 21 May 2019 15:58:35 +0200 Subject: [PATCH 2/4] some fixes and add non regression test --- metric_learn/covariance.py | 7 ++++--- test/metric_learn_test.py | 20 +++++++++++++++++++- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/metric_learn/covariance.py b/metric_learn/covariance.py index ed716251..327ae022 100644 --- a/metric_learn/covariance.py +++ b/metric_learn/covariance.py @@ -14,6 +14,7 @@ from .base_metric import MahalanobisMixin from ._util import transformer_from_metric +import scipy class Covariance(MahalanobisMixin, TransformerMixin): @@ -35,11 +36,11 @@ def fit(self, X, y=None): y : unused """ X = self._prepare_inputs(X, ensure_min_samples=2) - M = np.atleast2d(np.cov(X, rowvar = False)) + M = np.atleast_2d(np.cov(X, rowvar=False)) if len(M) == 1: - M = 1./M + M = 1. / M else: - M = np.linalg.pinvh(M) + M = scipy.linalg.pinvh(M) self.transformer_ = transformer_from_metric(np.atleast_2d(M)) return self diff --git a/test/metric_learn_test.py b/test/metric_learn_test.py index a785d60d..26e204ea 100644 --- a/test/metric_learn_test.py +++ b/test/metric_learn_test.py @@ -6,7 +6,8 @@ from six.moves import xrange from sklearn.metrics import pairwise_distances from sklearn.datasets import load_iris, make_classification, make_regression -from numpy.testing import assert_array_almost_equal, assert_array_equal +from numpy.testing import (assert_array_almost_equal, assert_array_equal, + assert_allclose) from sklearn.utils.testing import assert_warns_message from sklearn.exceptions import ConvergenceWarning from sklearn.utils.validation import check_X_y @@ -53,6 +54,23 @@ def test_iris(self): # deterministic result self.assertAlmostEqual(csep, 0.72981476) + def test_singular_returns_pseudo_inverse(self): + """Checks that if the input covariance matrix is singular, we return + the pseudo inverse""" + X, y = load_iris(return_X_y=True) + # We add a virtual column that is a linear combination of the other + # columns so that the covariance matrix will be singular + X = np.concatenate([X, X[:, :2].dot([[2], [3]])], axis=1) + cov_matrix = np.cov(X, rowvar=False) + covariance = Covariance() + covariance.fit(X) + pseudo_inverse = covariance.get_mahalanobis_matrix() + # here is the definition of a pseudo inverse according to wikipedia: + assert_allclose(cov_matrix.dot(pseudo_inverse).dot(cov_matrix), + cov_matrix) + assert_allclose(pseudo_inverse.dot(cov_matrix).dot(pseudo_inverse), + pseudo_inverse) + class TestLSML(MetricTestCase): def test_iris(self): From 6cb9fc349d8cdb5cc639190aa9c403d49d348a8c Mon Sep 17 00:00:00 2001 From: William de Vazelhes Date: Tue, 21 May 2019 16:01:55 +0200 Subject: [PATCH 3/4] Use size instead of len --- metric_learn/covariance.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/metric_learn/covariance.py b/metric_learn/covariance.py index 327ae022..0e8f46d8 100644 --- a/metric_learn/covariance.py +++ b/metric_learn/covariance.py @@ -37,7 +37,7 @@ def fit(self, X, y=None): """ X = self._prepare_inputs(X, ensure_min_samples=2) M = np.atleast_2d(np.cov(X, rowvar=False)) - if len(M) == 1: + if M.size == 1: M = 1. / M else: M = scipy.linalg.pinvh(M) From a8967bad4520c3fba6642362c9ac066f47959fd4 Mon Sep 17 00:00:00 2001 From: William de Vazelhes Date: Wed, 5 Jun 2019 12:10:44 +0200 Subject: [PATCH 4/4] Address https://github.com/metric-learn/metric-learn/pull/206#pullrequestreview-240810281 --- metric_learn/covariance.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/metric_learn/covariance.py b/metric_learn/covariance.py index 0e8f46d8..83d2f9d8 100644 --- a/metric_learn/covariance.py +++ b/metric_learn/covariance.py @@ -10,11 +10,11 @@ from __future__ import absolute_import import numpy as np +import scipy from sklearn.base import TransformerMixin from .base_metric import MahalanobisMixin from ._util import transformer_from_metric -import scipy class Covariance(MahalanobisMixin, TransformerMixin):