Skip to content

Commit b37dd21

Browse files
committed
Predictions: allow predicting probabilities for classless data
Before, combo box for selection of class probabilities was only shown if the data on the input had a dicrete class. Now, the combo is shown as soon as there is one predictor which works with discrete class vars. If class is missing from the file, only model probabilities options are shown there.
1 parent 41999e5 commit b37dd21

File tree

2 files changed

+55
-2
lines changed

2 files changed

+55
-2
lines changed

Orange/widgets/evaluate/owpredictions.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -267,10 +267,16 @@ def _set_target_combos(self):
267267
self.target_class = self.TARGET_AVERAGE
268268
else:
269269
self.shown_probs = self.NO_PROBS
270+
model = prob_combo.model()
271+
for v in (self.DATA_PROBS, self.BOTH_PROBS):
272+
item = model.item(v)
273+
item.setFlags(item.flags() & ~Qt.ItemIsEnabled)
270274

271275
def _update_control_visibility(self):
272276
for widget in self._prob_controls:
273-
widget.setVisible(self.is_discrete_class)
277+
widget.setVisible(any((slot.predictor.domain.class_var is not None and
278+
slot.predictor.domain.class_var.is_discrete)
279+
for slot in self.predictors))
274280

275281
for widget in self._target_controls:
276282
widget.setVisible(self.is_discrete_class and self.show_scores)

Orange/widgets/evaluate/tests/test_owpredictions.py

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ class TestOWPredictions(WidgetTest):
3939
def setUp(self):
4040
self.widget = self.create_widget(OWPredictions) # type: OWPredictions
4141
self.iris = Table("iris")
42+
self.iris_classless = self.iris.transform(Domain(self.iris.domain.attributes, []))
4243
self.housing = Table("housing")
4344

4445
def test_rowCount_from_model(self):
@@ -746,16 +747,32 @@ def test_update_delegates_continuous(self):
746747

747748
widget.data = Table.from_list(Domain([], ContinuousVariable("c")), [])
748749

750+
# only regression
751+
all_predictors = widget.predictors
752+
widget.predictors = [widget.predictors[-1]]
749753
widget._update_control_visibility()
750754
self.assertTrue(widget.controls.shown_probs.isHidden())
751755
self.assertTrue(widget.controls.target_class.isHidden())
752756

757+
# regression and classification
758+
widget.predictors = all_predictors
759+
widget._update_control_visibility()
760+
self.assertFalse(widget.controls.shown_probs.isHidden())
761+
self.assertTrue(widget.controls.target_class.isHidden())
762+
753763
widget._set_class_values()
754764
self.assertEqual(widget.class_values, list("abcde"))
755765

756766
widget._set_target_combos()
757767
self.assertEqual(widget.shown_probs, widget.NO_PROBS)
758768

769+
def is_enabled(prob_item):
770+
return widget.controls.shown_probs.model().item(prob_item).flags() & Qt.ItemIsEnabled
771+
self.assertTrue(is_enabled(widget.NO_PROBS))
772+
self.assertTrue(is_enabled(widget.MODEL_PROBS))
773+
self.assertFalse(is_enabled(widget.DATA_PROBS))
774+
self.assertFalse(is_enabled(widget.BOTH_PROBS))
775+
759776
def test_delegate_ranges(self):
760777
widget = self.widget
761778

@@ -816,7 +833,6 @@ def predict(self, X):
816833
delegate = widget.predictionsview.itemDelegateForColumn(2)
817834
self.assertIsInstance(delegate, ClassificationItemDelegate)
818835

819-
820836
class _Scorer(TargetScore):
821837
# pylint: disable=arguments-differ
822838
def compute_score(self, _, target, **__):
@@ -940,6 +956,37 @@ def test_output_regression(self):
940956
out.metas,
941957
np.hstack([pred.results.predicted.T for pred in widget.predictors]))
942958

959+
def test_classless(self):
960+
widget = self.widget
961+
iris012 = self.iris
962+
purge = Remove(class_flags=Remove.RemoveUnusedValues)
963+
iris01 = purge(iris012[:100])
964+
iris12 = purge(iris012[50:])
965+
966+
bayes01 = NaiveBayesLearner()(iris01)
967+
bayes12 = NaiveBayesLearner()(iris12)
968+
bayes012 = NaiveBayesLearner()(iris012)
969+
970+
self.send_signal(widget.Inputs.data, self.iris_classless)
971+
self.send_signal(widget.Inputs.predictors, bayes01, 0)
972+
self.send_signal(widget.Inputs.predictors, bayes12, 1)
973+
self.send_signal(widget.Inputs.predictors, bayes012, 2)
974+
975+
for i, pred in enumerate(widget.predictors):
976+
p = pred.results.unmapped_probabilities
977+
p[0] = 10 + 100 * i + np.arange(p.shape[1])
978+
pred.results.unmapped_predicted[:] = i
979+
980+
widget.shown_probs = widget.NO_PROBS
981+
widget._commit_predictions()
982+
out = self.get_output(widget.Outputs.predictions)
983+
self.assertEqual(list(out.metas[0]), [0, 1, 2])
984+
985+
widget.shown_probs = widget.MODEL_PROBS
986+
widget._commit_predictions()
987+
out = self.get_output(widget.Outputs.predictions)
988+
self.assertEqual(list(out.metas[0]), [0, 10, 11, 1, 110, 111, 2, 210, 211, 212])
989+
943990
@patch("Orange.widgets.evaluate.owpredictions.usable_scorers",
944991
Mock(return_value=[_Scorer]))
945992
def test_change_target(self):

0 commit comments

Comments
 (0)