Skip to content

Commit aabd844

Browse files
authored
Merge pull request #2677 from janezd/fix-outliers
[FIX] Outliers widget no longer checks classes and doesn't crash on singular covariances matrices
2 parents ea87577 + aa5fcef commit aabd844

File tree

3 files changed

+16
-22
lines changed

3 files changed

+16
-22
lines changed

Orange/classification/elliptic_envelope.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
from Orange.base import SklLearner, SklModel
44
from Orange.data import Table
5+
from Orange.preprocess import Continuize, RemoveNaNColumns, SklImpute
56

67
__all__ = ["EllipticEnvelopeLearner"]
78

@@ -27,6 +28,7 @@ def mahalanobis(self, observations):
2728
class EllipticEnvelopeLearner(SklLearner):
2829
__wraps__ = skl_covariance.EllipticEnvelope
2930
__returns__ = EllipticEnvelopeClassifier
31+
preprocessors = [Continuize(), RemoveNaNColumns(), SklImpute()]
3032

3133
def __init__(self, store_precision=True, assume_centered=False,
3234
support_fraction=None, contamination=0.1,

Orange/widgets/data/owoutliers.py

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@ class Outputs:
4343

4444
class Error(widget.OWWidget.Error):
4545
singular_cov = Msg("Singular covariance matrix.")
46-
multiclass_error = Msg("Multiple class data is not supported")
4746
memory_error = Msg("Not enough memory")
4847

4948
def __init__(self):
@@ -149,6 +148,7 @@ def _get_outliers(self):
149148
except ValueError:
150149
self.Error.singular_cov()
151150
self.in_out_info_label.setText(self.in_out_info_default)
151+
return None, None
152152
except MemoryError:
153153
self.Error.memory_error()
154154
return None, None
@@ -170,10 +170,7 @@ def commit(self):
170170
inliers = outliers = None
171171
self.n_inliers = self.n_outliers = None
172172
if self.data is not None and len(self.data) > 0:
173-
if self.data.Y.ndim > 1 and self.data.Y.shape[1] > 1:
174-
self.Error.multiclass_error()
175-
else:
176-
inliers, outliers = self._get_outliers()
173+
inliers, outliers = self._get_outliers()
177174

178175
self.Outputs.inliers.send(inliers)
179176
self.Outputs.outliers.send(outliers)
@@ -188,8 +185,9 @@ def detect_outliers(self):
188185
support_fraction=self.support_fraction
189186
if self.empirical_covariance else None,
190187
contamination=self.cont / 100.)
191-
model = learner(self.data)
192-
y_pred = model(self.data)
188+
data = self.data.transform(Domain(self.data.domain.attributes))
189+
model = learner(data)
190+
y_pred = model(data)
193191
self.add_metas(model)
194192
return np.array(y_pred)
195193

Orange/widgets/data/tests/test_owoutliers.py

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
import numpy as np
77

8-
from Orange.data import Table, Domain, ContinuousVariable, DiscreteVariable
8+
from Orange.data import Table
99
from Orange.widgets.data.owoutliers import OWOutliers
1010
from Orange.widgets.tests.base import WidgetTest
1111

@@ -25,20 +25,6 @@ def test_data(self):
2525
self.assertEqual(self.widget.data, None)
2626
self.assertIsNone(self.get_output("Data"))
2727

28-
def test_multiclass(self):
29-
"""Check widget for multiclass dataset"""
30-
attrs = [ContinuousVariable("c1"), ContinuousVariable("c2")]
31-
class_vars = [DiscreteVariable("cls", ["a", "b", "c"]),
32-
DiscreteVariable("cls", ["aa", "bb", "cc"])]
33-
domain = Domain(attrs, class_vars)
34-
X = np.arange(12).reshape(6, 2)
35-
Y = np.array([[0, 1], [2, 1], [0, 2], [1, 1], [1, 2], [2, 0]])
36-
data = Table(domain, X, Y)
37-
self.send_signal(self.widget.Inputs.data, data)
38-
self.assertTrue(self.widget.Error.multiclass_error.is_shown())
39-
self.send_signal(self.widget.Inputs.data, None)
40-
self.assertFalse(self.widget.Error.multiclass_error.is_shown())
41-
4228
def test_memory_error(self):
4329
"""
4430
Handling memory error.
@@ -51,3 +37,11 @@ def test_memory_error(self):
5137
side_effect=MemoryError):
5238
self.send_signal("Data", data)
5339
self.assertTrue(self.widget.Error.memory_error.is_shown())
40+
41+
def test_nans(self):
42+
"""Widget does not crash with nans"""
43+
a = np.arange(20, dtype=float).reshape(4, 5)
44+
a[0, 0] = np.nan
45+
data = Table(a)
46+
self.send_signal(self.widget.Inputs.data, data)
47+
self.assertIsNot(self.get_output(self.widget.Outputs.inliers), None)

0 commit comments

Comments
 (0)