Skip to content

Commit 74c01f5

Browse files
committed
TestAndScore: Fix data errors
1 parent d019c6c commit 74c01f5

File tree

2 files changed

+55
-40
lines changed

2 files changed

+55
-40
lines changed

Orange/widgets/evaluate/owtestandscore.py

Lines changed: 22 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
from Orange.evaluation import Results
3333
from Orange.preprocess.preprocess import Preprocess
3434
import Orange.regression
35+
from Orange.statistics.util import unique
3536
from Orange.widgets import gui, settings, widget
3637
from Orange.widgets.evaluate.utils import \
3738
usable_scorers, ScoreTable, learner_name, scorer_caller
@@ -187,19 +188,15 @@ class Outputs:
187188
class_selection = settings.ContextSetting(TARGET_AVERAGE)
188189

189190
class Error(OWWidget.Error):
190-
train_data_empty = Msg("Train dataset is empty.")
191191
test_data_empty = Msg("Test dataset is empty.")
192-
class_required = Msg("Train data input requires a target variable.")
193-
too_many_classes = Msg("Too many target variables.")
194192
class_required_test = Msg("Test data input requires a target variable.")
195193
too_many_folds = Msg("Number of folds exceeds the data size")
196194
class_inconsistent = Msg("Test and train datasets "
197195
"have different target variables.")
198196
memory_error = Msg("Not enough memory.")
199-
no_class_values = Msg("Target variable has no values.")
200-
only_one_class_var_value = Msg("Target variable has only one value.")
201197
test_data_incompatible = Msg(
202198
"Test data may be incompatible with train data.")
199+
train_data_error = Msg("{}")
203200

204201
class Warning(OWWidget.Warning):
205202
missing_data = \
@@ -382,26 +379,27 @@ def set_train_data(self, data):
382379
"""
383380
self.cancel()
384381
self.Information.data_sampled.clear()
385-
self.Error.train_data_empty.clear()
386-
self.Error.class_required.clear()
387-
self.Error.too_many_classes.clear()
388-
self.Error.no_class_values.clear()
389-
self.Error.only_one_class_var_value.clear()
390-
if data is not None and not data:
391-
self.Error.train_data_empty()
392-
data = None
393-
if data:
394-
conds = [not data.domain.class_vars,
395-
len(data.domain.class_vars) > 1,
396-
np.isnan(data.Y).all(),
397-
data.domain.has_discrete_class and len(data.domain.class_var.values) == 1]
398-
errors = [self.Error.class_required,
399-
self.Error.too_many_classes,
400-
self.Error.no_class_values,
401-
self.Error.only_one_class_var_value]
402-
for cond, error in zip(conds, errors):
382+
self.Error.train_data_error.clear()
383+
384+
if data is not None:
385+
data_errors = [
386+
("Train dataset is empty.", len(data) == 0),
387+
(
388+
"Train data input requires a target variable.",
389+
not data.domain.class_vars
390+
),
391+
("Too many target variables.", len(data.domain.class_vars) > 1),
392+
("Target variable has no values.", np.isnan(data.Y).all()),
393+
(
394+
"Target variable has only one value.",
395+
data.domain.has_discrete_class and len(unique(data.Y)) < 2
396+
),
397+
("Data has no features to learn from.", data.X.shape[1] == 0),
398+
]
399+
400+
for error_msg, cond in data_errors:
403401
if cond:
404-
error()
402+
self.Error.train_data_error(error_msg)
405403
data = None
406404
break
407405

Orange/widgets/evaluate/tests/test_owtestandscore.py

Lines changed: 33 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -166,25 +166,38 @@ def test_one_class_value(self):
166166
"yyyy"))
167167
)
168168
self.widget.n_folds = 0
169-
self.assertFalse(self.widget.Error.only_one_class_var_value.is_shown())
169+
self.assertFalse(self.widget.Error.train_data_error.is_shown())
170170
self.send_signal("Data", table)
171171
self.send_signal("Learner", MajorityLearner(), 0, wait=1000)
172-
self.assertTrue(self.widget.Error.only_one_class_var_value.is_shown())
172+
self.assertTrue(self.widget.Error.train_data_error.is_shown())
173173

174-
def test_nan_class(self):
175-
"""
176-
Do not crash on a data with only nan class values.
177-
GH-2751
178-
"""
179-
def assertErrorShown(data, is_shown):
174+
def test_data_errors(self):
175+
""" Test all data_errors """
176+
def assertErrorShown(data, is_shown, message):
180177
self.send_signal("Data", data)
181-
self.assertEqual(is_shown, self.widget.Error.no_class_values.is_shown())
178+
self.assertEqual(is_shown, self.widget.Error.train_data_error.is_shown())
179+
self.assertEqual(message, str(self.widget.Error.train_data_error))
182180

183181
data = Table("iris")[::30]
184182
data.Y[:] = np.nan
185183

186-
for data, is_shown in zip([None, data, Table("iris")[:30]], [False, True, False]):
187-
assertErrorShown(data, is_shown)
184+
iris_empty_x = Table.from_table(
185+
Domain([], data.domain.class_var), Table("iris")
186+
)
187+
188+
for data, is_shown, message in zip(
189+
[None, data, Table("iris")[:30], iris_empty_x, data[:0]],
190+
[False, True, True, True, True],
191+
[
192+
"",
193+
"Target variable has no values.",
194+
"Target variable has only one value.",
195+
"Data has no features to learn from.",
196+
"Train dataset is empty."
197+
]
198+
199+
):
200+
assertErrorShown(data, is_shown, message)
188201

189202
def test_addon_scorers(self):
190203
try:
@@ -319,15 +332,19 @@ def _test_scores(self, train_data, test_data, learner, sampling, n_folds):
319332
self.send_signal(self.widget.Inputs.learner, learner, 0, wait=5000)
320333
return self._retrieve_scores()
321334

322-
def test_scores_constant_all_same(self):
335+
def test_scores_constant(self):
323336
table = Table.from_list(
324337
self.scores_domain,
325-
list(zip(*self.scores_table_values + [list("yyyy")]))
338+
list(zip(*self.scores_table_values + [list("yyyn")]))
326339
)
327340

328-
self.assertTupleEqual(self._test_scores(
329-
table, table, ConstantLearner(), OWTestAndScore.TestOnTest, None),
330-
(None, 1, 1, 1, 1))
341+
self.assertTupleEqual(
342+
self._test_scores(
343+
table, table[:3], ConstantLearner(),
344+
OWTestAndScore.TestOnTest, None
345+
),
346+
(None, 1, 1, 1, 1)
347+
)
331348

332349
def test_scores_log_reg_overfitted(self):
333350
table = Table.from_list(

0 commit comments

Comments
 (0)